From 2b1872ae35d58a6c888c466c05eda78fd342765e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Wo=C5=BAniak?= Date: Wed, 17 Aug 2022 21:03:26 +0200 Subject: [PATCH] Update dependencies --- Cargo.lock | 1803 +++++++++++++------- amdfan/src/main.rs | 21 +- amdfand/src/change_mode.rs | 3 +- amdfand/src/command.rs | 17 +- amdfand/src/main.rs | 9 +- amdfand/src/service.rs | 6 +- amdgpu-config/src/fan.rs | 6 +- amdgpu-config/src/monitor.rs | 3 +- amdgpu/src/error.rs | 12 +- amdgpu/src/lib.rs | 10 +- amdgpu/src/lock_file.rs | 13 +- amdgpu/src/{ => pidfile}/helper_cmd.rs | 21 +- amdgpu/src/pidfile/mod.rs | 133 ++ amdgpu/src/{ => pidfile}/ports.rs | 21 +- amdgpu/src/temp_input.rs | 3 +- amdgui-helper/src/main.rs | 113 +- amdguid/Cargo.toml | 33 +- amdguid/assets/icons/html_port-512.png | Bin 0 -> 9410 bytes amdguid/assets/icons/ports.jpg | Bin 0 -> 110787 bytes amdguid/assets/icons/vga_port-512.png | Bin 0 -> 9380 bytes amdguid/src/app.rs | 102 +- amdguid/src/backend/glium_backend.rs | 5 +- amdguid/src/backend/glow_backend.rs | 4 +- amdguid/src/backend/mod.rs | 38 +- amdguid/src/backend/wayland_backend.rs | 436 +++-- amdguid/src/items.rs | 10 +- amdguid/src/items/arrows.rs | 8 +- amdguid/src/items/h_line.rs | 11 +- amdguid/src/items/line.rs | 11 +- amdguid/src/items/plot_image.rs | 12 +- amdguid/src/items/plot_item.rs | 8 +- amdguid/src/items/points.rs | 18 +- amdguid/src/items/polygons.rs | 19 +- amdguid/src/items/text.rs | 18 +- amdguid/src/items/v_line.rs | 15 +- amdguid/src/items/value.rs | 4 +- amdguid/src/items/values.rs | 20 +- amdguid/src/transform.rs | 3 +- amdguid/src/widgets/change_fan_settings.rs | 15 +- amdguid/src/widgets/config_file.rs | 3 +- amdguid/src/widgets/cooling_performance.rs | 28 +- amdguid/src/widgets/drag_plot.rs | 43 +- amdguid/src/widgets/drag_plot_prepared.rs | 48 +- amdguid/src/widgets/legend.rs | 20 +- amdguid/src/widgets/legend_widget.rs | 14 +- amdguid/src/widgets/mod.rs | 2 + amdguid/src/widgets/output_widget.rs | 69 + amdguid/src/widgets/outputs_settings.rs | 86 + amdguid/src/widgets/reload_section.rs | 15 +- amdmond-lib/src/lib.rs | 3 +- amdmond/src/main.rs | 4 +- amdportsd/src/main.rs | 68 +- amdvold/src/main.rs | 3 +- rustfmt.toml | 7 + 54 files changed, 2201 insertions(+), 1196 deletions(-) rename amdgpu/src/{ => pidfile}/helper_cmd.rs (87%) create mode 100644 amdgpu/src/pidfile/mod.rs rename amdgpu/src/{ => pidfile}/ports.rs (92%) create mode 100644 amdguid/assets/icons/html_port-512.png create mode 100644 amdguid/assets/icons/ports.jpg create mode 100644 amdguid/assets/icons/vga_port-512.png create mode 100644 amdguid/src/widgets/output_widget.rs create mode 100644 amdguid/src/widgets/outputs_settings.rs create mode 100644 rustfmt.toml diff --git a/Cargo.lock b/Cargo.lock index c4be851..cfcbb22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser 0.15.0", + "owned_ttf_parser", ] [[package]] @@ -33,6 +33,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "ahash" version = "0.7.6" @@ -41,7 +47,6 @@ checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ "getrandom", "once_cell", - "serde", "version_check", ] @@ -93,7 +98,7 @@ version = "1.0.11" dependencies = [ "gumdrop", "log", - "nix 0.24.1", + "nix 0.24.2", "pidlock", "pretty_env_logger", "ron 0.7.1", @@ -141,20 +146,22 @@ dependencies = [ "amdgpu", "amdgpu-config", "amdmond-lib", - "egui", + "bytemuck", + "egui 0.18.1", "egui-winit", "egui_glium", "egui_glow", "egui_vulkano", - "epaint", + "epaint 0.18.1", "epi", - "glium", + "glium 0.32.1", "glow", - "glutin", + "glutin 0.29.1", "gumdrop", + "image", "log", - "nix 0.24.1", - "parking_lot 0.11.2", + "nix 0.25.0", + "parking_lot 0.12.1", "pretty_env_logger", "serde", "thiserror", @@ -163,7 +170,7 @@ dependencies = [ "vulkano", "vulkano-shaders", "vulkano-win", - "winit", + "winit 0.26.1", ] [[package]] @@ -226,19 +233,6 @@ dependencies = [ "toml", ] -[[package]] -name = "andrew" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4afb09dd642feec8408e33f92f3ffc4052946f6b20f32fb99c1f58cd4fa7cf" -dependencies = [ - "bitflags", - "rusttype", - "walkdir", - "xdg", - "xml-rs", -] - [[package]] name = "android_glue" version = "0.2.3" @@ -246,12 +240,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" [[package]] -name = "ash" -version = "0.33.3+1.2.191" +name = "android_system_properties" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219" +checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e" dependencies = [ - "libloading 0.7.3", + "libc", +] + +[[package]] +name = "arboard" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc120354d1b5ec6d7aaf4876b602def75595937b5e15d356eb554ab5177e08bb" +dependencies = [ + "clipboard-win", + "log", + "objc", + "objc-foundation", + "objc_id", + "parking_lot 0.12.1", + "thiserror", + "winapi", + "x11rb", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "ash" +version = "0.36.0+1.3.206" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceea9c64653169f33f946debf0a41568afc4e23a4c37d29004a23b2ffbfb4034" +dependencies = [ + "libloading", ] [[package]] @@ -279,9 +311,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.65" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" dependencies = [ "addr2line", "cc", @@ -298,6 +330,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + [[package]] name = "bitflags" version = "1.3.2" @@ -329,19 +367,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] -name = "bytes" -version = "1.1.0" +name = "bytemuck" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9e1f5fa78f69496407a27ae9ed989e3c3b072310286f5ef385525e4cbc24a9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "calloop" -version = "0.6.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b036167e76041694579972c28cf4877b4f92da222560ddb49008937b6a6727c" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" dependencies = [ "log", - "nix 0.18.0", + "nix 0.22.3", +] + +[[package]] +name = "calloop" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22a6a8f622f797120d452c630b0ab12e1331a1a753e2039ce7868d4ac77b4ee" +dependencies = [ + "log", + "nix 0.24.2", + "slotmap", + "thiserror", + "vec_map", ] [[package]] @@ -356,6 +433,12 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "0.1.10" @@ -379,25 +462,28 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "serde", "time", + "wasm-bindgen", "winapi", ] [[package]] name = "clipboard-win" -version = "3.1.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" +checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219" dependencies = [ - "lazy-bytes-cast", + "error-code", + "str-buf", "winapi", ] @@ -420,7 +506,7 @@ dependencies = [ "block", "core-foundation 0.7.0", "core-graphics 0.19.2", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] @@ -436,7 +522,7 @@ dependencies = [ "cocoa-foundation", "core-foundation 0.9.3", "core-graphics 0.22.3", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] @@ -451,23 +537,25 @@ dependencies = [ "block", "core-foundation 0.9.3", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "libc", "objc", ] [[package]] -name = "copypasta" -version = "0.7.1" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4423d79fed83ebd9ab81ec21fa97144300a961782158287dc9bf7eddac37ff0b" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ - "clipboard-win", - "objc", - "objc-foundation", - "objc_id", - "smithay-clipboard", - "x11-clipboard", + "bytes", + "memchr", ] [[package]] @@ -510,7 +598,7 @@ checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" dependencies = [ "bitflags", "core-foundation 0.7.0", - "foreign-types", + "foreign-types 0.3.2", "libc", ] @@ -523,7 +611,7 @@ dependencies = [ "bitflags", "core-foundation 0.9.3", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", "libc", ] @@ -535,7 +623,19 @@ checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ "bitflags", "core-foundation 0.9.3", - "foreign-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-text" +version = "19.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25" +dependencies = [ + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "foreign-types 0.3.2", "libc", ] @@ -553,10 +653,19 @@ dependencies = [ ] [[package]] -name = "crossbeam" -version = "0.8.1" +name = "crc32fast" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" dependencies = [ "cfg-if 1.0.0", "crossbeam-channel", @@ -568,9 +677,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -578,9 +687,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", @@ -589,23 +698,23 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" dependencies = [ "autocfg", "cfg-if 1.0.0", "crossbeam-utils", - "lazy_static", "memoffset", + "once_cell", "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -613,12 +722,35 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", +] + +[[package]] +name = "crossfont" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66b1c1979c4362323f03ab6bf7fb522902bfc418e0c37319ab347f9561d980f" +dependencies = [ + "cocoa 0.24.0", + "core-foundation 0.9.3", + "core-foundation-sys 0.8.3", + "core-graphics 0.22.3", + "core-text", + "dwrote", + "foreign-types 0.5.0", + "freetype-rs", + "libc", + "log", + "objc", + "once_cell", + "pkg-config", + "servo-fontconfig", + "winapi", ] [[package]] @@ -630,7 +762,7 @@ dependencies = [ "bitflags", "crossterm_winapi", "libc", - "mio 0.8.3", + "mio", "parking_lot 0.12.1", "signal-hook", "signal-hook-mio", @@ -654,7 +786,7 @@ checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" dependencies = [ "bstr", "csv-core", - "itoa", + "itoa 0.4.8", "ryu", "serde", ] @@ -676,9 +808,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "darling" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core", "darling_macro", @@ -686,9 +818,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", @@ -700,9 +832,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.10.2" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", @@ -710,44 +842,12 @@ dependencies = [ ] [[package]] -name = "directories-next" -version = "2.0.0" +name = "deflate" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", + "adler32", ] [[package]] @@ -756,22 +856,13 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" -[[package]] -name = "dlib" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b11f15d1e3268f140f68d390637d5e76d849782d971ae7063e0da69fe9709a76" -dependencies = [ - "libloading 0.6.7", -] - [[package]] name = "dlib" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" dependencies = [ - "libloading 0.7.3", + "libloading", ] [[package]] @@ -781,78 +872,116 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] -name = "egui" -version = "0.15.0" +name = "dwrote" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8d416a3343cbfc6f4d17bb1cba46b4d7efecb9ee541967763e0b5e04e5fae7" +checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" +dependencies = [ + "lazy_static", + "libc", + "serde", + "serde_derive", + "winapi", + "wio", +] + +[[package]] +name = "egui" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a3cd1d47e12f7a17912595241622e373aa652a4e0fa90b3f9278f90a64aedf7" dependencies = [ "ahash", - "epaint", + "epaint 0.17.0", "nohash-hasher", - "ron 0.7.1", - "serde", +] + +[[package]] +name = "egui" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb095a8b9feb9b7ff8f00b6776dffcef059538a3f4a91238e03c900e9c9ad9a2" +dependencies = [ + "ahash", + "epaint 0.18.1", + "nohash-hasher", + "tracing", ] [[package]] name = "egui-winit" -version = "0.15.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc403e91d1bd693239f1c734193cdf0eb38c8682bbfb9990c4b6cd2db5ee368e" +checksum = "b040afd583fd95a9b9578d4399214a13d948ed26bc0ff7cc0104502501f34e68" dependencies = [ - "copypasta", - "egui", - "epi", - "serde", + "arboard", + "egui 0.18.1", + "instant", + "tracing", "webbrowser", - "winit", + "winit 0.26.1", ] [[package]] name = "egui_glium" -version = "0.15.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26478ec89b8c9c41a45687a90f9c8fc18106e3ffd8a08559285d625185a2ac92" +checksum = "38243eb1ae916be2861d4aeba8cf564492a65d7729a0713e5c4b4cd5603ac082" dependencies = [ - "egui", + "ahash", + "bytemuck", + "egui 0.18.1", "egui-winit", - "epi", - "glium", + "glium 0.31.0", ] [[package]] name = "egui_glow" -version = "0.15.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fba815b217b8d4c17dcd080497d9ea2ad0e2047aec8d584db1c7c4a28e978db" +checksum = "af43ed7ec7199907ab5853c3bb3883ae1e741ab540aa127a798a60b7bdb906f1" dependencies = [ - "egui", - "egui-winit", - "epi", + "bytemuck", + "egui 0.18.1", "glow", - "glutin", "memoffset", + "tracing", + "wasm-bindgen", + "web-sys", ] [[package]] name = "egui_vulkano" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7606011e9ea06cef4f81fde8baffb6b8d43314ca424b4b3f3c06c4c47c842403" +checksum = "a8b9f32026b6b6d27f8c15d32c695169e3e1a9c52344a6c93bf9646f4ba2cb0c" dependencies = [ - "egui", - "epaint", + "bytemuck", + "egui 0.18.1", "thiserror", "vulkano", "vulkano-shaders", ] [[package]] -name = "emath" -version = "0.15.0" +name = "either" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a1aaa922d55da6a2bf32957c3d153e7fb9d52ed8d69777a75092240172eb6e" +checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" + +[[package]] +name = "emath" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a977a80456be58a2c2d48e69c1d0baadef46cecef5a0c98df141c468da006f12" + +[[package]] +name = "emath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c223f58c7e38abe1770f367b969f1b3fbd4704b67666bcb65dbb1adb0980ba72" dependencies = [ - "serde", + "bytemuck", ] [[package]] @@ -870,29 +999,99 @@ dependencies = [ [[package]] name = "epaint" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bb4d3b8bbbd132c99d2a5efec8567e8b6d09b742f758ae6cf1e4b104fe0231" +checksum = "033292846059f08e03a71e1b5db2ee6ab7c9622c3b48da21f4bd13258ebee2db" dependencies = [ "ab_glyph", "ahash", "atomic_refcell", - "emath", + "emath 0.17.0", "nohash-hasher", - "parking_lot 0.11.2", - "serde", +] + +[[package]] +name = "epaint" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c29567088888e8ac3e8f61bbb2ddc820207ebb8d69eefde5bcefa06d65e4e89" +dependencies = [ + "ab_glyph", + "ahash", + "atomic_refcell", + "bytemuck", + "emath 0.18.0", + "nohash-hasher", + "parking_lot 0.12.1", ] [[package]] name = "epi" -version = "0.15.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5e4e08127f9b86e2c450c96a3032764b63546eb170c2fc54684dc70ff3fc82" +checksum = "c95445deccef4d29fa30488d3f7f2e942dd343eef01228becc7cefd5b918176e" dependencies = [ - "directories-next", - "egui", - "ron 0.7.1", - "serde", + "egui 0.17.0", + "tracing", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "expat-sys" +version = "2.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" +dependencies = [ + "cmake", + "pkg-config", +] + +[[package]] +name = "exr" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cc0e06fb5f67e5d6beadf3a382fec9baca1aa751c6d5368fdeee7e5932c215" +dependencies = [ + "bit_field", + "deflate", + "flume", + "half", + "inflate", + "lebe", + "smallvec", + "threadpool", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "pin-project", + "spin", ] [[package]] @@ -907,7 +1106,28 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -917,10 +1137,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] -name = "futures" -version = "0.3.21" +name = "foreign-types-shared" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "freetype-rs" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" +dependencies = [ + "bitflags", + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + +[[package]] +name = "futures" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab30e97ab6aacfe635fad58f22c2bb06c8b685f7421eb1e064a729e2a5f481fa" dependencies = [ "futures-channel", "futures-core", @@ -933,9 +1191,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "2bfc52cbddcfd745bf1740338492bb0bd83d76c67b445f91c5fb29fae29ecaa1" dependencies = [ "futures-core", "futures-sink", @@ -943,15 +1201,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "d2acedae88d38235936c3922476b10fced7b2b68136f5e3c03c2d5be348a1115" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "1d11aa21b5b587a64682c0094c2bdd4df0076c5324961a40cc3abd7f37930528" dependencies = [ "futures-core", "futures-task", @@ -960,15 +1218,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "93a66fc6d035a26a3ae255a6d2bca35eda63ae4c5512bef54449113f7a1228e5" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "0db9cce532b0eae2ccf2766ab246f114b56b9cf6d445e00c2549fbc100ca045d" dependencies = [ "proc-macro2", "quote", @@ -977,21 +1235,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "ca0bae1fe9752cf7fd9b0064c674ae63f97b37bc714d745cbde0afb7ec4e6765" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "842fc63b931f4056a24d59de13fb1272134ce261816e063e634ad0c15cdc5306" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "f0828a5471e340229c11c77ca80017937ce3c58cb788a17e5f1c2d5c485a9577" dependencies = [ "futures-channel", "futures-core", @@ -1005,6 +1263,16 @@ dependencies = [ "slab", ] +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.2.7" @@ -1012,15 +1280,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" +dependencies = [ + "color_quant", + "weezl", ] [[package]] name = "gimli" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" [[package]] name = "gl_generator" @@ -1035,14 +1315,30 @@ dependencies = [ [[package]] name = "glium" -version = "0.30.2" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "506a2aa1564891d447ae5d1ba37519a8efd6d01ea3e7952da81aa30430c90007" +checksum = "0ab4f09b43d8ee427a700cb9ed3b20e0e858d62a509edded1a98ca5707d68e19" dependencies = [ "backtrace", "fnv", "gl_generator", - "glutin", + "glutin 0.28.0", + "lazy_static", + "memoffset", + "smallvec", + "takeable-option", +] + +[[package]] +name = "glium" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2766728ecb86014b91d3d687614b32d65aacbbdc887f424a7b03cba3ab593bf" +dependencies = [ + "backtrace", + "fnv", + "gl_generator", + "glutin 0.29.1", "lazy_static", "memoffset", "smallvec", @@ -1063,9 +1359,9 @@ dependencies = [ [[package]] name = "glutin" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "762d6cd2e1b855d99668ebe591cc9058659d85ac39a9a2078000eb122ddba8f0" +checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2" dependencies = [ "android_glue", "cgl", @@ -1077,22 +1373,48 @@ dependencies = [ "glutin_glx_sys", "glutin_wgl_sys", "lazy_static", - "libloading 0.7.3", + "libloading", "log", "objc", "osmesa-sys", "parking_lot 0.11.2", - "wayland-client 0.28.6", + "wayland-client", "wayland-egl", "winapi", - "winit", + "winit 0.26.1", +] + +[[package]] +name = "glutin" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444c9ad294fdcaf20ccf6726b78f380b5450275540c9b68ab62f49726ad1c713" +dependencies = [ + "cgl", + "cocoa 0.24.0", + "core-foundation 0.9.3", + "glutin_egl_sys", + "glutin_gles2_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading", + "log", + "objc", + "once_cell", + "osmesa-sys", + "parking_lot 0.12.1", + "raw-window-handle 0.5.0", + "wayland-client", + "wayland-egl", + "winapi", + "winit 0.27.2", ] [[package]] name = "glutin_egl_sys" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +checksum = "68900f84b471f31ea1d1355567eb865a2cf446294f06cef8d653ed7bcf5f013d" dependencies = [ "gl_generator", "winapi", @@ -1116,9 +1438,9 @@ dependencies = [ [[package]] name = "glutin_glx_sys" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +checksum = "d93d0575865098580c5b3a423188cd959419912ea60b1e48e8b3b526f6d02468" dependencies = [ "gl_generator", "x11-dl", @@ -1161,18 +1483,15 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heck" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -1192,6 +1511,19 @@ dependencies = [ "quick-error", ] +[[package]] +name = "iana-time-zone" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5528d9c2817db4e10cc78f8d4c8228906e5854f389ff6b076cee3572a09d35" +dependencies = [ + "android_system_properties", + "core-foundation-sys 0.8.3", + "js-sys", + "wasm-bindgen", + "winapi", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1199,15 +1531,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "indexmap" -version = "1.8.2" +name = "idna" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30ca2ecf7666107ff827a8e481de6a132a9b687ed3bb20bb1c144a36c00964" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", ] +[[package]] +name = "inflate" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" +dependencies = [ + "adler32", +] + [[package]] name = "instant" version = "0.1.12" @@ -1215,6 +1586,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1223,6 +1597,26 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -1230,10 +1624,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] -name = "js-sys" -version = "0.3.58" +name = "jpeg-decoder" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" +checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ "wasm-bindgen", ] @@ -1244,12 +1647,6 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" -[[package]] -name = "lazy-bytes-cast" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1257,20 +1654,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "libc" -version = "0.2.126" +name = "lebe" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] -name = "libloading" -version = "0.6.7" +name = "libc" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" -dependencies = [ - "cfg-if 1.0.0", - "winapi", -] +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "libloading" @@ -1310,6 +1703,12 @@ dependencies = [ "libc", ] +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + [[package]] name = "memchr" version = "2.5.0" @@ -1318,18 +1717,18 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" dependencies = [ "libc", ] [[package]] name = "memmap2" -version = "0.3.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498" dependencies = [ "libc", ] @@ -1353,7 +1752,7 @@ dependencies = [ "block", "cocoa 0.20.2", "core-graphics 0.19.2", - "foreign-types", + "foreign-types 0.3.2", "log", "objc", ] @@ -1375,22 +1774,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.14" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - -[[package]] -name = "mio" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" dependencies = [ "libc", "log", @@ -1399,60 +1785,114 @@ dependencies = [ ] [[package]] -name = "mio-misc" -version = "1.2.2" +name = "nanorand" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47412f3a52115b936ff2a229b803498c7b4d332adeb87c2f1498c9da54c398c" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" dependencies = [ - "crossbeam", - "crossbeam-queue", - "log", - "mio 0.7.14", -] - -[[package]] -name = "miow" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" -dependencies = [ - "winapi", + "getrandom", ] [[package]] name = "ndk" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" dependencies = [ + "bitflags", "jni-sys", - "ndk-sys", + "ndk-sys 0.2.2", "num_enum", "thiserror", ] [[package]] -name = "ndk-glue" -version = "0.3.0" +name = "ndk" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.4.0", + "num_enum", + "raw-window-handle 0.5.0", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71bee8ea72d685477e28bd004cfe1bf99c754d688cd78cad139eae4089484d4" dependencies = [ "lazy_static", "libc", "log", - "ndk", + "ndk 0.5.0", + "ndk-context", "ndk-macro", - "ndk-sys", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-glue" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f" +dependencies = [ + "libc", + "log", + "ndk 0.7.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.4.0", + "once_cell", + "parking_lot 0.12.1", ] [[package]] name = "ndk-macro" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" dependencies = [ "darling", - "proc-macro-crate 0.1.5", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -1465,27 +1905,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" [[package]] -name = "nix" -version = "0.18.0" +name = "ndk-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" dependencies = [ - "bitflags", - "cc", - "cfg-if 0.1.10", - "libc", + "jni-sys", ] [[package]] -name = "nix" -version = "0.20.0" +name = "ndk-sys" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +checksum = "21d83ec9c63ec5bf950200a8e508bdad6659972187b625469f58ef8c08e29046" dependencies = [ - "bitflags", - "cc", - "cfg-if 1.0.0", - "libc", + "jni-sys", ] [[package]] @@ -1516,9 +1950,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" +checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc" dependencies = [ "bitflags", "cfg-if 1.0.0", @@ -1526,6 +1960,20 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb" +dependencies = [ + "autocfg", + "bitflags", + "cfg-if 1.0.0", + "libc", + "memoffset", + "pin-utils", +] + [[package]] name = "nohash-hasher" version = "0.2.0" @@ -1542,15 +1990,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "ntapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -1561,6 +2000,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1595,7 +2045,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ - "proc-macro-crate 1.1.3", + "proc-macro-crate", "proc-macro2", "quote", "syn", @@ -1642,18 +2092,18 @@ dependencies = [ [[package]] name = "object" -version = "0.28.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" +checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e" [[package]] name = "osmesa-sys" @@ -1666,20 +2116,11 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.6.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" +checksum = "07ef1a404ae479dd6906f4fa2c88b3c94028f1284beb42a47c183a7c27ee9a3e" dependencies = [ - "ttf-parser 0.6.2", -] - -[[package]] -name = "owned_ttf_parser" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" -dependencies = [ - "ttf-parser 0.15.1", + "ttf-parser", ] [[package]] @@ -1746,6 +2187,26 @@ dependencies = [ "log", ] +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1764,6 +2225,18 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +[[package]] +name = "png" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -1776,28 +2249,20 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] @@ -1808,34 +2273,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-xml" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" -dependencies = [ - "memchr", -] - [[package]] name = "quote" -version = "1.0.18" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] -[[package]] -name = "raw-window-handle" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" -dependencies = [ - "libc", - "raw-window-handle 0.4.3", -] - [[package]] name = "raw-window-handle" version = "0.4.3" @@ -1846,30 +2292,52 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.2.13" +name = "raw-window-handle" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" +dependencies = [ + "cty", +] + +[[package]] +name = "rayon" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - [[package]] name = "regex" -version = "1.5.6" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" dependencies = [ "aho-corasick", "memchr", @@ -1884,9 +2352,9 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.26" +version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" [[package]] name = "ron" @@ -1915,20 +2383,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] -name = "rusttype" -version = "0.9.2" +name = "ryu" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" -dependencies = [ - "ab_glyph_rasterizer", - "owned_ttf_parser 0.6.0", -] +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] -name = "ryu" -version = "1.0.10" +name = "safe_arch" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +dependencies = [ + "bytemuck", +] [[package]] name = "same-file" @@ -1945,6 +2412,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1952,25 +2425,69 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "serde" -version = "1.0.137" +name = "sctk-adwaita" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "04b7c47a572f73de28bee5b5060d085b42b6ce1e4ee2b49c956ea7b25e94b6f0" +dependencies = [ + "crossfont", + "log", + "smithay-client-toolkit 0.16.0", + "tiny-skia", +] + +[[package]] +name = "serde" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" +dependencies = [ + "itoa 1.0.3", + "ryu", + "serde", +] + +[[package]] +name = "servo-fontconfig" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" +dependencies = [ + "libc", + "servo-fontconfig-sys", +] + +[[package]] +name = "servo-fontconfig-sys" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" +dependencies = [ + "expat-sys", + "freetype-sys", + "pkg-config", +] + [[package]] name = "shaderc" version = "0.7.4" @@ -2018,7 +2535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" dependencies = [ "libc", - "mio 0.8.3", + "mio", "signal-hook", ] @@ -2033,9 +2550,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] [[package]] name = "slotmap" @@ -2048,28 +2568,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "smithay-client-toolkit" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4750c76fd5d3ac95fa3ed80fe667d6a3d8590a960e5b575b98eea93339a80b80" -dependencies = [ - "andrew", - "bitflags", - "calloop", - "dlib 0.4.2", - "lazy_static", - "log", - "memmap2 0.1.0", - "nix 0.18.0", - "wayland-client 0.28.6", - "wayland-cursor 0.28.6", - "wayland-protocols 0.28.6", -] +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" [[package]] name = "smithay-client-toolkit" @@ -2078,25 +2579,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" dependencies = [ "bitflags", - "dlib 0.5.0", + "calloop 0.9.3", + "dlib", "lazy_static", "log", "memmap2 0.3.1", "nix 0.22.3", "pkg-config", - "wayland-client 0.29.4", - "wayland-cursor 0.29.4", - "wayland-protocols 0.29.4", + "wayland-client", + "wayland-cursor", + "wayland-protocols", ] [[package]] -name = "smithay-clipboard" -version = "0.6.5" +name = "smithay-client-toolkit" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "610b551bd25378bfd2b8e7a0fcbd83d427e8f2f6a40c47ae0f70688e9949dd55" +checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454" dependencies = [ - "smithay-client-toolkit 0.15.4", - "wayland-client 0.29.4", + "bitflags", + "calloop 0.10.1", + "dlib", + "lazy_static", + "log", + "memmap2 0.5.7", + "nix 0.24.2", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", ] [[package]] @@ -2110,20 +2621,25 @@ dependencies = [ ] [[package]] -name = "spirv_headers" -version = "1.5.0" +name = "spin" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5b132530b1ac069df335577e3581765995cba5a13995cdbbdbc8fb057c532c" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" dependencies = [ - "bitflags", - "num-traits", + "lock_api", ] [[package]] -name = "strsim" -version = "0.9.3" +name = "str-buf" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "sudo" @@ -2137,9 +2653,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.96" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -2163,24 +2679,44 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiff" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7259662e32d1e219321eb309d5f9d898b779769d81b76e762c07c8e5d38fcb65" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.1.44" @@ -2193,15 +2729,56 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "1.19.2" +name = "tiny-skia" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +checksum = "642680569bb895b16e4b9d181c60be1ed136fa0c9c7f11d004daf053ba89bf82" dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if 1.0.0", + "png", + "safe_arch", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c114d32f0c2ee43d585367cb013dfaba967ab9f62b90d9af0d696e955e70fa6c" +dependencies = [ + "arrayref", + "bytemuck", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581" +dependencies = [ + "autocfg", "bytes", "libc", "memchr", - "mio 0.8.3", + "mio", "num_cpus", "once_cell", "parking_lot 0.12.1", @@ -2233,16 +2810,42 @@ dependencies = [ ] [[package]] -name = "ttf-parser" -version = "0.6.2" +name = "tracing" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" +dependencies = [ + "once_cell", +] [[package]] name = "ttf-parser" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d4b50cba812f0f04f0707bb6a0eaa5fae4ae05d90fc2a377998d2f21e77a1c" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" [[package]] name = "tui" @@ -2258,10 +2861,25 @@ dependencies = [ ] [[package]] -name = "unicode-ident" -version = "1.0.1" +name = "unicode-bidi" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] [[package]] name = "unicode-segmentation" @@ -2275,6 +2893,24 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" @@ -2283,28 +2919,32 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vk-parse" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1538fa783f47fb5a6eb495f024f426599a4fe66ff3773ff2252156c64d350a" +checksum = "29f3bfdc05ca5a9f385f50daa1d714b60324b68814b3bae99d797f0952e13e84" dependencies = [ "xml-rs", ] [[package]] name = "vulkano" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e631daf0d54bf36908ccff9f38ced7ff253a327e396ac13503a11401bee8c38" +checksum = "3663883d6bf6e3d34c891432fe5ce5829ad75f0cc2e43b3d079340385c2d81e0" dependencies = [ "ash", + "bytemuck", "crossbeam-queue", - "fnv", "half", "heck", "indexmap", "lazy_static", - "parking_lot 0.11.2", + "parking_lot 0.12.1", + "proc-macro2", + "quote", "regex", + "serde", + "serde_json", "shared_library", "smallvec", "vk-parse", @@ -2312,30 +2952,30 @@ dependencies = [ [[package]] name = "vulkano-shaders" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f45834e124ae0fdc95a358d83f163d9b14e9ec7780d99cd5aecbf4e76b1a67e" +checksum = "a462137ae796894a271b4d8048ef33597a8173e0ae3e4ec54fc72e70c2d1a977" dependencies = [ - "num-traits", + "heck", "proc-macro2", "quote", "shaderc", - "spirv_headers", "syn", + "vulkano", ] [[package]] name = "vulkano-win" -version = "0.25.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5a84fe7d636a1aefdaecabb89b8c47d0b3a785653a38ffbc69a34fb46f6784" +checksum = "ba30adc8d7b317e155e43343b6d30195d335df139d168d2ae5ece7837d57e887" dependencies = [ "cocoa 0.20.2", "metal", "objc", - "raw-window-handle 0.3.4", + "raw-window-handle 0.4.3", "vulkano", - "winit", + "winit 0.26.1", ] [[package]] @@ -2363,9 +3003,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2373,13 +3013,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -2388,9 +3028,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2398,9 +3038,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", @@ -2411,25 +3051,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.81" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" - -[[package]] -name = "wayland-client" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ab332350e502f159382201394a78e3cc12d0f04db863429260164ea40e0355" -dependencies = [ - "bitflags", - "downcast-rs", - "libc", - "nix 0.20.0", - "scoped-tls", - "wayland-commons 0.28.6", - "wayland-scanner 0.28.6", - "wayland-sys 0.28.6", -] +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "wayland-client" @@ -2442,21 +3066,9 @@ dependencies = [ "libc", "nix 0.22.3", "scoped-tls", - "wayland-commons 0.29.4", - "wayland-scanner 0.29.4", - "wayland-sys 0.29.4", -] - -[[package]] -name = "wayland-commons" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21817947c7011bbd0a27e11b17b337bfd022e8544b071a2641232047966fbda" -dependencies = [ - "nix 0.20.0", - "once_cell", - "smallvec", - "wayland-sys 0.28.6", + "wayland-commons", + "wayland-scanner", + "wayland-sys", ] [[package]] @@ -2468,18 +3080,7 @@ dependencies = [ "nix 0.22.3", "once_cell", "smallvec", - "wayland-sys 0.29.4", -] - -[[package]] -name = "wayland-cursor" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be610084edd1586d45e7bdd275fe345c7c1873598caa464c4fb835dee70fa65a" -dependencies = [ - "nix 0.20.0", - "wayland-client 0.28.6", - "xcursor", + "wayland-sys", ] [[package]] @@ -2489,30 +3090,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" dependencies = [ "nix 0.22.3", - "wayland-client 0.29.4", + "wayland-client", "xcursor", ] [[package]] name = "wayland-egl" -version = "0.28.6" +version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ba1ab1e18756b23982d36f08856d521d7df45015f404a2d7c4f0b2d2f66956" +checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" dependencies = [ - "wayland-client 0.28.6", - "wayland-sys 0.28.6", -] - -[[package]] -name = "wayland-protocols" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "286620ea4d803bacf61fa087a4242ee316693099ee5a140796aaba02b29f861f" -dependencies = [ - "bitflags", - "wayland-client 0.28.6", - "wayland-commons 0.28.6", - "wayland-scanner 0.28.6", + "wayland-client", + "wayland-sys", ] [[package]] @@ -2522,20 +3111,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" dependencies = [ "bitflags", - "wayland-client 0.29.4", - "wayland-commons 0.29.4", - "wayland-scanner 0.29.4", -] - -[[package]] -name = "wayland-scanner" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce923eb2deb61de332d1f356ec7b6bf37094dc5573952e1c8936db03b54c03f1" -dependencies = [ - "proc-macro2", - "quote", - "xml-rs", + "wayland-client", + "wayland-commons", + "wayland-scanner", ] [[package]] @@ -2549,33 +3127,22 @@ dependencies = [ "xml-rs", ] -[[package]] -name = "wayland-sys" -version = "0.28.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d841fca9aed7febf9bed2e9796c49bf58d4152ceda8ac949ebe00868d8f0feb8" -dependencies = [ - "dlib 0.5.0", - "lazy_static", - "pkg-config", -] - [[package]] name = "wayland-sys" version = "0.29.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" dependencies = [ - "dlib 0.5.0", + "dlib", "lazy_static", "pkg-config", ] [[package]] name = "web-sys" -version = "0.3.58" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -2583,20 +3150,29 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.5.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecad156490d6b620308ed411cfee90d280b3cbd13e189ea0d3fada8acc89158a" +checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b" dependencies = [ + "jni", + "ndk-glue 0.6.2", + "url", "web-sys", "widestring", "winapi", ] [[package]] -name = "widestring" -version = "0.4.3" +name = "weezl" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" [[package]] name = "winapi" @@ -2623,6 +3199,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2674,9 +3259,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winit" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79610794594d5e86be473ef7763f604f2159cbac8c94debd00df8fb41e86c2f8" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" dependencies = [ "bitflags", "cocoa 0.24.0", @@ -2688,36 +3273,70 @@ dependencies = [ "lazy_static", "libc", "log", - "mio 0.7.14", - "mio-misc", - "ndk", - "ndk-glue", - "ndk-sys", + "mio", + "ndk 0.5.0", + "ndk-glue 0.5.2", + "ndk-sys 0.2.2", "objc", "parking_lot 0.11.2", "percent-encoding", - "raw-window-handle 0.3.4", - "scopeguard", - "smithay-client-toolkit 0.12.3", - "wayland-client 0.28.6", + "raw-window-handle 0.4.3", + "smithay-client-toolkit 0.15.4", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", "winapi", "x11-dl", ] [[package]] -name = "x11-clipboard" -version = "0.5.3" +name = "winit" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" +checksum = "83a8f3e9d742401efcfe833b8f84960397482ff049cb7bf59a112e14a4be97f7" dependencies = [ - "xcb", + "bitflags", + "cocoa 0.24.0", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "dispatch", + "instant", + "libc", + "log", + "mio", + "ndk 0.7.0", + "ndk-glue 0.7.0", + "objc", + "once_cell", + "parking_lot 0.12.1", + "percent-encoding", + "raw-window-handle 0.4.3", + "raw-window-handle 0.5.0", + "sctk-adwaita", + "smithay-client-toolkit 0.16.0", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "windows-sys", + "x11-dl", +] + +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", ] [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6" dependencies = [ "lazy_static", "libc", @@ -2725,14 +3344,15 @@ dependencies = [ ] [[package]] -name = "xcb" -version = "0.10.1" +name = "x11rb" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" +checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" dependencies = [ - "libc", - "log", - "quick-xml", + "gethostname", + "nix 0.22.3", + "winapi", + "winapi-wsapoll", ] [[package]] @@ -2744,15 +3364,6 @@ dependencies = [ "nom", ] -[[package]] -name = "xdg" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" -dependencies = [ - "dirs", -] - [[package]] name = "xml-rs" version = "0.8.4" diff --git a/amdfan/src/main.rs b/amdfan/src/main.rs index 534558f..347a982 100644 --- a/amdfan/src/main.rs +++ b/amdfan/src/main.rs @@ -1,17 +1,20 @@ +use std::io; +use std::path::PathBuf; +use std::time::{Duration, Instant}; + use amdgpu_config::fan::{MatrixPoint, DEFAULT_FAN_CONFIG_PATH}; -use crossterm::{ - event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, - execute, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +use crossterm::event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}; +use crossterm::execute; +use crossterm::terminal::{ + disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; use gumdrop::Options; -use std::path::PathBuf; -use std::time::Instant; -use std::{io, time::Duration}; -use tui::backend::Backend; +use tui::backend::{Backend, CrosstermBackend}; +use tui::layout::*; use tui::style::{Color, Modifier, Style}; use tui::symbols::Marker; -use tui::{backend::CrosstermBackend, layout::*, widgets::*, Frame, Terminal}; +use tui::widgets::*; +use tui::{Frame, Terminal}; #[derive(Options)] struct Opts { diff --git a/amdfand/src/change_mode.rs b/amdfand/src/change_mode.rs index 3c2a229..8b5a295 100644 --- a/amdfand/src/change_mode.rs +++ b/amdfand/src/change_mode.rs @@ -1,7 +1,6 @@ -use gumdrop::Options; - use amdgpu::utils::hw_mons; use amdgpu_config::fan::Config; +use gumdrop::Options; use crate::command::Fan; use crate::{AmdFanError, FanMode}; diff --git a/amdfand/src/command.rs b/amdfand/src/command.rs index 8fd199d..231b96c 100644 --- a/amdfand/src/command.rs +++ b/amdfand/src/command.rs @@ -1,5 +1,3 @@ -use gumdrop::Options; - use amdgpu::hw_mon::HwMon; use amdgpu::utils::{linear_map, load_temp_inputs}; use amdgpu::{ @@ -7,6 +5,7 @@ use amdgpu::{ PULSE_WIDTH_MODULATION_MIN, PULSE_WIDTH_MODULATION_MODE, }; use amdgpu_config::fan::Config; +use gumdrop::Options; use crate::{change_mode, service}; @@ -90,7 +89,8 @@ impl Fan { v.into_iter().map(|hw| Self::wrap(hw, config)).collect() } - /// Change fan speed to given value if it's between minimal and maximal value + /// Change fan speed to given value if it's between minimal and maximal + /// value pub fn set_speed(&mut self, speed: f64) -> crate::Result<()> { let min = self.pwm_min() as f64; let max = self.pwm_max() as f64; @@ -99,15 +99,16 @@ impl Fan { Ok(()) } - /// Change gpu fan speed management to manual (amdfand will manage speed) instead of - /// GPU embedded manager + /// Change gpu fan speed management to manual (amdfand will manage speed) + /// instead of GPU embedded manager pub fn write_manual(&self) -> crate::Result<()> { self.hw_mon_write(MODULATION_ENABLED_FILE, 1) .map_err(FanError::ManualSpeedFailed)?; Ok(()) } - /// Change gpu fan speed management to automatic, speed will be managed by GPU embedded manager + /// Change gpu fan speed management to automatic, speed will be managed by + /// GPU embedded manager pub fn write_automatic(&self) -> crate::Result<()> { self.hw_mon_write("pwm1_enable", 2) .map_err(FanError::AutomaticSpeedFailed)?; @@ -132,8 +133,8 @@ impl Fan { } /// Get maximal GPU temperature from all inputs. - /// This is not recommended since GPU can heat differently in different parts and usually only - /// temp1 should be taken for consideration. + /// This is not recommended since GPU can heat differently in different + /// parts and usually only temp1 should be taken for consideration. pub fn max_gpu_temp(&self) -> crate::Result { if let Some(input) = self.temp_input.as_ref() { let value = self.read_gpu_temp(&input.as_string())?; diff --git a/amdfand/src/main.rs b/amdfand/src/main.rs index 4d5eac1..d209735 100644 --- a/amdfand/src/main.rs +++ b/amdfand/src/main.rs @@ -1,12 +1,9 @@ extern crate log; -use gumdrop::Options; - -use amdgpu::{ - lock_file::PidLock, - utils::{ensure_config_dir, hw_mons}, -}; +use amdgpu::lock_file::PidLock; +use amdgpu::utils::{ensure_config_dir, hw_mons}; use amdgpu_config::fan::{load_config, Config, DEFAULT_FAN_CONFIG_PATH}; +use gumdrop::Options; use crate::command::FanCommand; use crate::error::AmdFanError; diff --git a/amdfand/src/service.rs b/amdfand/src/service.rs index 3cc13f5..00e7589 100644 --- a/amdfand/src/service.rs +++ b/amdfand/src/service.rs @@ -1,13 +1,13 @@ -use gumdrop::Options; - use amdgpu::utils::hw_mons; use amdgpu::{config_reloaded, is_reload_required, listen_unix_signal}; use amdgpu_config::fan::Config; +use gumdrop::Options; use crate::command::Fan; use crate::AmdFanError; -/// Start service which will change fan speed according to config and GPU temperature +/// Start service which will change fan speed according to config and GPU +/// temperature pub fn run(mut config: Config) -> crate::Result<()> { listen_unix_signal(); diff --git a/amdgpu-config/src/fan.rs b/amdgpu-config/src/fan.rs index 3578ab0..7fe4f3e 100644 --- a/amdgpu-config/src/fan.rs +++ b/amdgpu-config/src/fan.rs @@ -28,7 +28,8 @@ impl MatrixPoint { pub struct Config { #[serde(skip)] path: String, - /// One of temperature inputs /sys/class/drm/card{X}/device/hwmon/hwmon{Y}/temp{Z}_input + /// One of temperature inputs + /// /sys/class/drm/card{X}/device/hwmon/hwmon{Y}/temp{Z}_input /// If nothing is provided higher reading will be taken (this is not good!) temp_input: Option, log_level: LogLevel, @@ -242,9 +243,8 @@ pub fn load_config(config_path: &str) -> Result { #[cfg(test)] mod parse_config { - use serde::Deserialize; - use amdgpu::{AmdGpuError, Card, TempInput}; + use serde::Deserialize; #[derive(Deserialize, PartialEq, Eq, Debug)] pub struct Foo { diff --git a/amdgpu-config/src/monitor.rs b/amdgpu-config/src/monitor.rs index 881ec26..065b73f 100644 --- a/amdgpu-config/src/monitor.rs +++ b/amdgpu-config/src/monitor.rs @@ -1,7 +1,6 @@ -use serde::{Deserialize, Serialize}; - use amdgpu::utils::ensure_config; use amdgpu::LogLevel; +use serde::{Deserialize, Serialize}; pub static DEFAULT_MONITOR_CONFIG_PATH: &str = "/etc/amdfand/monitor.toml"; diff --git a/amdgpu/src/error.rs b/amdgpu/src/error.rs index 6e559a0..38242f9 100644 --- a/amdgpu/src/error.rs +++ b/amdgpu/src/error.rs @@ -1,10 +1,12 @@ -#[cfg(feature = "gui-helper")] -use crate::helper_cmd::GuiHelperError; -use crate::lock_file::LockFileError; -use crate::ports::PortsError; -use pidlock::PidlockError; use std::fmt::{Debug, Display, Formatter}; +use pidlock::PidlockError; + +use crate::lock_file::LockFileError; +#[cfg(feature = "gui-helper")] +use crate::pidfile::helper_cmd::GuiHelperError; +use crate::pidfile::ports::PortsError; + pub struct IoFailure { pub io: std::io::Error, pub path: std::path::PathBuf, diff --git a/amdgpu/src/lib.rs b/amdgpu/src/lib.rs index 9cc0917..4b1e551 100644 --- a/amdgpu/src/lib.rs +++ b/amdgpu/src/lib.rs @@ -1,16 +1,14 @@ -use serde::{Deserialize, Serialize}; - pub use card::*; pub use error::*; +use serde::{Deserialize, Serialize}; pub use temp_input::*; mod card; mod error; #[cfg(feature = "gui-helper")] -pub mod helper_cmd; pub mod hw_mon; pub mod lock_file; -pub mod ports; +pub mod pidfile; mod temp_input; pub mod utils; @@ -28,7 +26,9 @@ pub static PULSE_WIDTH_MODULATION_MAX: &str = "pwm1_max"; /// pulse width modulation fan level (0-255) pub static PULSE_WIDTH_MODULATION: &str = "pwm1"; -/// pulse width modulation fan control method (0: no fan speed control, 1: manual fan speed control using pwm interface, 2: automatic fan speed control) +/// pulse width modulation fan control method (0: no fan speed control, 1: +/// manual fan speed control using pwm interface, 2: automatic fan speed +/// control) pub static PULSE_WIDTH_MODULATION_MODE: &str = "pwm1_enable"; // static PULSE_WIDTH_MODULATION_DISABLED: &str = "0"; diff --git a/amdgpu/src/lock_file.rs b/amdgpu/src/lock_file.rs index 588c68b..9c2d346 100644 --- a/amdgpu/src/lock_file.rs +++ b/amdgpu/src/lock_file.rs @@ -1,11 +1,13 @@ //! Create lock file and prevent running 2 identical services. //! NOTE: For 2 amdfand services you may just give 2 different names -use crate::helper_cmd::Pid; -use crate::IoFailure; -use nix::libc; use std::path::Path; +use nix::libc; + +use crate::pidfile::Pid; +use crate::IoFailure; + #[derive(Debug, thiserror::Error)] pub enum LockFileError { #[error("Failed to read {path}. {err:?}")] @@ -56,7 +58,8 @@ impl PidLock { /// Create new lock file. File will be created if: /// * pid file does not exists /// * pid file exists but process is dead - /// * old pid and current pid have different names (lock file exists after reboot and PID was taken by other process) + /// * old pid and current pid have different names (lock file exists after + /// reboot and PID was taken by other process) pub fn acquire(&mut self) -> Result<(), crate::error::AmdGpuError> { log::debug!("PID LOCK acquiring {}", self.pid_path); let pid = self.process_pid(); @@ -84,7 +87,7 @@ impl PidLock { log::warn!("Conflicting {} and {} for process {}", old.0, pid.0, name); return Err(LockFileError::Conflict { pid: old, name }.into()); } - Ok(name /*name isn't the same*/) => { + Ok(name /* name isn't the same */) => { log::debug!( "Old process {:?} and current process {:?} have different names, overriding....", name, self.name diff --git a/amdgpu/src/helper_cmd.rs b/amdgpu/src/pidfile/helper_cmd.rs similarity index 87% rename from amdgpu/src/helper_cmd.rs rename to amdgpu/src/pidfile/helper_cmd.rs index a369d78..f86275f 100644 --- a/amdgpu/src/helper_cmd.rs +++ b/amdgpu/src/pidfile/helper_cmd.rs @@ -1,9 +1,10 @@ //! AMD GUI helper communication toolkit use std::io::{Read, Write}; -use std::ops::Deref; use std::os::unix::net::UnixStream; +use crate::pidfile::{Pid, PidResponse}; + #[derive(Debug, thiserror::Error)] pub enum GuiHelperError { #[error("GUI Helper socket file not found. Is service running?")] @@ -14,18 +15,6 @@ pub enum GuiHelperError { Serialize(#[from] ron::Error), } -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] -#[serde(transparent)] -pub struct Pid(pub i32); - -impl Deref for Pid { - type Target = i32; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum Command { ReloadConfig { pid: Pid }, @@ -41,6 +30,12 @@ pub enum Response { ConfigFileSaveFailed(String), } +impl PidResponse for Response { + fn kill_response() -> Self { + Self::NoOp + } +} + pub fn sock_file() -> std::path::PathBuf { std::path::Path::new("/tmp").join("amdgui-helper.sock") } diff --git a/amdgpu/src/pidfile/mod.rs b/amdgpu/src/pidfile/mod.rs new file mode 100644 index 0000000..e7b6095 --- /dev/null +++ b/amdgpu/src/pidfile/mod.rs @@ -0,0 +1,133 @@ +use std::fmt::Debug; +use std::io::{Read, Write}; +use std::marker::PhantomData; +use std::net::Shutdown; +use std::ops::Deref; +use std::os::unix::net::UnixStream; + +use serde::de::DeserializeOwned; +use serde::Serialize; + +pub mod helper_cmd; +pub mod ports; + +#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] +#[serde(transparent)] +pub struct Pid(pub i32); + +impl Deref for Pid { + type Target = i32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub fn handle_connection(stream: UnixStream, handle_command: HandleCmd) +where + HandleCmd: FnOnce(Service, Cmd) + Copy, + Cmd: DeserializeOwned + Serialize + Debug, + Res: DeserializeOwned + Serialize + Debug + PidResponse, +{ + let mut service = Service::::new(stream); + + let command = match service.read_command() { + Some(s) => s, + _ => return service.kill(), + }; + + log::info!("Incoming {:?}", command); + let cmd = match ron::from_str::(command.trim()) { + Ok(cmd) => cmd, + Err(e) => { + log::warn!("Invalid message {:?}. {:?}", command, e); + return service.kill(); + } + }; + handle_command(service, cmd); +} + +pub trait PidResponse: Sized { + fn kill_response() -> Self; +} + +pub struct Service(UnixStream, PhantomData) +where + Response: serde::Serialize + Debug + PidResponse; + +impl Service +where + Response: serde::Serialize + Debug + PidResponse, +{ + pub fn new(file: UnixStream) -> Self { + Self(file, Default::default()) + } + + /// Serialize and send command + pub fn write_response(&mut self, res: Response) { + write_response(&mut self.0, res) + } + + /// Read from `.sock` file new line separated commands + pub fn read_command(&mut self) -> Option { + read_command(&mut self.0) + } + + /// Close connection with no operation response + pub fn kill(mut self) { + self.write_response(Response::kill_response()); + self.close(); + } + + pub fn close(self) { + let _ = self.0.shutdown(Shutdown::Both); + } +} + +/// Serialize and send command +pub fn write_response(file: &mut UnixStream, res: Response) +where + Response: serde::Serialize + Debug, +{ + match ron::to_string(&res) { + Ok(buffer) => match file.write_all(buffer.as_bytes()) { + Ok(_) => { + log::info!("Response successfully written") + } + Err(e) => log::warn!("Failed to write response. {:?}", e), + }, + Err(e) => { + log::warn!("Failed to serialize response {:?}. {:?}", res, e) + } + } +} + +/// Read from `.sock` file new line separated commands +pub fn read_command(file: &mut UnixStream) -> Option { + let mut command = String::with_capacity(100); + log::info!("Reading stream..."); + read_line(file, &mut command); + if command.is_empty() { + return None; + } + Some(command) +} + +pub fn read_line(stream: &mut UnixStream, command: &mut String) { + let mut buffer = [0]; + while stream.read_exact(&mut buffer).is_ok() { + if buffer[0] == b'\n' { + break; + } + match std::str::from_utf8(&buffer) { + Ok(s) => { + command.push_str(s); + } + Err(e) => { + log::error!("Failed to read from client. {:?}", e); + let _ = stream.shutdown(Shutdown::Both); + continue; + } + } + } +} diff --git a/amdgpu/src/ports.rs b/amdgpu/src/pidfile/ports.rs similarity index 92% rename from amdgpu/src/ports.rs rename to amdgpu/src/pidfile/ports.rs index 3d0b17e..d232ad0 100644 --- a/amdgpu/src/ports.rs +++ b/amdgpu/src/pidfile/ports.rs @@ -1,12 +1,13 @@ //! AMD GUI helper communication toolkit use std::io::{Read, Write}; -use std::ops::Deref; use std::os::unix::net::UnixStream; use std::path::PathBuf; use serde::{Deserialize, Serialize}; +use crate::pidfile::PidResponse; + #[derive(Debug, thiserror::Error)] pub enum PortsError { #[error("AMD GPU ports socket file not found. Is service running?")] @@ -74,18 +75,6 @@ impl Output { } } -#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] -#[serde(transparent)] -pub struct Pid(pub i32); - -impl Deref for Pid { - type Target = i32; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum Command { Ports, @@ -97,6 +86,12 @@ pub enum Response { NoOp, } +impl PidResponse for Response { + fn kill_response() -> Self { + Self::NoOp + } +} + pub fn sock_file() -> PathBuf { std::path::Path::new("/tmp").join("amdgpu-ports.sock") } diff --git a/amdgpu/src/temp_input.rs b/amdgpu/src/temp_input.rs index 7656b25..8cbd36b 100644 --- a/amdgpu/src/temp_input.rs +++ b/amdgpu/src/temp_input.rs @@ -1,6 +1,7 @@ -use crate::AmdGpuError; use serde::Serializer; +use crate::AmdGpuError; + #[derive(PartialEq, Eq, Debug, Copy, Clone)] pub struct TempInput(pub u16); diff --git a/amdgui-helper/src/main.rs b/amdgui-helper/src/main.rs index 8753520..3cfd742 100644 --- a/amdgui-helper/src/main.rs +++ b/amdgui-helper/src/main.rs @@ -1,23 +1,26 @@ -//! Special daemon with root privileges. Since GUI should not have (and sometimes can't have) root -//! privileges and service processes are designed to be as small as possible this is proxy. +//! Special daemon with root privileges. Since GUI should not have (and +//! sometimes can't have) root privileges and service processes are designed to +//! be as small as possible this is proxy. //! //! It is responsible for: -//! * Loading all amdfand processes. In order to do this process needs to be killed with signal 0 to check if it still is alive +//! * Loading all amdfand processes. In order to do this process needs to be +//! killed with signal 0 to check if it still is alive //! * Reload amdfand process with signal SIGHUP //! * Save changed config file //! -//! It is using `/tmp/amdgui-helper.sock` file and `ron` serialization for communication. -//! After each operation connection is terminated so each command needs new connection. +//! It is using `/tmp/amdgui-helper.sock` file and `ron` serialization for +//! communication. After each operation connection is terminated so each command +//! needs new connection. #![allow(clippy::non_octal_unix_permissions)] -use amdgpu::helper_cmd::{Command, Pid, Response}; -use amdgpu::IoFailure; use std::ffi::OsStr; use std::fs::Permissions; -use std::io::{Read, Write}; -use std::net::Shutdown; use std::os::unix::fs::PermissionsExt; -use std::os::unix::net::{UnixListener, UnixStream}; +use std::os::unix::net::UnixListener; + +use amdgpu::pidfile::helper_cmd::{Command, Response}; +use amdgpu::pidfile::{handle_connection, Pid}; +use amdgpu::IoFailure; #[derive(Debug, thiserror::Error)] pub enum Error { @@ -38,7 +41,7 @@ fn main() -> Result<()> { let mut lock = amdgpu::lock_file::PidLock::new("amdgui", String::from("helper"))?; lock.acquire()?; - let sock_path = amdgpu::helper_cmd::sock_file(); + let sock_path = amdgpu::pidfile::helper_cmd::sock_file(); let listener = { let _ = std::fs::remove_file(&sock_path); @@ -52,86 +55,27 @@ fn main() -> Result<()> { } while let Ok((stream, _addr)) = listener.accept() { - handle_connection(stream); + handle_connection::<_, Command, Response>(stream, handle_command); } lock.release()?; Ok(()) } -pub struct Service(UnixStream); +pub type Service = amdgpu::pidfile::Service; -impl Service { - /// Serialize and send command - pub fn write_response(&mut self, res: amdgpu::helper_cmd::Response) { - match ron::to_string(&res) { - Ok(buffer) => match self.0.write_all(buffer.as_bytes()) { - Ok(_) => { - log::info!("Response successfully written") - } - Err(e) => log::warn!("Failed to write response. {:?}", e), - }, - Err(e) => { - log::warn!("Failed to serialize response {:?}. {:?}", res, e) - } - } - } - - /// Read from `.sock` file new line separated commands - pub fn read_command(&mut self) -> Option { - let mut command = String::with_capacity(100); - log::info!("Reading stream..."); - read_line(&mut self.0, &mut command); - if command.is_empty() { - return None; - } - Some(command) - } - - /// Close connection with no operation response - pub fn kill(mut self) { - self.write_response(Response::NoOp); - self.close(); - } - - pub fn close(self) { - let _ = self.0.shutdown(Shutdown::Both); - } -} - -fn handle_connection(stream: UnixStream) { - let mut service = Service(stream); - - let command = match service.read_command() { - Some(s) => s, - _ => return service.kill(), - }; - - log::info!("Incoming {:?}", command); - let cmd = match ron::from_str::(command.trim()) { - Ok(cmd) => cmd, - Err(e) => { - log::warn!("Invalid message {:?}. {:?}", command, e); - return service.kill(); - } - }; - handle_command(service, cmd); -} - -fn handle_command(mut service: Service, cmd: Command) { +fn handle_command(service: Service, cmd: Command) { match cmd { Command::ReloadConfig { pid } => { log::info!("Reloading config file for pid {:?}", pid); handle_reload_config(service, pid); } Command::FanServices => handle_fan_services(service), - Command::SaveFanConfig { path, content } => { - handle_save_fan_config(&mut service, path, content) - } + Command::SaveFanConfig { path, content } => handle_save_fan_config(service, path, content), } } -fn handle_save_fan_config(service: &mut Service, path: String, content: String) { +fn handle_save_fan_config(mut service: Service, path: String, content: String) { match std::fs::write(path, content) { Err(e) => service.write_response(Response::ConfigFileSaveFailed(format!("{:?}", e))), Ok(..) => service.write_response(Response::ConfigFileSaved), @@ -145,25 +89,6 @@ fn handle_fan_services(mut service: Service) { service.write_response(Response::Services(services)); } -fn read_line(stream: &mut UnixStream, command: &mut String) { - let mut buffer = [0]; - while stream.read_exact(&mut buffer).is_ok() { - if buffer[0] == b'\n' { - break; - } - match std::str::from_utf8(&buffer) { - Ok(s) => { - command.push_str(s); - } - Err(e) => { - log::error!("Failed to read from client. {:?}", e); - let _ = stream.shutdown(Shutdown::Both); - continue; - } - } - } -} - fn handle_reload_config(service: Service, pid: Pid) { unsafe { nix::libc::kill(pid.0, nix::sys::signal::Signal::SIGHUP as i32); diff --git a/amdguid/Cargo.toml b/amdguid/Cargo.toml index 13522aa..b7c6dfe 100644 --- a/amdguid/Cargo.toml +++ b/amdguid/Cargo.toml @@ -40,28 +40,31 @@ gumdrop = { version = "0.8" } log = { version = "0.4" } pretty_env_logger = { version = "0.4" } -egui = { version = "0.15", optional = true } -epaint = { version = "0.15", features = ["serialize"], optional = true } -epi = { version = "0.15", optional = true } -winit = { version = "0.25", optional = true } -egui-winit = { version = "0.15", optional = true } +egui = { version = "0.18", optional = true, features = [] } +epaint = { version = "0.18", features = [], optional = true } +epi = { version = "0.17.0", optional = true } +winit = { version = "0.26", optional = true } +egui-winit = { version = "0.18", optional = true } # vulkan -egui_vulkano = { version = "0.4", optional = true } -vulkano-win = { version = "0.25", optional = true } -vulkano = { version = "0.25", optional = true } -vulkano-shaders = { version = "0.25", optional = true } +egui_vulkano = { version = "0.8.0", optional = true } +vulkano-win = { version = "0.29.0", optional = true } +vulkano = { version = "0.29.0", optional = true } +vulkano-shaders = { version = "0.29.0", optional = true } +bytemuck = { version = "*" } # xorg glium -glium = { version = "0.30", optional = true } -egui_glium = { version = "0.15", optional = true } +glium = { version = "0.32.1", optional = true } +egui_glium = { version = "0.18.0", optional = true } # xorg glow -glutin = { version = "0.27", optional = true } +glutin = { version = "0.29", optional = true } glow = { version = "0.11", optional = true } -egui_glow = { version = "0.15", optional = true } +egui_glow = { version = "0.18", optional = true } tokio = { version = "1.15", features = ["full"] } -parking_lot = { version = "0.11" } +parking_lot = { version = "0.12" } -nix = { version = "0.24" } +nix = { version = "0.25" } + +image = { version = "0.24.2" } [dev-dependencies] amdgpu = { path = "../amdgpu", version = "1.0", features = ["gui-helper"] } diff --git a/amdguid/assets/icons/html_port-512.png b/amdguid/assets/icons/html_port-512.png new file mode 100644 index 0000000000000000000000000000000000000000..8819ee3d6912c6bafcc4d87bd76977891127f3ba GIT binary patch literal 9410 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

O^&F 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 OW9$Db(@cndul_%vFw=Pe literal 0 HcmV?d00001 diff --git a/amdguid/assets/icons/vga_port-512.png b/amdguid/assets/icons/vga_port-512.png new file mode 100644 index 0000000000000000000000000000000000000000..3f79ee6fff86b0dc70a7b0ac0008954659b3f8b9 GIT binary patch literal 9380 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 r#VIn literal 0 HcmV?d00001 diff --git a/amdguid/src/app.rs b/amdguid/src/app.rs index 13ee593..046f6e6 100644 --- a/amdguid/src/app.rs +++ b/amdguid/src/app.rs @@ -1,10 +1,14 @@ -use crate::widgets::{ChangeFanSettings, CoolingPerformance}; -use amdgpu::helper_cmd::Pid; -use egui::{CtxRef, Ui}; +use std::collections::{BTreeMap, HashMap}; +use std::sync::Arc; + +use amdgpu::pidfile::ports::Output; +use amdgpu::pidfile::Pid; +use egui::Ui; use epi::Frame; use parking_lot::Mutex; -use std::collections::HashMap; -use std::sync::Arc; + +use crate::widgets::outputs_settings::OutputsSettings; +use crate::widgets::{ChangeFanSettings, CoolingPerformance}; pub enum ChangeState { New, @@ -61,6 +65,7 @@ impl From> for FanServices { pub enum Page { Config, Monitoring, + Outputs, Settings, } @@ -85,14 +90,16 @@ pub struct StatefulConfig { pub struct AmdGui { pub page: Page, pid_files: FanServices, + outputs: BTreeMap>, cooling_performance: CoolingPerformance, change_fan_settings: ChangeFanSettings, + outputs_settings: OutputsSettings, config: StatefulConfig, reload_pid_list_delay: u8, } impl epi::App for AmdGui { - fn update(&mut self, _ctx: &CtxRef, _frame: &mut Frame<'_>) {} + fn update(&mut self, _ctx: &epi::egui::Context, _frame: &Frame) {} fn name(&self) -> &str { "AMD GUI" @@ -104,8 +111,10 @@ impl AmdGui { Self { page: Default::default(), pid_files: FanServices::from(vec![]), + outputs: Default::default(), cooling_performance: CoolingPerformance::new(100, config.clone()), change_fan_settings: ChangeFanSettings::new(config.clone()), + outputs_settings: OutputsSettings::default(), config: StatefulConfig { config, state: ChangeState::New, @@ -124,6 +133,10 @@ impl AmdGui { self.cooling_performance.draw(ui, &self.pid_files); } Page::Settings => {} + Page::Outputs => { + self.outputs_settings + .draw(ui, &mut self.config, &self.outputs); + } } } @@ -131,20 +144,71 @@ impl AmdGui { self.cooling_performance.tick(); if self.pid_files.0.is_empty() || self.reload_pid_list_delay.checked_sub(1).is_none() { self.reload_pid_list_delay = RELOAD_PID_LIST_DELAY; - match amdgpu::helper_cmd::send_command(amdgpu::helper_cmd::Command::FanServices) { - Ok(amdgpu::helper_cmd::Response::Services(services)) - if self.pid_files.list_changed(&services) => - { - self.pid_files = FanServices::from(services); + + { + use amdgpu::pidfile::helper_cmd::{send_command, Command, Response}; + + match send_command(Command::FanServices) { + Ok(Response::Services(services)) if self.pid_files.list_changed(&services) => { + self.pid_files = FanServices::from(services); + } + Ok(Response::Services(_services)) => { + // SKIP + } + Ok(res) => { + log::warn!("Unexpected response {:?} while loading fan services", res); + } + Err(e) => { + log::warn!("Failed to load amd fan services pid list. {:?}", e); + } } - Ok(amdgpu::helper_cmd::Response::Services(_services)) => { - // SKIP - } - Ok(res) => { - log::warn!("Unexpected response {:?} while loading fan services", res); - } - Err(e) => { - log::warn!("Failed to load amd fan services pid list. {:?}", e); + } + + { + use amdgpu::pidfile::ports::{send_command, Command, Response}; + + match send_command(Command::Ports) { + Ok(Response::NoOp) => {} + Ok(Response::Ports(outputs)) => { + let mut names = outputs.iter().fold( + Vec::with_capacity(outputs.len()), + |mut set, output| { + set.push(format!("{}", output.card)); + set + }, + ); + names.sort(); + + let mut tree = BTreeMap::new(); + names.into_iter().for_each(|name| { + tree.insert(name, Vec::with_capacity(6)); + }); + + self.outputs = outputs.into_iter().fold(tree, |mut agg, output| { + let v = agg + .entry(output.card.clone()) + .or_insert_with(|| Vec::with_capacity(6)); + v.push(output); + v.sort_by(|a, b| { + format!( + "{}{}{}", + a.port_type, + a.port_name.as_deref().unwrap_or_default(), + a.port_number, + ) + .cmp(&format!( + "{}{}{}", + b.port_type, + b.port_name.as_deref().unwrap_or_default(), + b.port_number, + )) + }); + agg + }); + } + Err(e) => { + log::warn!("Failed to load amd fan services pid list. {:?}", e); + } } } } else { diff --git a/amdguid/src/backend/glium_backend.rs b/amdguid/src/backend/glium_backend.rs index a0ca948..40e987c 100644 --- a/amdguid/src/backend/glium_backend.rs +++ b/amdguid/src/backend/glium_backend.rs @@ -1,10 +1,11 @@ -use parking_lot::Mutex; use std::sync::Arc; + +use glium::glutin; +use parking_lot::Mutex; use tokio::sync::mpsc::UnboundedReceiver; use crate::app::AmdGui; use crate::backend::create_ui; -use glium::glutin; fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display { let window_builder = glutin::window::WindowBuilder::new() diff --git a/amdguid/src/backend/glow_backend.rs b/amdguid/src/backend/glow_backend.rs index 7cbdc9d..69c464d 100644 --- a/amdguid/src/backend/glow_backend.rs +++ b/amdguid/src/backend/glow_backend.rs @@ -108,7 +108,9 @@ pub fn run_app(amd_gui: Arc>, mut receiver: UnboundedReceiver { egui.destroy(&gl); diff --git a/amdguid/src/backend/mod.rs b/amdguid/src/backend/mod.rs index 9a4273e..4deda97 100644 --- a/amdguid/src/backend/mod.rs +++ b/amdguid/src/backend/mod.rs @@ -5,39 +5,52 @@ pub mod glow_backend; #[cfg(feature = "wayland")] pub mod wayland_backend; +use std::sync::Arc; + use egui::panel::TopBottomSide; use egui::{Layout, PointerButton}; -use epaint::TextStyle; +#[cfg(feature = "xorg-glium")] +pub use glium_backend::run_app; +#[cfg(feature = "xorg-glow")] +pub use glow_backend::run_app; use parking_lot::Mutex; -use std::sync::Arc; #[cfg(feature = "wayland")] pub use wayland_backend::run_app; -#[cfg(feature = "xorg-glow")] -pub use glow_backend::run_app; - use crate::app::Page; use crate::AmdGui; -#[cfg(feature = "xorg-glium")] -pub use glium_backend::run_app; -pub fn create_ui(amd_gui: Arc>, ctx: &egui::CtxRef) { +pub fn create_ui(amd_gui: Arc>, ctx: &egui::Context) { egui::containers::TopBottomPanel::new(TopBottomSide::Top, "menu").show(ctx, |ui| { let mut child = ui.child_ui(ui.available_rect_before_wrap(), Layout::left_to_right()); if child - .add(egui::Button::new("Config").text_style(TextStyle::Heading)) + .add( + egui::Button::new("Outputs"), /* .text_style(TextStyle::Heading) */ + ) + .clicked_by(PointerButton::Primary) + { + amd_gui.lock().page = Page::Outputs; + } + if child + .add( + egui::Button::new("Config"), /* .text_style(TextStyle::Heading) */ + ) .clicked_by(PointerButton::Primary) { amd_gui.lock().page = Page::Config; } if child - .add(egui::Button::new("Monitoring").text_style(TextStyle::Heading)) + .add( + egui::Button::new("Monitoring"), /* .text_style(TextStyle::Heading) */ + ) .clicked_by(PointerButton::Primary) { amd_gui.lock().page = Page::Monitoring; } if child - .add(egui::Button::new("Settings").text_style(TextStyle::Heading)) + .add( + egui::Button::new("Settings"), /* .text_style(TextStyle::Heading) */ + ) .clicked_by(PointerButton::Primary) { amd_gui.lock().page = Page::Settings; @@ -54,6 +67,9 @@ pub fn create_ui(amd_gui: Arc>, ctx: &egui::CtxRef) { Page::Monitoring => { gui.ui(ui); } + Page::Outputs => { + gui.ui(ui); + } Page::Settings => { ctx.settings_ui(ui); } diff --git a/amdguid/src/backend/wayland_backend.rs b/amdguid/src/backend/wayland_backend.rs index f03bbae..d3acf3f 100644 --- a/amdguid/src/backend/wayland_backend.rs +++ b/amdguid/src/backend/wayland_backend.rs @@ -1,112 +1,156 @@ -use crate::app::AmdGui; -use crate::backend::create_ui; -use parking_lot::Mutex; +use std::convert::{TryFrom, TryInto}; use std::sync::Arc; + +use bytemuck::{Pod, Zeroable}; +use egui_vulkano::UpdateTexturesResult; +use parking_lot::Mutex; use tokio::sync::mpsc::UnboundedReceiver; -use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; -use vulkano::command_buffer::{ - AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents, -}; +use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess}; +use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents}; +use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType}; +use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo}; use vulkano::format::Format; use vulkano::image::view::ImageView; -use vulkano::image::{ImageUsage, SwapchainImage}; -use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass}; -use vulkano::swapchain::{AcquireError, ColorSpace, Swapchain, SwapchainCreationError}; -use vulkano::sync::{FlushError, GpuFuture}; -use vulkano::{swapchain, sync, Version}; +use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage}; +use vulkano::instance::{Instance, InstanceCreateInfo}; +use vulkano::pipeline::graphics::input_assembly::InputAssemblyState; +use vulkano::pipeline::graphics::vertex_input::BuffersDefinition; +use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState}; +use vulkano::pipeline::GraphicsPipeline; +use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}; +use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError}; +use vulkano::sync::{FenceSignalFuture, FlushError, GpuFuture}; +use vulkano::{swapchain, sync}; use vulkano_win::VkSurfaceBuild; -use winit::dpi::PhysicalSize; use winit::event::{Event, WindowEvent}; -use winit::event_loop::ControlFlow; -use winit::window::Window; +use winit::event_loop::{ControlFlow, EventLoop}; +use winit::window::{Fullscreen, Window, WindowBuilder}; -pub mod vs { - vulkano_shaders::shader! { - ty: "vertex", - src: " - #version 450 - layout(location = 0) in vec2 position; - void main() { - gl_Position = vec4(position, 0.0, 1.0); - } - " - } -} +use crate::app::AmdGui; +use crate::backend::create_ui; -pub mod fs { - vulkano_shaders::shader! { - ty: "fragment", - src: " - #version 450 - layout(location = 0) out vec4 f_color; - void main() { - f_color = vec4(1.0, 0.0, 0.0, 1.0); - } - " - } -} - -#[derive(Default, Debug, Clone)] +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] struct Vertex { position: [f32; 2], + color: [f32; 4], +} + +pub enum FrameEndFuture { + FenceSignalFuture(FenceSignalFuture), + BoxedFuture(Box), +} + +impl FrameEndFuture { + pub fn now(device: Arc) -> Self { + Self::BoxedFuture(sync::now(device).boxed()) + } + + pub fn get(self) -> Box { + match self { + FrameEndFuture::FenceSignalFuture(f) => f.boxed(), + FrameEndFuture::BoxedFuture(f) => f, + } + } +} + +impl AsMut for FrameEndFuture { + fn as_mut(&mut self) -> &mut (dyn GpuFuture + 'static) { + match self { + FrameEndFuture::FenceSignalFuture(f) => f, + FrameEndFuture::BoxedFuture(f) => f, + } + } } pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) { let required_extensions = vulkano_win::required_extensions(); - let instance = - vulkano::instance::Instance::new(None, Version::V1_0, &required_extensions, None).unwrap(); - let physical = vulkano::device::physical::PhysicalDevice::enumerate(&instance) - .next() - .unwrap(); + let instance = Instance::new(InstanceCreateInfo { + enabled_extensions: required_extensions, + ..Default::default() + }) + .unwrap(); - let event_loop = winit::event_loop::EventLoop::new(); - let surface = winit::window::WindowBuilder::new() - .with_inner_size(PhysicalSize::new(1024, 768)) - .with_title("AMD GUI") + let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); + + println!( + "Using device: {} (type: {:?})", + physical.properties().device_name, + physical.properties().device_type, + ); + + let event_loop = EventLoop::new(); + let surface = WindowBuilder::new() + .with_title("egui_vulkano demo") + .with_fullscreen(Some(Fullscreen::Borderless(None))) .build_vk_surface(&event_loop, instance.clone()) .unwrap(); - // vulkan - let queue_family = physical - .queue_families() - .find(|&q| q.supports_graphics() && surface.is_supported(q).unwrap_or(false)) + let device_extensions = DeviceExtensions { + khr_swapchain: true, + ..DeviceExtensions::none() + }; + + let (physical_device, queue_family) = PhysicalDevice::enumerate(&instance) + .filter(|&p| p.supported_extensions().is_superset_of(&device_extensions)) + .filter_map(|p| { + p.queue_families() + .find(|&q| q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false)) + .map(|q| (p, q)) + }) + .min_by_key(|(p, _)| match p.properties().device_type { + PhysicalDeviceType::DiscreteGpu => 0, + PhysicalDeviceType::IntegratedGpu => 1, + PhysicalDeviceType::VirtualGpu => 2, + PhysicalDeviceType::Cpu => 3, + PhysicalDeviceType::Other => 4, + }) .unwrap(); - let device_ext = vulkano::device::DeviceExtensions { - khr_swapchain: true, - ..vulkano::device::DeviceExtensions::none() - }; - let (device, mut queues) = vulkano::device::Device::new( - physical, - physical.supported_features(), - &device_ext, - [(queue_family, 0.5)].iter().cloned(), + let (device, mut queues) = Device::new( + physical_device, + DeviceCreateInfo { + enabled_extensions: physical_device + .required_extensions() + .union(&device_extensions), + queue_create_infos: vec![QueueCreateInfo::family(queue_family)], + ..Default::default() + }, ) .unwrap(); let queue = queues.next().unwrap(); let (mut swapchain, images) = { - let caps = surface.capabilities(physical).unwrap(); - let alpha = caps.supported_composite_alpha.iter().next().unwrap(); + let caps = physical_device + .surface_capabilities(&surface, Default::default()) + .unwrap(); + let composite_alpha = caps.supported_composite_alpha.iter().next().unwrap(); - assert!(&caps - .supported_formats - .contains(&(Format::B8G8R8A8Srgb, ColorSpace::SrgbNonLinear))); - let format = Format::B8G8R8A8Srgb; - let dimensions: [u32; 2] = surface.window().inner_size().into(); + let image_format = Some(Format::B8G8R8A8_SRGB); + let image_extent: [u32; 2] = surface.window().inner_size().into(); - Swapchain::start(device.clone(), surface.clone()) - .num_images(caps.min_image_count) - .format(format) - .dimensions(dimensions) - .usage(ImageUsage::color_attachment()) - .sharing_mode(&queue) - .composite_alpha(alpha) - .build() - .unwrap() + Swapchain::new( + device.clone(), + surface.clone(), + SwapchainCreateInfo { + min_image_count: caps.min_image_count, + image_format, + image_extent, + image_usage: ImageUsage::color_attachment(), + composite_alpha, + + ..Default::default() + }, + ) + .unwrap() }; + #[derive(Default, Debug, Clone, Copy, Pod, Zeroable)] + #[repr(C)] + struct Vertex { + position: [f32; 2], + } vulkano::impl_vertex!(Vertex, position); let vertex_buffer = { @@ -131,59 +175,82 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) .unwrap() }; - let vs = vs::Shader::load(device.clone()).unwrap(); - let fs = fs::Shader::load(device.clone()).unwrap(); + mod vs { + vulkano_shaders::shader! { + ty: "vertex", + src: " + #version 450 - let render_pass = Arc::new( - vulkano::ordered_passes_renderpass!( - device.clone(), - attachments: { - color: { - load: Clear, - store: Store, - format: swapchain.format(), - samples: 1, - } - }, - passes: [ - { color: [color], depth_stencil: {}, input: [] }, - { color: [color], depth_stencil: {}, input: [] } // Create a second render pass to draw egui - ] - ) - .unwrap(), - ); + layout(location = 0) in vec2 position; - let pipeline = Arc::new( - vulkano::pipeline::GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vs.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .fragment_shader(fs.main_entry_point(), ()) - .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) - .build(device.clone()) - .unwrap(), - ); + void main() { + gl_Position = vec4(position, 0.0, 1.0); + } + " + } + } - let mut dynamic_state = DynamicState { - line_width: None, - viewports: None, - scissors: None, - compare_mask: None, - write_mask: None, - reference: None, + mod fs { + vulkano_shaders::shader! { + ty: "fragment", + src: " + #version 450 + + layout(location = 0) out vec4 f_color; + + void main() { + f_color = vec4(1.0, 0.0, 0.0, 1.0); + } + " + } + } + + let vs = vs::load(device.clone()).unwrap(); + let fs = fs::load(device.clone()).unwrap(); + + let render_pass = vulkano::ordered_passes_renderpass!( + device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: swapchain.image_format(), + samples: 1, + } + }, + passes: [ + { color: [color], depth_stencil: {}, input: [] }, + { color: [color], depth_stencil: {}, input: [] } // Create a second renderpass to draw egui + ] + ) + .unwrap(); + + let pipeline = GraphicsPipeline::start() + .vertex_input_state(BuffersDefinition::new().vertex::()) + .vertex_shader(vs.entry_point("main").unwrap(), ()) + .input_assembly_state(InputAssemblyState::new()) + .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant()) + .fragment_shader(fs.entry_point("main").unwrap(), ()) + .render_pass(Subpass::from(render_pass.clone().into(), 0).unwrap()) + .build(device.clone()) + .unwrap(); + + let mut viewport = Viewport { + origin: [0.0, 0.0], + dimensions: [0.0, 0.0], + depth_range: 0.0..1.0, }; - let mut framebuffers = - window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state); + let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport); - let mut recreate_swap_chain = false; + let mut recreate_swapchain = false; - let mut previous_frame_end = Some(sync::now(device.clone()).boxed()); + let mut previous_frame_end = Some(FrameEndFuture::now(device.clone())); + //Set up everything need to draw the gui let window = surface.window(); - let mut egui_ctx = egui::CtxRef::default(); - let mut egui_winit = egui_winit::State::new(window); + let egui_ctx = egui::Context::default(); + let mut egui_winit = egui_winit::State::new(4096, window); let mut egui_painter = egui_vulkano::Painter::new( device.clone(), @@ -192,6 +259,11 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) ) .unwrap(); + //Set up some window to look at for the test + + // let mut my_texture = egui_ctx.load_texture("my_texture", + // ColorImage::example()); + event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { @@ -204,7 +276,7 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) event: WindowEvent::Resized(_), .. } => { - recreate_swap_chain = true; + recreate_swapchain = true; } Event::WindowEvent { event, .. } => { let egui_consumed_event = egui_winit.on_event(&egui_ctx, &event); @@ -212,39 +284,47 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) // do your own event handling here }; } - Event::UserEvent(_) | Event::RedrawEventsCleared => { - previous_frame_end.as_mut().unwrap().cleanup_finished(); + Event::RedrawEventsCleared => { + previous_frame_end + .as_mut() + .unwrap() + .as_mut() + .cleanup_finished(); - if recreate_swap_chain { + if recreate_swapchain { let dimensions: [u32; 2] = surface.window().inner_size().into(); - let (new_swap_chain, new_images) = - match swapchain.recreate().dimensions(dimensions).build() { + let (new_swapchain, new_images) = + match swapchain.recreate(SwapchainCreateInfo { + image_extent: surface.window().inner_size().into(), + ..swapchain.create_info() + }) { Ok(r) => r, - Err(SwapchainCreationError::UnsupportedDimensions) => return, - Err(e) => panic!("Failed to recreate swap chain: {:?}", e), + Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return, + Err(e) => panic!("Failed to recreate swapchain: {:?}", e), }; - swapchain = new_swap_chain; + swapchain = new_swapchain; framebuffers = window_size_dependent_setup( &new_images, render_pass.clone(), - &mut dynamic_state, + &mut viewport, ); - recreate_swap_chain = false; + viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; + recreate_swapchain = false; } let (image_num, suboptimal, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { - recreate_swap_chain = true; + recreate_swapchain = true; return; } Err(e) => panic!("Failed to acquire next image: {:?}", e), }; if suboptimal { - recreate_swap_chain = true; + recreate_swapchain = true; } let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()]; @@ -255,6 +335,20 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) ) .unwrap(); + egui_ctx.begin_frame(egui_winit.take_egui_input(surface.window())); + + create_ui(amd_gui.clone(), &egui_ctx); + + let egui_output = egui_ctx.end_frame(); + let platform_output = egui_output.platform_output; + egui_winit.handle_platform_output(surface.window(), &egui_ctx, platform_output); + + let result = egui_painter + .update_textures(egui_output.textures_delta, &mut builder) + .expect("egui texture error"); + + let wait_for_last_frame = result == UpdateTexturesResult::Changed; + // Do your usual rendering builder .begin_render_pass( @@ -263,29 +357,23 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) clear_values, ) .unwrap() - .draw( - pipeline.clone(), - &dynamic_state, - vertex_buffer.clone(), - (), - (), - ) + .set_viewport(0, [viewport.clone()]) + .bind_pipeline_graphics(pipeline.clone()) + .bind_vertex_buffers(0, vertex_buffer.clone()) + .draw(vertex_buffer.len().try_into().unwrap(), 1, 0, 0) .unwrap(); // Don't end the render pass yet - egui_ctx.begin_frame(egui_winit.take_egui_input(surface.window())); + // Build your gui - create_ui(amd_gui.clone(), &egui_ctx); - - let (egui_output, clipped_shapes) = egui_ctx.end_frame(); - egui_winit.handle_output(surface.window(), &egui_ctx, egui_output); + // Automatically start the next render subpass and draw the gui let size = surface.window().inner_size(); + let sf: f32 = surface.window().scale_factor() as f32; egui_painter .draw( &mut builder, - &dynamic_state, - [size.width as f32, size.height as f32], + [(size.width as f32) / sf, (size.height as f32) / sf], &egui_ctx, - clipped_shapes, + egui_output.shapes, ) .unwrap(); @@ -294,9 +382,16 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) let command_buffer = builder.build().unwrap(); + if wait_for_last_frame { + if let Some(FrameEndFuture::FenceSignalFuture(ref mut f)) = previous_frame_end { + f.wait(None).unwrap(); + } + } + let future = previous_frame_end .take() .unwrap() + .get() .join(acquire_future) .then_execute(queue.clone(), command_buffer) .unwrap() @@ -305,15 +400,15 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) match future { Ok(future) => { - previous_frame_end = Some(future.boxed()); + previous_frame_end = Some(FrameEndFuture::FenceSignalFuture(future)); } Err(FlushError::OutOfDate) => { - recreate_swap_chain = true; - previous_frame_end = Some(sync::now(device.clone()).boxed()); + recreate_swapchain = true; + previous_frame_end = Some(FrameEndFuture::now(device.clone())); } Err(e) => { println!("Failed to flush future: {:?}", e); - previous_frame_end = Some(sync::now(device.clone()).boxed()); + previous_frame_end = Some(FrameEndFuture::now(device.clone())); } } } @@ -325,28 +420,23 @@ pub fn run_app(amd_gui: Arc>, _receiver: UnboundedReceiver) fn window_size_dependent_setup( images: &[Arc>], render_pass: Arc, - dynamic_state: &mut DynamicState, -) -> Vec> { - let dimensions = images[0].dimensions(); - - let viewport = vulkano::pipeline::viewport::Viewport { - origin: [0.0, 0.0], - dimensions: [dimensions[0] as f32, dimensions[1] as f32], - depth_range: 0.0..1.0, - }; - dynamic_state.viewports = Some(vec![viewport]); + viewport: &mut Viewport, +) -> Vec> { + let dimensions = images[0].dimensions().width_height(); + viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; images .iter() .map(|image| { - let view = ImageView::new(image.clone()).unwrap(); - Arc::new( - Framebuffer::start(render_pass.clone()) - .add(view) - .unwrap() - .build() - .unwrap(), - ) as Arc + let view = ImageView::new_default(image.clone()).unwrap(); + Framebuffer::new( + render_pass.clone(), + FramebufferCreateInfo { + attachments: vec![view], + ..Default::default() + }, + ) + .unwrap() }) .collect::>() } diff --git a/amdguid/src/items.rs b/amdguid/src/items.rs index 8045f93..064a704 100644 --- a/amdguid/src/items.rs +++ b/amdguid/src/items.rs @@ -2,10 +2,9 @@ use std::ops::RangeInclusive; +pub use arrows::*; use egui::Pos2; use epaint::{Color32, Shape, Stroke}; - -pub use arrows::*; pub use h_line::*; pub use line::*; pub use marker_shape::*; @@ -129,7 +128,8 @@ impl ToString for LineStyle { // ---------------------------------------------------------------------------- -/// Describes a function y = f(x) with an optional range for x and a number of points. +/// Describes a function y = f(x) with an optional range for x and a number of +/// points. pub struct ExplicitGenerator { function: Box f64>, x_range: RangeInclusive, @@ -138,8 +138,8 @@ pub struct ExplicitGenerator { // ---------------------------------------------------------------------------- -/// Returns the x-coordinate of a possible intersection between a line segment from `p1` to `p2` and -/// a horizontal line at the given y-coordinate. +/// Returns the x-coordinate of a possible intersection between a line segment +/// from `p1` to `p2` and a horizontal line at the given y-coordinate. #[inline(always)] pub fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option { ((p1.y > y && p2.y < y) || (p1.y < y && p2.y > y)) diff --git a/amdguid/src/items/arrows.rs b/amdguid/src/items/arrows.rs index eabb9b4..7ab0f2b 100644 --- a/amdguid/src/items/arrows.rs +++ b/amdguid/src/items/arrows.rs @@ -1,9 +1,11 @@ +use std::ops::RangeInclusive; + +use egui::Ui; +use epaint::{Color32, Shape}; + use crate::items::plot_item::PlotItem; use crate::items::values::Values; use crate::transform::{Bounds, ScreenTransform}; -use egui::Ui; -use epaint::{Color32, Shape}; -use std::ops::RangeInclusive; /// A set of arrows. pub struct Arrows { diff --git a/amdguid/src/items/h_line.rs b/amdguid/src/items/h_line.rs index 8a545b7..623625f 100644 --- a/amdguid/src/items/h_line.rs +++ b/amdguid/src/items/h_line.rs @@ -1,11 +1,13 @@ +use std::ops::RangeInclusive; + +use egui::Ui; +use epaint::{Color32, Shape, Stroke}; + use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::items::LineStyle; use crate::transform::{Bounds, ScreenTransform}; -use egui::Ui; -use epaint::{Color32, Shape, Stroke}; -use std::ops::RangeInclusive; /// A horizontal line in a plot, filling the full width #[derive(Clone, Debug, PartialEq)] @@ -28,7 +30,8 @@ impl HLine { } } - /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. + /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will + /// be auto-assigned. #[must_use] pub fn color(mut self, color: impl Into) -> Self { self.stroke.color = color.into(); diff --git a/amdguid/src/items/line.rs b/amdguid/src/items/line.rs index 779e8dc..339fa0a 100644 --- a/amdguid/src/items/line.rs +++ b/amdguid/src/items/line.rs @@ -1,12 +1,14 @@ +use std::ops::RangeInclusive; + +use egui::{pos2, NumExt, Ui}; +use epaint::{Color32, Mesh, Rgba, Shape, Stroke}; + use crate::items; use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::items::{LineStyle, DEFAULT_FILL_ALPHA}; use crate::transform::{Bounds, ScreenTransform}; -use egui::{pos2, NumExt, Ui}; -use epaint::{Color32, Mesh, Rgba, Shape, Stroke}; -use std::ops::RangeInclusive; impl PlotItem for Line { fn get_shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec) { @@ -120,7 +122,8 @@ impl Line { } } - /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. + /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will + /// be auto-assigned. #[must_use] pub fn color(mut self, color: impl Into) -> Self { self.stroke.color = color.into(); diff --git a/amdguid/src/items/plot_image.rs b/amdguid/src/items/plot_image.rs index 1cd131e..797234b 100644 --- a/amdguid/src/items/plot_image.rs +++ b/amdguid/src/items/plot_image.rs @@ -1,10 +1,12 @@ +use std::ops::RangeInclusive; + +use egui::{pos2, Image, Rect, Ui, Vec2}; +use epaint::{Color32, Shape, Stroke, TextureId}; + use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::transform::{Bounds, ScreenTransform}; -use egui::{pos2, Image, Rect, Ui, Vec2}; -use epaint::{Color32, Shape, Stroke, TextureId}; -use std::ops::RangeInclusive; /// An image in the plot. pub struct PlotImage { @@ -65,8 +67,8 @@ impl PlotImage { /// /// This name will show up in the plot legend, if legends are turned on. /// - /// Multiple plot items may share the same name, in which case they will also share an entry in - /// the legend. + /// Multiple plot items may share the same name, in which case they will + /// also share an entry in the legend. #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn name(mut self, name: impl ToString) -> Self { diff --git a/amdguid/src/items/plot_item.rs b/amdguid/src/items/plot_item.rs index 38c6982..bb4a75f 100644 --- a/amdguid/src/items/plot_item.rs +++ b/amdguid/src/items/plot_item.rs @@ -1,8 +1,10 @@ -use crate::items::Values; -use crate::transform::{Bounds, ScreenTransform}; +use std::ops::RangeInclusive; + use egui::Ui; use epaint::{Color32, Shape}; -use std::ops::RangeInclusive; + +use crate::items::Values; +use crate::transform::{Bounds, ScreenTransform}; /// Trait shared by things that can be drawn in the plot. pub trait PlotItem { diff --git a/amdguid/src/items/points.rs b/amdguid/src/items/points.rs index 0c8a074..97ea387 100644 --- a/amdguid/src/items/points.rs +++ b/amdguid/src/items/points.rs @@ -1,17 +1,20 @@ +use std::ops::RangeInclusive; + +use egui::{pos2, vec2, Pos2, Ui}; +use epaint::{Color32, Shape, Stroke}; + use crate::items::marker_shape::MarkerShape; use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::transform::{Bounds, ScreenTransform}; -use egui::{pos2, vec2, Pos2, Ui}; -use epaint::{Color32, Shape, Stroke}; -use std::ops::RangeInclusive; /// A set of points. pub struct Points { pub(crate) series: Values, pub(crate) shape: MarkerShape, - /// Color of the marker. `Color32::TRANSPARENT` means that it will be picked automatically. + /// Color of the marker. `Color32::TRANSPARENT` means that it will be picked + /// automatically. pub(crate) color: Color32, /// Whether to fill the marker. Does not apply to all types. pub(crate) filled: bool, @@ -64,7 +67,8 @@ impl Points { self } - /// Whether to add stems between the markers and a horizontal reference line. + /// Whether to add stems between the markers and a horizontal reference + /// line. #[must_use] pub fn stems(mut self, y_reference: impl Into) -> Self { self.stems = Some(y_reference.into()); @@ -82,8 +86,8 @@ impl Points { /// /// This name will show up in the plot legend, if legends are turned on. /// - /// Multiple plot items may share the same name, in which case they will also share an entry in - /// the legend. + /// Multiple plot items may share the same name, in which case they will + /// also share an entry in the legend. #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn name(mut self, name: impl ToString) -> Self { diff --git a/amdguid/src/items/polygons.rs b/amdguid/src/items/polygons.rs index f0a579b..7821cb1 100644 --- a/amdguid/src/items/polygons.rs +++ b/amdguid/src/items/polygons.rs @@ -1,10 +1,12 @@ +use std::ops::RangeInclusive; + +use egui::{NumExt, Ui}; +use epaint::{Color32, Rgba, Shape, Stroke}; + use crate::items::plot_item::PlotItem; use crate::items::values::Values; use crate::items::{LineStyle, DEFAULT_FILL_ALPHA}; use crate::transform::{Bounds, ScreenTransform}; -use egui::{NumExt, Ui}; -use epaint::{Color32, Rgba, Shape, Stroke}; -use std::ops::RangeInclusive; /// A convex polygon. pub struct Polygon { @@ -28,8 +30,8 @@ impl Polygon { } } - /// Highlight this polygon in the plot by scaling up the stroke and reducing the fill - /// transparency. + /// Highlight this polygon in the plot by scaling up the stroke and reducing + /// the fill transparency. #[must_use] pub fn highlight(mut self) -> Self { self.highlight = true; @@ -50,7 +52,8 @@ impl Polygon { self } - /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. + /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will + /// be auto-assigned. #[must_use] pub fn color(mut self, color: impl Into) -> Self { self.stroke.color = color.into(); @@ -75,8 +78,8 @@ impl Polygon { /// /// This name will show up in the plot legend, if legends are turned on. /// - /// Multiple plot items may share the same name, in which case they will also share an entry in - /// the legend. + /// Multiple plot items may share the same name, in which case they will + /// also share an entry in the legend. #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn name(mut self, name: impl ToString) -> Self { diff --git a/amdguid/src/items/text.rs b/amdguid/src/items/text.rs index 53e25fb..784cd74 100644 --- a/amdguid/src/items/text.rs +++ b/amdguid/src/items/text.rs @@ -1,10 +1,12 @@ +use std::ops::RangeInclusive; + +use egui::{Align2, Rect, TextStyle, Ui}; +use epaint::{Color32, Shape, Stroke}; + use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::transform::{Bounds, ScreenTransform}; -use egui::{Align2, Rect, Ui}; -use epaint::{Color32, Shape, Stroke, TextStyle}; -use std::ops::RangeInclusive; /// Text inside the plot. pub struct Text { @@ -45,7 +47,8 @@ impl Text { self } - /// Text color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. + /// Text color. Default is `Color32::TRANSPARENT` which means a color will + /// be auto-assigned. #[must_use] pub fn color(mut self, color: impl Into) -> Self { self.color = color.into(); @@ -63,8 +66,8 @@ impl Text { /// /// This name will show up in the plot legend, if legends are turned on. /// - /// Multiple plot items may share the same name, in which case they will also share an entry in - /// the legend. + /// Multiple plot items may share the same name, in which case they will + /// also share an entry in the legend. #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn name(mut self, name: impl ToString) -> Self { @@ -80,10 +83,11 @@ impl PlotItem for Text { } else { self.color }; + let fond_id = ui.style().text_styles.get(&self.style).unwrap(); let pos = transform.position_from_value(&self.position); let galley = ui .fonts() - .layout_no_wrap(self.text.clone(), self.style, color); + .layout_no_wrap(self.text.clone(), fond_id.clone(), color); let rect = self .anchor .anchor_rect(Rect::from_min_size(pos, galley.size())); diff --git a/amdguid/src/items/v_line.rs b/amdguid/src/items/v_line.rs index c61a30e..4d6f7b7 100644 --- a/amdguid/src/items/v_line.rs +++ b/amdguid/src/items/v_line.rs @@ -1,11 +1,13 @@ +use std::ops::RangeInclusive; + +use egui::Ui; +use epaint::{Color32, Shape, Stroke}; + use crate::items::plot_item::PlotItem; use crate::items::value::Value; use crate::items::values::Values; use crate::items::LineStyle; use crate::transform::{Bounds, ScreenTransform}; -use egui::Ui; -use epaint::{Color32, Shape, Stroke}; -use std::ops::RangeInclusive; impl PlotItem for VLine { fn get_shapes(&self, _ui: &mut Ui, transform: &ScreenTransform, shapes: &mut Vec) { @@ -95,7 +97,8 @@ impl VLine { self } - /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. + /// Stroke color. Default is `Color32::TRANSPARENT` which means a color will + /// be auto-assigned. #[must_use] pub fn color(mut self, color: impl Into) -> Self { self.stroke.color = color.into(); @@ -113,8 +116,8 @@ impl VLine { /// /// This name will show up in the plot legend, if legends are turned on. /// - /// Multiple plot items may share the same name, in which case they will also share an entry in - /// the legend. + /// Multiple plot items may share the same name, in which case they will + /// also share an entry in the legend. #[allow(clippy::needless_pass_by_value)] #[must_use] pub fn name(mut self, name: impl ToString) -> Self { diff --git a/amdguid/src/items/value.rs b/amdguid/src/items/value.rs index 807670f..92d1677 100644 --- a/amdguid/src/items/value.rs +++ b/amdguid/src/items/value.rs @@ -4,8 +4,8 @@ /// large values (e.g. unix time on x axis). #[derive(Clone, Copy, Debug, PartialEq)] pub struct Value { - /// This is often something monotonically increasing, such as time, but doesn't have to be. - /// Goes from left to right. + /// This is often something monotonically increasing, such as time, but + /// doesn't have to be. Goes from left to right. pub x: f64, /// Goes from bottom to top (inverse of everything else in egui!). pub y: f64, diff --git a/amdguid/src/items/values.rs b/amdguid/src/items/values.rs index 6b0efd0..0ea6cf5 100644 --- a/amdguid/src/items/values.rs +++ b/amdguid/src/items/values.rs @@ -1,8 +1,9 @@ -use crate::items::{ExplicitGenerator, Value}; -use crate::transform::Bounds; use std::collections::Bound; use std::ops::{RangeBounds, RangeInclusive}; +use crate::items::{ExplicitGenerator, Value}; +use crate::transform::Bounds; + pub struct Values { pub values: Vec, generator: Option, @@ -20,7 +21,8 @@ impl Values { Self::from_values(iter.collect()) } - /// Draw a line based on a function `y=f(x)`, a range (which can be infinite) for x and the number of points. + /// Draw a line based on a function `y=f(x)`, a range (which can be + /// infinite) for x and the number of points. pub fn from_explicit_callback( function: impl Fn(f64) -> f64 + 'static, x_range: impl RangeBounds, @@ -48,8 +50,9 @@ impl Values { } } - /// Draw a line based on a function `(x,y)=f(t)`, a range for t and the number of points. - /// The range may be specified as start..end or as start..=end. + /// Draw a line based on a function `(x,y)=f(t)`, a range for t and the + /// number of points. The range may be specified as start..end or as + /// start..=end. pub fn from_parametric_callback( function: impl Fn(f64) -> (f64, f64), t_range: impl RangeBounds, @@ -92,13 +95,14 @@ impl Values { Self::from_values(values) } - /// Returns true if there are no data points available and there is no function to generate any. + /// Returns true if there are no data points available and there is no + /// function to generate any. pub fn is_empty(&self) -> bool { self.generator.is_none() && self.values.is_empty() } - /// If initialized with a generator function, this will generate `n` evenly spaced points in the - /// given range. + /// If initialized with a generator function, this will generate `n` evenly + /// spaced points in the given range. pub fn generate_points(&mut self, x_range: RangeInclusive) { if let Some(generator) = self.generator.take() { if let Some(intersection) = Self::range_intersection(&x_range, &generator.x_range) { diff --git a/amdguid/src/transform.rs b/amdguid/src/transform.rs index c22a919..ffdcc0d 100644 --- a/amdguid/src/transform.rs +++ b/amdguid/src/transform.rs @@ -117,7 +117,8 @@ impl Bounds { } } -/// Contains the screen rectangle and the plot bounds and provides methods to transform them. +/// Contains the screen rectangle and the plot bounds and provides methods to +/// transform them. #[derive(Clone)] pub struct ScreenTransform { /// The screen rectangle. diff --git a/amdguid/src/widgets/change_fan_settings.rs b/amdguid/src/widgets/change_fan_settings.rs index daed7ee..027ff69 100644 --- a/amdguid/src/widgets/change_fan_settings.rs +++ b/amdguid/src/widgets/change_fan_settings.rs @@ -1,12 +1,13 @@ -use amdgpu::helper_cmd::Command; +use amdgpu::pidfile::helper_cmd::{send_command, Command, Response}; use amdgpu_config::fan::MatrixPoint; use egui::{emath, pos2, Layout, PointerButton, Ui}; use epaint::Color32; use crate::app::{ChangeState, FanConfig, FanServices, StatefulConfig}; +use crate::widgets; use crate::widgets::drag_plot::PlotMsg; use crate::widgets::reload_section::ReloadSection; -use crate::{widgets, widgets::ConfigFile}; +use crate::widgets::ConfigFile; pub struct ChangeFanSettings { config: FanConfig, @@ -139,10 +140,10 @@ impl ChangeFanSettings { ui.label("Saving..."); } ChangeState::Success => { - ui.add(egui::Label::new("Saved").text_color(Color32::GREEN)); + ui.add(egui::Label::new("Saved")/*.text_color(Color32::GREEN)*/); } ChangeState::Failure(msg) => { - ui.add(egui::Label::new(format!("Failure. {}", msg)).text_color(Color32::RED)); + ui.add(egui::Label::new(format!("Failure. {}", msg))/*.text_color(Color32::RED)*/); } } }); @@ -164,11 +165,11 @@ impl ChangeFanSettings { path: String::from(config.path()), content, }; - match amdgpu::helper_cmd::send_command(command) { - Ok(amdgpu::helper_cmd::Response::ConfigFileSaveFailed(msg)) => { + match send_command(command) { + Ok(Response::ConfigFileSaveFailed(msg)) => { state.state = ChangeState::Failure(msg); } - Ok(amdgpu::helper_cmd::Response::ConfigFileSaved) => { + Ok(Response::ConfigFileSaved) => { state.state = ChangeState::Success; } _ => {} diff --git a/amdguid/src/widgets/config_file.rs b/amdguid/src/widgets/config_file.rs index c4e1793..46892f9 100644 --- a/amdguid/src/widgets/config_file.rs +++ b/amdguid/src/widgets/config_file.rs @@ -1,6 +1,5 @@ -use egui::{PointerButton, Response, Sense, Ui, Widget}; - use amdgpu_config::fan::MatrixPoint; +use egui::{PointerButton, Response, Sense, Ui, Widget}; use crate::app::FanConfig; diff --git a/amdguid/src/widgets/cooling_performance.rs b/amdguid/src/widgets/cooling_performance.rs index b70f84c..1999783 100644 --- a/amdguid/src/widgets/cooling_performance.rs +++ b/amdguid/src/widgets/cooling_performance.rs @@ -1,11 +1,13 @@ -use crate::app::{FanConfig, FanServices}; -use amdgpu::Card; -use amdmond_lib::AmdMon; use core::option::Option; use core::option::Option::Some; -use egui::Ui; use std::collections::vec_deque::VecDeque; +use amdgpu::Card; +use amdmond_lib::AmdMon; +use egui::Ui; + +use crate::app::{FanConfig, FanServices}; + pub struct CoolingPerformance { capacity: usize, data: VecDeque, @@ -55,18 +57,20 @@ impl CoolingPerformance { .name("Overheating") .color(Color32::DARK_RED); - let plot = Plot::new("cooling performance") + ui.label("Temperature"); + Plot::new("cooling performance") .allow_drag(false) .allow_zoom(false) .height(600.0) - .line(curve) - .hline(zero) - .hline(optimal) - .hline(target) - .legend(Legend::default()); + .show(ui, |plot_ui| { + plot_ui.line(curve); + plot_ui.hline(zero); + plot_ui.hline(optimal); + plot_ui.hline(target); + // plot_ui.legend(Legend::default()); + }); - ui.label("Temperature"); - ui.add(plot); + // ui.add(plot); ui.horizontal(|ui| { ui.label("Current temperature"); ui.label(format!("{:<3.2}°C", current)); diff --git a/amdguid/src/widgets/drag_plot.rs b/amdguid/src/widgets/drag_plot.rs index 83c7a5b..8ed831b 100644 --- a/amdguid/src/widgets/drag_plot.rs +++ b/amdguid/src/widgets/drag_plot.rs @@ -1,10 +1,9 @@ use egui::{emath, vec2, CursorIcon, Id, NumExt, PointerButton, Response, Sense, Ui, Vec2}; use epaint::ahash::AHashSet; use epaint::color::Hsva; -use epaint::Color32; +use epaint::{Color32, Rounding}; -use crate::items::HLine; -use crate::items::*; +use crate::items::{HLine, *}; use crate::transform::{Bounds, ScreenTransform}; use crate::widgets::drag_plot_prepared::DragPlotPrepared; use crate::widgets::legend::Legend; @@ -16,7 +15,8 @@ pub enum PlotMsg { Drag(emath::Vec2), } -#[derive(Clone, serde::Serialize, serde::Deserialize)] +// , serde::Serialize, serde::Deserialize +#[derive(Clone)] struct PlotMemory { bounds: Bounds, auto_bounds: bool, @@ -125,12 +125,13 @@ where self.next_auto_color_idx += 1; let golden_ratio = (5.0_f32.sqrt() - 1.0) / 2.0; // 0.61803398875 let h = i as f32 * golden_ratio; - Hsva::new(h, 0.85, 0.5, 1.0).into() // TODO: OkLab or some other perspective color space + Hsva::new(h, 0.85, 0.5, 1.0).into() // TODO: OkLab or some other + // perspective color space } /// width / height ratio of the data. - /// For instance, it can be useful to set this to `1.0` for when the two axes show the same - /// unit. + /// For instance, it can be useful to set this to `1.0` for when the two + /// axes show the same unit. /// By default the plot window's aspect ratio is used. #[must_use] pub fn data_aspect(mut self, data_aspect: f32) -> Self { @@ -139,7 +140,8 @@ where } /// width / height ratio of the plot region. - /// By default no fixed aspect ratio is set (and width/height will fill the ui it is in). + /// By default no fixed aspect ratio is set (and width/height will fill the + /// ui it is in). #[must_use] pub fn view_aspect(mut self, view_aspect: f32) -> Self { self.view_aspect = Some(view_aspect); @@ -147,7 +149,8 @@ where } /// Width of plot. By default a plot will fill the ui it is in. - /// If you set [`Self::view_aspect`], the width can be calculated from the height. + /// If you set [`Self::view_aspect`], the width can be calculated from the + /// height. #[must_use] pub fn width(mut self, width: f32) -> Self { self.min_size.x = width; @@ -156,7 +159,8 @@ where } /// Height of plot. By default a plot will fill the ui it is in. - /// If you set [`Self::view_aspect`], the height can be calculated from the width. + /// If you set [`Self::view_aspect`], the height can be calculated from the + /// width. #[must_use] pub fn height(mut self, height: f32) -> Self { self.min_size.y = height; @@ -240,9 +244,9 @@ where } = self; let plot_id = ui.make_persistent_id(id); let memory = ui - .memory() - .id_data - .get_mut_or_insert_with(plot_id, || PlotMemory { + .ctx() + .data() + .get_persisted_mut_or_insert_with(plot_id, || PlotMemory { bounds: min_auto_bounds, auto_bounds: false, hovered_entry: None, @@ -284,11 +288,11 @@ where }; let (rect, response) = ui.allocate_exact_size(size, Sense::click_and_drag()); - let plot_painter = ui.painter().sub_region(rect); + let plot_painter = ui.painter().with_clip_rect(rect); plot_painter.add(epaint::RectShape { rect, - corner_radius: 2.0, + rounding: Rounding::from(2.0), fill: ui.visuals().extreme_bg_color, stroke: ui.visuals().widgets.noninteractive.bg_stroke, }); @@ -408,16 +412,15 @@ where hovered_entry = legend.get_hovered_entry_name(); } - ui.memory().id_data.insert( - plot_id, - PlotMemory { + ui.ctx() + .data() + .get_persisted_mut_or_insert_with(plot_id, || PlotMemory { bounds: t_bounds, auto_bounds, hovered_entry, hidden_items, min_auto_bounds, - }, - ); + }); response.on_hover_cursor(CursorIcon::Crosshair) } } diff --git a/amdguid/src/widgets/drag_plot_prepared.rs b/amdguid/src/widgets/drag_plot_prepared.rs index e69aa2d..61b19fe 100644 --- a/amdguid/src/widgets/drag_plot_prepared.rs +++ b/amdguid/src/widgets/drag_plot_prepared.rs @@ -1,8 +1,7 @@ -use egui::{emath, pos2, remap_clamp, vec2, Align2, Layout, NumExt, Pos2, Response, Ui}; -use epaint::{Color32, Rgba, Shape, Stroke, TextStyle}; +use egui::{emath, pos2, remap_clamp, vec2, Align2, Layout, NumExt, Pos2, Response, TextStyle, Ui}; +use epaint::{Color32, Rgba, Shape, Stroke}; -use crate::items::Value; -use crate::items::{Line, PlotItem}; +use crate::items::{Line, PlotItem, Value}; use crate::transform::ScreenTransform; pub struct DragPlotPrepared { @@ -41,7 +40,9 @@ impl DragPlotPrepared { self.hover(ui, pointer, &mut shapes); } - ui.painter().sub_region(*transform.frame()).extend(shapes); + ui.painter() + .with_clip_rect(*transform.frame()) + .extend(shapes); } fn paint_axis(&self, ui: &Ui, axis: usize, shapes: &mut Vec) { @@ -77,9 +78,12 @@ impl DragPlotPrepared { let n = (value_main / step_size).round() as i64; let spacing_in_points = if n % (base * base) == 0 { - step_size_in_points * (base_f * base_f) as f32 // think line (multiple of 100) + step_size_in_points * (base_f * base_f) as f32 // think line + // (multiple of + // 100) } else if n % base == 0 { - step_size_in_points * base_f as f32 // medium line (multiple of 10) + step_size_in_points * base_f as f32 // medium line (multiple of + // 10) } else { step_size_in_points // thin line }; @@ -106,7 +110,11 @@ impl DragPlotPrepared { let color = color_from_alpha(ui, text_alpha); let text = emath::round_to_decimals(value_main, 5).to_string(); // hack - let galley = ui.painter().layout_no_wrap(text, text_style, color); + let galley = ui.painter().layout_no_wrap( + text, + ui.style().text_styles.get(&text_style).cloned().unwrap(), + color, + ); let mut text_pos = pos_in_gui + vec2(1.0, -galley.size().y); @@ -135,15 +143,13 @@ impl DragPlotPrepared { let interact_radius: f32 = 16.0; let mut closest_value = None; let mut closest_dist_sq = interact_radius.powi(2); - for item in lines { - if let Some(values) = item.values() { - for (idx, value) in values.values.iter().enumerate() { - let pos = transform.position_from_value(value); - let dist_sq = pointer.distance_sq(pos); - if dist_sq < closest_dist_sq { - closest_dist_sq = dist_sq; - closest_value = Some(idx); - } + for values in lines.iter().filter_map(|v| v.values()) { + for (idx, value) in values.values.iter().enumerate() { + let pos = transform.position_from_value(value); + let dist_sq = pointer.distance_sq(pos); + if dist_sq < closest_dist_sq { + closest_dist_sq = dist_sq; + closest_value = Some(idx); } } } @@ -255,11 +261,15 @@ impl DragPlotPrepared { }; shapes.push(Shape::text( - ui.fonts(), + &*ui.fonts(), pointer + vec2(3.0, -2.0), Align2::LEFT_BOTTOM, text, - TextStyle::Body, + ui.style() + .text_styles + .get(&TextStyle::Body) + .cloned() + .unwrap(), ui.visuals().text_color(), )); } diff --git a/amdguid/src/widgets/legend.rs b/amdguid/src/widgets/legend.rs index c661721..18a29cd 100644 --- a/amdguid/src/widgets/legend.rs +++ b/amdguid/src/widgets/legend.rs @@ -1,7 +1,9 @@ use std::string::String; -use egui::{pos2, vec2, Align, PointerButton, Rect, Response, Sense, WidgetInfo, WidgetType}; -use epaint::{Color32, TextStyle}; +use egui::{ + pos2, vec2, Align, PointerButton, Rect, Response, Sense, TextStyle, WidgetInfo, WidgetType, +}; +use epaint::Color32; /// Where to place the plot legend. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -26,7 +28,7 @@ impl Corner { } /// The configuration for a plot legend. -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, PartialEq)] pub struct Legend { pub text_style: TextStyle, pub background_alpha: f32, @@ -89,9 +91,15 @@ impl LegendEntry { hovered, } = self; - let galley = - ui.fonts() - .layout_delayed_color(text, ui.style().body_text_style, f32::INFINITY); + let galley = ui.fonts().layout_delayed_color( + text, + ui.style() + .text_styles + .get(&TextStyle::Body) + .unwrap() + .clone(), + f32::INFINITY, + ); let icon_size = galley.size().y; let icon_spacing = icon_size / 5.0; diff --git a/amdguid/src/widgets/legend_widget.rs b/amdguid/src/widgets/legend_widget.rs index a85472e..6f3258f 100644 --- a/amdguid/src/widgets/legend_widget.rs +++ b/amdguid/src/widgets/legend_widget.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; -use egui::{vec2, Align, Direction, Frame, Layout, Rect, Response, Ui, Widget}; +use egui::style::Margin; +use egui::{Align, Direction, Frame, Layout, Rect, Response, Ui, Widget}; use epaint::ahash::AHashSet; use epaint::Color32; @@ -15,8 +16,8 @@ pub struct LegendWidget { } impl LegendWidget { - /// Create a new legend from items, the names of items that are hidden and the style of the - /// text. Returns `None` if the legend has no entries. + /// Create a new legend from items, the names of items that are hidden and + /// the style of the text. Returns `None` if the legend has no entries. pub fn try_new( rect: Rect, config: Legend, @@ -89,10 +90,11 @@ impl Widget for &mut LegendWidget { let mut legend_ui = ui.child_ui(legend_rect, layout); legend_ui .scope(|ui| { - ui.style_mut().body_text_style = config.text_style; + // ui.style_mut().body_text_style = config.text_style; let background_frame = Frame { - margin: vec2(8.0, 4.0), - corner_radius: ui.style().visuals.window_corner_radius, + inner_margin: Margin::symmetric(8.0, 4.0), + outer_margin: Default::default(), + rounding: ui.style().visuals.window_rounding, shadow: epaint::Shadow::default(), fill: ui.style().visuals.extreme_bg_color, stroke: ui.style().visuals.window_stroke(), diff --git a/amdguid/src/widgets/mod.rs b/amdguid/src/widgets/mod.rs index 9405256..78a6343 100644 --- a/amdguid/src/widgets/mod.rs +++ b/amdguid/src/widgets/mod.rs @@ -5,6 +5,8 @@ pub mod drag_plot; pub mod drag_plot_prepared; pub mod legend; pub mod legend_widget; +pub mod output_widget; +pub mod outputs_settings; pub mod reload_section; pub use change_fan_settings::*; diff --git a/amdguid/src/widgets/output_widget.rs b/amdguid/src/widgets/output_widget.rs new file mode 100644 index 0000000..e74ed72 --- /dev/null +++ b/amdguid/src/widgets/output_widget.rs @@ -0,0 +1,69 @@ +use std::collections::HashMap; + +use amdgpu::pidfile::ports::Output; +use egui::{Response, Sense, Ui, Vec2}; +use epaint::Stroke; + +pub struct OutputWidget<'output, 'textures> { + output: &'output Output, + textures: &'textures HashMap, +} + +impl<'output, 'textures> OutputWidget<'output, 'textures> { + pub fn new( + output: &'output Output, + textures: &'textures HashMap, + ) -> Self { + Self { output, textures } + } +} + +impl<'output, 'textures> egui::Widget for OutputWidget<'output, 'textures> { + fn ui(self, ui: &mut Ui) -> Response { + let (rect, res) = ui.allocate_exact_size(Vec2::new(80.0, 70.0), Sense::click()); + // let _transform = ScreenTransform::new(rect, Bounds::new_symmetrical(1.0), + // false, false); let _frame = *transform.frame(); + // eprintln!("min {:?} max {:?}", frame.min, frame.max); + let painter = ui.painter(); //.sub_region(*transform.frame()); + + painter.rect_filled(rect, 0.0, epaint::color::Color32::DARK_RED); + painter.rect(rect, 2.0, epaint::color::Color32::DARK_RED, { + let mut s = Stroke::default(); + s.color = epaint::color::Color32::GREEN; + s.width = 1.0; + s + }); + + let rect_middle_point = (rect.max - rect.min) / 2.0; + + painter.circle_filled( + rect.min + Vec2::new(rect_middle_point.x / 2.0, rect_middle_point.y), + 3.0, + epaint::color::Color32::GREEN, + ); + painter.circle_filled( + rect.min + rect_middle_point, + 3.0, + epaint::color::Color32::GREEN, + ); + + painter.circle_filled( + rect.min + + Vec2::new( + rect_middle_point.x + (rect_middle_point.x / 2.0), + rect_middle_point.y, + ), + 3.0, + epaint::color::Color32::GREEN, + ); + res + } +} + +fn icon(name: &str, textures: &HashMap) { + if let Some(_texture) = textures.get(name) { + // + } else { + // + } +} diff --git a/amdguid/src/widgets/outputs_settings.rs b/amdguid/src/widgets/outputs_settings.rs new file mode 100644 index 0000000..46d8d8c --- /dev/null +++ b/amdguid/src/widgets/outputs_settings.rs @@ -0,0 +1,86 @@ +use std::collections::{BTreeMap, HashMap}; + +use amdgpu::pidfile::ports::{Output, Status}; +use egui::Ui; +use epaint::ColorImage; +use image::ImageFormat; + +use crate::app::StatefulConfig; +use crate::widgets::output_widget::OutputWidget; + +#[derive(Default)] +pub struct OutputsSettings { + textures: HashMap, +} + +impl OutputsSettings { + pub fn draw( + &mut self, + ui: &mut Ui, + _state: &mut StatefulConfig, + outputs: &BTreeMap>, + ) { + outputs.values().flatten().for_each(|output| { + // 160x160 + let image = { + let bytes = include_bytes!("../../assets/icons/ports.jpg"); + image::load_from_memory(bytes).unwrap() + }; + + for (_idx, _pixel, _p) in image.to_rgba8().enumerate_pixels() { + // let bytes = pixel.; + // eprintln!("{:?}", bytes); + } + + if !self.textures.contains_key(&output.port_type) { + let img = image::load_from_memory_with_format( + include_bytes!("../../assets/icons/ports.jpg"), + ImageFormat::Jpeg, + ) + .unwrap(); + let image_buffer = img.to_rgba8(); + let size = [image.width() as _, image.height() as _]; + let pixels = image_buffer.as_flat_samples(); + let _ = ui.ctx().load_texture( + output.port_type.clone(), + ColorImage::from_rgba_unmultiplied(size, pixels.as_slice()), + ); + } + }); + let _available = ui.available_rect_before_wrap(); + + ui.vertical(|ui| { + ui.horizontal_top(|ui| { + outputs.iter().for_each(|(name, outputs)| { + ui.vertical(|ui| { + ui.label(format!("name {name}")); + ui.horizontal_top(|ui| { + outputs.iter().for_each(|output| { + ui.vertical(|ui| { + ui.add(OutputWidget::new(output, &self.textures)); + + ui.label(format!("port_number {}", output.port_number)); + ui.label(format!("port_type {}", output.port_type)); + ui.label(format!("card {}", output.card)); + ui.label(format!( + "port_name {}", + output.port_name.as_deref().unwrap_or_default() + )); + ui.label(match output.status { + Status::Connected => "Connected", + Status::Disconnected => "Disconnected", + }); + }); + }); + }); + }); + }); + }); + // eprintln!("=============================================================="); + }); + } +} + +fn vga_port_icon() { + // Texture +} diff --git a/amdguid/src/widgets/reload_section.rs b/amdguid/src/widgets/reload_section.rs index 3d353da..24124c8 100644 --- a/amdguid/src/widgets/reload_section.rs +++ b/amdguid/src/widgets/reload_section.rs @@ -1,7 +1,7 @@ -use crate::app::{ChangeState, FanServices}; -use amdgpu::helper_cmd::Command; +use amdgpu::pidfile::helper_cmd::Command; use egui::{PointerButton, Response, Sense, Ui}; -use epaint::Color32; + +use crate::app::{ChangeState, FanServices}; pub struct ReloadSection<'l> { pub services: &'l mut FanServices, @@ -18,7 +18,7 @@ impl<'l> egui::Widget for ReloadSection<'l> { if ui.button("Reload").clicked_by(PointerButton::Primary) { service.reload = ChangeState::Reloading; - match amdgpu::helper_cmd::send_command(Command::ReloadConfig { + match amdgpu::pidfile::helper_cmd::send_command(Command::ReloadConfig { pid: service.pid, }) { Ok(response) => { @@ -37,12 +37,13 @@ impl<'l> egui::Widget for ReloadSection<'l> { ui.label("Reloading..."); } ChangeState::Success => { - ui.add(egui::Label::new("Reloaded").text_color(Color32::DARK_GREEN)); + ui.add( + egui::Label::new("Reloaded"), /* .text_color(Color32::DARK_GREEN) */ + ); } ChangeState::Failure(msg) => { ui.add( - egui::Label::new(format!("Failure. {}", msg)) - .text_color(Color32::RED), + egui::Label::new(format!("Failure. {}", msg)), // .text_color(Color32::RED), ); } } diff --git a/amdmond-lib/src/lib.rs b/amdmond-lib/src/lib.rs index 35d626e..b814e8e 100644 --- a/amdmond-lib/src/lib.rs +++ b/amdmond-lib/src/lib.rs @@ -1,6 +1,5 @@ pub mod errors; -use crate::errors::AmdMonError; use amdgpu::hw_mon::HwMon; use amdgpu::utils::load_temp_inputs; use amdgpu::{ @@ -8,6 +7,8 @@ use amdgpu::{ }; use amdgpu_config::fan; +use crate::errors::AmdMonError; + pub type Result = std::result::Result; pub struct AmdMon { diff --git a/amdmond/src/main.rs b/amdmond/src/main.rs index bbc80e6..9cfe5c2 100644 --- a/amdmond/src/main.rs +++ b/amdmond/src/main.rs @@ -2,11 +2,11 @@ mod command; mod log_file; mod watch; +use amdgpu::utils::ensure_config_dir; +use amdgpu_config::monitor::{load_config, Config, DEFAULT_MONITOR_CONFIG_PATH}; use gumdrop::Options; use crate::command::Command; -use amdgpu::utils::ensure_config_dir; -use amdgpu_config::monitor::{load_config, Config, DEFAULT_MONITOR_CONFIG_PATH}; #[derive(gumdrop::Options)] pub struct Opts { diff --git a/amdportsd/src/main.rs b/amdportsd/src/main.rs index b8b0a09..a8769ba 100644 --- a/amdportsd/src/main.rs +++ b/amdportsd/src/main.rs @@ -1,13 +1,12 @@ -use amdgpu::ports::{sock_file, Command, Response}; -use amdgpu::{ports::*, IoFailure}; use std::fs::{DirEntry, Permissions}; -use std::io::{Read, Write}; -use std::net::Shutdown; use std::os::unix::fs::PermissionsExt; use std::os::unix::net::{UnixListener, UnixStream}; use std::sync::{Arc, Mutex}; use std::time::Duration; +use amdgpu::pidfile::ports::{sock_file, Command, Response, *}; +use amdgpu::IoFailure; + fn parse_output(entry: DirEntry) -> Option { let ty = entry.file_type().ok()?; if ty.is_dir() { @@ -60,45 +59,7 @@ async fn read_outputs(state: Arc>>) { } } -pub struct Service(UnixStream); - -impl Service { - /// Serialize and send command - pub fn write_response(&mut self, res: Response) { - match ron::to_string(&res) { - Ok(buffer) => match self.0.write_all(buffer.as_bytes()) { - Ok(_) => { - log::info!("Response successfully written") - } - Err(e) => log::warn!("Failed to write response. {:?}", e), - }, - Err(e) => { - log::warn!("Failed to serialize response {:?}. {:?}", res, e) - } - } - } - - /// Read from `.sock` file new line separated commands - pub fn read_command(&mut self) -> Option { - let mut command = String::with_capacity(100); - log::info!("Reading stream..."); - read_line(&mut self.0, &mut command); - if command.is_empty() { - return None; - } - Some(command) - } - - /// Close connection with no operation response - pub fn kill(mut self) { - self.write_response(Response::NoOp); - self.close(); - } - - pub fn close(self) { - let _ = self.0.shutdown(Shutdown::Both); - } -} +pub type Service = amdgpu::pidfile::Service; async fn service(state: Arc>>) { let sock_path = sock_file(); @@ -121,27 +82,8 @@ async fn service(state: Arc>>) { } } -fn read_line(stream: &mut UnixStream, command: &mut String) { - let mut buffer = [0]; - while stream.read_exact(&mut buffer).is_ok() { - if buffer[0] == b'\n' { - break; - } - match std::str::from_utf8(&buffer) { - Ok(s) => { - command.push_str(s); - } - Err(e) => { - log::error!("Failed to read from client. {:?}", e); - let _ = stream.shutdown(Shutdown::Both); - continue; - } - } - } -} - fn handle_connection(stream: UnixStream, state: Arc>>) { - let mut service = Service(stream); + let mut service = Service::new(stream); let command = match service.read_command() { Some(s) => s, diff --git a/amdvold/src/main.rs b/amdvold/src/main.rs index db1a7e4..d4de5b2 100644 --- a/amdvold/src/main.rs +++ b/amdvold/src/main.rs @@ -1,7 +1,6 @@ -use gumdrop::Options; - use amdgpu::utils::ensure_config_dir; use amdgpu_config::voltage::{load_config, Config}; +use gumdrop::Options; use crate::command::VoltageCommand; use crate::error::VoltageError; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..9413ba7 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +imports_granularity = "Module" +group_imports = "StdExternalCrate" +reorder_modules = true +reorder_imports = true +use_field_init_shorthand = true +wrap_comments = true +edition = "2021"