diff --git a/.github/workflows/build-packages.yaml b/.github/workflows/build-packages.yaml
new file mode 100644
index 00000000..e422a7bf
--- /dev/null
+++ b/.github/workflows/build-packages.yaml
@@ -0,0 +1,60 @@
+name: Build packages
+
+on:
+ push:
+ branches: ['v2', 'master']
+
+jobs:
+ build-packages:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Install pkger
+ run: |
+ curl -L -o /tmp/pkger.deb https://github.com/vv9k/pkger/releases/download/0.11.0/pkger-0.11.0-0.amd64.deb
+ sudo apt -y install /tmp/pkger.deb
+
+ - name: Build packages
+ run: pkger -c .pkger.yml build lact
+
+ - name: Copy release files
+ run: |
+ OUT_DIR=$PWD/release-artifacts
+ mkdir -p $OUT_DIR
+
+ pushd pkg/output
+ for DISTRO in $(ls); do
+ cd $DISTRO
+ rm -f *.src.rpm
+
+ for FILE in $(ls); do
+ NAME="${FILE%.*}"
+ EXT="${FILE##*.}"
+
+ OUT_NAME="$OUT_DIR/$NAME.$DISTRO.$EXT"
+ cp $FILE $OUT_NAME
+ done
+ cd ..
+ done
+ popd
+
+ - name: Create release
+ uses: ncipollo/release-action@v1.12.0
+ with:
+ removeArtifacts: true
+ allowUpdates: true
+ artifactErrorsFailBuild: true
+ artifacts: "release-artifacts/*"
+ body: ${{ github.event.head_commit.message }}
+ prerelease: true
+ name: Test release
+ tag: test-build
+
+ - name: Update test-build tag
+ run: |
+ git tag -f test-build
+ git push -f origin test-build
+ shell: bash
+
diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml
index f366bc34..09230880 100644
--- a/.github/workflows/rust.yml
+++ b/.github/workflows/rust.yml
@@ -11,22 +11,23 @@ env:
jobs:
build-test:
- runs-on: ubuntu-20.04
+ if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }}
+ runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Update repos
run: sudo apt update
- name: Install dependencies
- run: sudo apt install libgtk-3-dev libvulkan-dev
+ run: sudo apt install libgtk-4-dev pkg-config libvulkan-dev
- name: Build
run: cargo build
- name: Run tests
- run: cargo test --verbose
+ run: cargo test --verbose --no-default-features
check-format:
- runs-on: ubuntu-20.04
-
+ runs-on: ubuntu-22.04
+ if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }}
steps:
- uses: actions/checkout@v2
- name: install rustfmt
diff --git a/.gitignore b/.gitignore
index 40c3a7b2..caf39b11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,8 @@
/target
+AppDir/
*.glade\~
+*.AppImage
+*.AppImage.zsync
+appimage-build/
+*.stignore
+pkg/output
diff --git a/.pkger.yml b/.pkger.yml
new file mode 100644
index 00000000..04fcaced
--- /dev/null
+++ b/.pkger.yml
@@ -0,0 +1,17 @@
+---
+recipes_dir: pkg/recipes
+output_dir: pkg/output
+images_dir: pkg/images
+log_dir: ~
+runtime_uri: ~
+gpg_key: ~
+gpg_name: ~
+ssh: ~
+images:
+ - name: debian-12
+ target: deb
+ - name: fedora-37
+ target: rpm
+ - name: ubuntu-2204
+ target: deb
+custom_simple_images: ~
diff --git a/.vscode/launch.json b/.vscode/launch.json
deleted file mode 100644
index eb007c82..00000000
--- a/.vscode/launch.json
+++ /dev/null
@@ -1,138 +0,0 @@
-{
- // Use IntelliSense to learn about possible attributes.
- // Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
- "version": "0.2.0",
- "configurations": [
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug unit tests in library 'daemon'",
- "cargo": {
- "args": [
- "test",
- "--no-run",
- "--lib",
- "--package=daemon"
- ],
- "filter": {
- "name": "daemon",
- "kind": "lib"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug executable 'daemon'",
- "cargo": {
- "args": [
- "build",
- "--bin=daemon",
- "--package=daemon"
- ],
- "filter": {
- "name": "daemon",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug unit tests in executable 'daemon'",
- "cargo": {
- "args": [
- "test",
- "--no-run",
- "--bin=daemon",
- "--package=daemon"
- ],
- "filter": {
- "name": "daemon",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug executable 'cli'",
- "cargo": {
- "args": [
- "build",
- "--bin=cli",
- "--package=cli"
- ],
- "filter": {
- "name": "cli",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug unit tests in executable 'cli'",
- "cargo": {
- "args": [
- "test",
- "--no-run",
- "--bin=cli",
- "--package=cli"
- ],
- "filter": {
- "name": "cli",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug executable 'gui'",
- "cargo": {
- "args": [
- "build",
- "--bin=gui",
- "--package=gui"
- ],
- "filter": {
- "name": "gui",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- },
- {
- "type": "lldb",
- "request": "launch",
- "name": "Debug unit tests in executable 'gui'",
- "cargo": {
- "args": [
- "test",
- "--no-run",
- "--bin=gui",
- "--package=gui"
- ],
- "filter": {
- "name": "gui",
- "kind": "bin"
- }
- },
- "args": [],
- "cwd": "${workspaceFolder}"
- }
- ]
-}
\ No newline at end of file
diff --git a/API.md b/API.md
new file mode 100644
index 00000000..69366ddf
--- /dev/null
+++ b/API.md
@@ -0,0 +1,42 @@
+# Description
+
+The LACT Daemon exposes a JSON API over a unix socket, available on `/var/run/lactd.sock`. You can configure who has access to the socket in `/etc/lact/config.yaml` in the `daemon.admin_groups` field.
+
+The API expects newline-separated JSON objects, and returns a JSON object for every request.
+
+The general format of requests looks like:
+```
+{"command": "command_name", "args": {}}
+```
+Note that the type of `args` depends on the specific request, and may be ommited in some cases.
+
+The response looks like this:
+```
+{"status": "ok|error", "data": {}}
+```
+Same as `args` in requests, `data` can be of a different type and may not be present depending on the specific request.
+
+You can try sending commands to socket interactively with `ncat`:
+```
+echo '{"command": "list_devices"}' | ncat -U /run/lactd.sock
+```
+Example response:
+```
+{"status":"ok","data":[{"id":"1002:687F-1043:0555-0000:0b:00.0","name":"Vega 10 XL/XT [Radeon RX Vega 56/64]"}]}
+```
+
+# Commands
+
+For the full list of available commands and responses, you can look at the source code of the schema: [requests](lact-schema/src/request.rs), [the basic response structure](lact-schema/src/response.rs) and [all possible types](lact-schema/src/lib.rs).
+
+It should also be fairly easy to figure out the API by trial and error, as the error message are quite verbose:
+
+```
+echo '{"command": "test"}' | ncat -U /run/lactd.sock
+
+{"status":"error","data":"Failed to deserialize request: unknown variant `test`, expected one of `ping`, `list_devices`, `system_info`, `device_info`, `device_stats`, `device_clocks_info`, `set_fan_control`, `set_power_cap`, `set_performance_level`, `set_clocks_value` at line 1 column 18"}
+```
+
+# Rust
+
+If you want to connect to the socket from a Rust program, you can simply import either the `lact-client` or `lact-schema` (if you want to write a custom client) crates from this repository.
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 9b19b9c9..7e5c75de 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,91 +3,57 @@
version = 3
[[package]]
-name = "adler"
-version = "1.0.2"
+name = "ahash"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+dependencies = [
+ "cfg-if",
+ "getrandom",
+ "once_cell",
+ "version_check",
+]
[[package]]
name = "aho-corasick"
-version = "0.7.18"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
-name = "ansi_term"
-version = "0.12.1"
+name = "amdgpu-sysfs"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+checksum = "182b6991fe3b8ac1e0fc4ab6eed0e79740cb6363877283c5a42f02e164737c92"
dependencies = [
- "winapi",
+ "enum_dispatch",
+ "serde",
]
[[package]]
name = "anyhow"
-version = "1.0.62"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1485d4d2cc45e7b201ee3767015c96faa5904387c9d87c6efdd0fb511f12d305"
+checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]]
name = "ash"
-version = "0.33.3+1.2.191"
+version = "0.37.2+1.3.238"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc4f1d82f164f838ae413296d1131aa6fa79b917d25bebaa7033d25620c09219"
+checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03"
dependencies = [
"libloading",
]
-[[package]]
-name = "atk"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a83b21d2aa75e464db56225e1bda2dd5993311ba1095acaa8fa03d1ae67026ba"
-dependencies = [
- "atk-sys",
- "bitflags",
- "glib",
- "libc",
-]
-
-[[package]]
-name = "atk-sys"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "badcf670157c84bb8b1cf6b5f70b650fed78da2033c9eed84c4e49b11cbe83ea"
-dependencies = [
- "glib-sys",
- "gobject-sys",
- "libc",
- "system-deps",
-]
-
-[[package]]
-name = "atty"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
-dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
-]
-
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-[[package]]
-name = "base64"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
-
[[package]]
name = "bincode"
version = "1.3.3"
@@ -104,35 +70,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
-name = "bumpalo"
-version = "3.12.0"
+name = "bytemuck"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
+checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "bytes"
-version = "1.2.1"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
+checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cairo-rs"
-version = "0.14.9"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33b5725979db0c586d98abad2193cdb612dd40ef95cd26bd99851bf93b3cb482"
+checksum = "a8af54f5d48af1226928adc1f57edd22f5df1349e7da1fc96ae15cf43db0e871"
dependencies = [
"bitflags",
"cairo-sys-rs",
"glib",
"libc",
+ "once_cell",
"thiserror",
]
[[package]]
name = "cairo-sys-rs"
-version = "0.14.9"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b448b876970834fda82ba3aeaccadbd760206b75388fc5c1b02f1e343b697570"
+checksum = "f55382a01d30e5e53f185eee269124f5e21ab526595b872751278dfbb463594e"
dependencies = [
"glib-sys",
"libc",
@@ -141,15 +122,15 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.73"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-expr"
-version = "0.8.1"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e"
+checksum = "b0357a6402b295ca3a86bc148e84df46c02e41f41fef186bda662557ef6328aa"
dependencies = [
"smallvec",
]
@@ -160,47 +141,41 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-[[package]]
-name = "chunked_transfer"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
-
[[package]]
name = "clap"
-version = "2.34.0"
+version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [
- "ansi_term",
- "atty",
"bitflags",
+ "clap_derive",
+ "clap_lex",
+ "is-terminal",
+ "once_cell",
"strsim",
- "textwrap",
- "unicode-width",
- "vec_map",
+ "termcolor",
]
[[package]]
-name = "cli"
-version = "0.1.0"
+name = "clap_derive"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
- "colored",
- "daemon",
- "env_logger 0.8.4",
- "log",
- "structopt",
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
-name = "colored"
-version = "2.0.0"
+name = "clap_lex"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
+checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
dependencies = [
- "atty",
- "lazy_static",
- "winapi",
+ "os_str_bytes",
]
[[package]]
@@ -220,19 +195,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
-name = "crc32fast"
-version = "1.3.2"
+name = "core-graphics-types"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
- "cfg-if",
+ "bitflags",
+ "core-foundation",
+ "foreign-types",
+ "libc",
]
[[package]]
name = "crossbeam-queue"
-version = "0.3.6"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
+checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add"
dependencies = [
"cfg-if",
"crossbeam-utils",
@@ -240,99 +218,111 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.11"
+version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
- "once_cell",
]
[[package]]
-name = "daemon"
-version = "0.1.0"
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "ctor"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
- "bincode",
- "env_logger 0.9.0",
- "log",
- "nix",
- "pciid-parser",
- "rand",
- "reqwest",
- "serde",
- "serde_json",
- "signal-hook",
- "vulkano",
+ "quote",
+ "syn",
]
[[package]]
-name = "either"
-version = "1.8.0"
+name = "darling"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
+checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
[[package]]
-name = "encoding_rs"
-version = "0.8.31"
+name = "darling_core"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
+checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [
- "cfg-if",
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
]
[[package]]
-name = "env_logger"
-version = "0.8.4"
+name = "darling_macro"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
+checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
+ "darling_core",
+ "quote",
+ "syn",
]
[[package]]
-name = "env_logger"
-version = "0.9.0"
+name = "diff"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
+
+[[package]]
+name = "enum_dispatch"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
+checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2"
dependencies = [
- "atty",
- "humantime",
- "log",
- "regex",
- "termcolor",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
-name = "fastrand"
-version = "1.8.0"
+name = "errno"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
- "instant",
+ "errno-dragonfly",
+ "libc",
+ "winapi",
]
[[package]]
-name = "field-offset"
-version = "0.3.4"
+name = "errno-dragonfly"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
- "memoffset",
- "rustc_version",
+ "cc",
+ "libc",
]
[[package]]
-name = "flate2"
-version = "1.0.24"
+name = "field-offset"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
dependencies = [
- "crc32fast",
- "miniz_oxide",
+ "memoffset 0.6.5",
+ "rustc_version",
]
[[package]]
@@ -357,35 +347,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
-name = "form_urlencoded"
-version = "1.0.1"
+name = "futures"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
+checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
dependencies = [
- "matches",
- "percent-encoding",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
]
[[package]]
name = "futures-channel"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050"
+checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
dependencies = [
"futures-core",
+ "futures-sink",
]
[[package]]
name = "futures-core"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf"
+checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
[[package]]
name = "futures-executor"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab"
+checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
dependencies = [
"futures-core",
"futures-task",
@@ -394,30 +389,44 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.24"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68"
+checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "futures-sink"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56"
+checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
[[package]]
name = "futures-task"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1"
+checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
[[package]]
name = "futures-util"
-version = "0.3.24"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90"
+checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
dependencies = [
+ "futures-channel",
"futures-core",
"futures-io",
+ "futures-macro",
+ "futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
@@ -425,39 +434,25 @@ dependencies = [
"slab",
]
-[[package]]
-name = "gdk"
-version = "0.14.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d749dcfc00d8de0d7c3a289e04a04293eb5ba3d8a4e64d64911d481fa9933b"
-dependencies = [
- "bitflags",
- "cairo-rs",
- "gdk-pixbuf",
- "gdk-sys",
- "gio",
- "glib",
- "libc",
- "pango",
-]
-
[[package]]
name = "gdk-pixbuf"
-version = "0.14.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534192cb8f01daeb8fab2c8d4baa8f9aae5b7a39130525779f5c2608e235b10f"
+checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf"
dependencies = [
+ "bitflags",
"gdk-pixbuf-sys",
"gio",
"glib",
"libc",
+ "once_cell",
]
[[package]]
name = "gdk-pixbuf-sys"
-version = "0.14.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f097c0704201fbc8f69c1762dc58c6947c8bb188b8ed0bc7e65259f1894fe590"
+checksum = "7b41bd2b44ed49d99277d3925652a163038bd5ed943ec9809338ffb2f4391e3b"
dependencies = [
"gio-sys",
"glib-sys",
@@ -467,10 +462,26 @@ dependencies = [
]
[[package]]
-name = "gdk-sys"
-version = "0.14.0"
+name = "gdk4"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5042053ee765aeef08d9d7e3f0f1e36a4d37f1659b3f93ad3d6997515dbb64a"
+dependencies = [
+ "bitflags",
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk4-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk4-sys"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e091b3d3d6696949ac3b3fb3c62090e5bfd7bd6850bef5c3c5ea701de1b1f1e"
+checksum = "14f0fb00507af1e9299681dd09965f720e2b5ea95536d49a5681e8994ef10c7a"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
@@ -485,9 +496,9 @@ dependencies = [
[[package]]
name = "getrandom"
-version = "0.2.7"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
+checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
@@ -496,26 +507,29 @@ dependencies = [
[[package]]
name = "gio"
-version = "0.14.8"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711c3632b3ebd095578a9c091418d10fed492da9443f58ebc8f45efbeb215cb0"
+checksum = "65acfc24267314eee46f49e0a531e08fd6c3025040d1cfb4a7cd8e41c5e06116"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-io",
+ "futures-util",
"gio-sys",
"glib",
"libc",
"once_cell",
+ "pin-project-lite",
+ "smallvec",
"thiserror",
]
[[package]]
name = "gio-sys"
-version = "0.14.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa"
+checksum = "b5d3076ecb86c8c3a672c9843d6232b3a344fb81d304d0ba1ac64b23343efa46"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -526,28 +540,32 @@ dependencies = [
[[package]]
name = "glib"
-version = "0.14.8"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4"
+checksum = "a78b6a0901e258cb03c761ca94c84d519427ede489cae12cd5ba0d7d584e69e9"
dependencies = [
"bitflags",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
+ "futures-util",
+ "gio-sys",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
+ "memchr",
"once_cell",
"smallvec",
+ "thiserror",
]
[[package]]
name = "glib-macros"
-version = "0.14.1"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518"
+checksum = "55e93d79ed130f0f0b58bc0aa29fb0e40c9dfd63997fec51f8adf780d1520bc4"
dependencies = [
"anyhow",
"heck",
@@ -560,9 +578,9 @@ dependencies = [
[[package]]
name = "glib-sys"
-version = "0.14.0"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae"
+checksum = "72a0985cf568e18cf63b443c9a14f4bdaa947fed7437476000dba84926a20b25"
dependencies = [
"libc",
"system-deps",
@@ -570,9 +588,9 @@ dependencies = [
[[package]]
name = "gobject-sys"
-version = "0.14.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5"
+checksum = "9a0155d388840c77d61b033b66ef4f9bc7f4133d83df83572d6b4fb234a3be7d"
dependencies = [
"glib-sys",
"libc",
@@ -580,54 +598,90 @@ dependencies = [
]
[[package]]
-name = "gtk"
-version = "0.14.3"
+name = "graphene-rs"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21cf11565bb0e4dfc2f99d4775b6c329f0d40a2cff9c0066214d31a0e1b46256"
+dependencies = [
+ "glib",
+ "graphene-sys",
+ "libc",
+]
+
+[[package]]
+name = "graphene-sys"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf80a4849a8d9565410a8fec6fc3678e9c617f4ac7be182ca55ab75016e07af9"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gsk4"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb51122dd3317e9327ec1e4faa151d1fa0d95664cd8fb8dcfacf4d4d29ac70c"
+checksum = "2fa9cd285a72a95124b65c069a9cb1b8fb8e310be71783404c39fccf3bf7774c"
dependencies = [
- "atk",
"bitflags",
"cairo-rs",
- "field-offset",
- "futures-channel",
- "gdk",
- "gdk-pixbuf",
- "gio",
+ "gdk4",
"glib",
- "gtk-sys",
- "gtk3-macros",
+ "graphene-rs",
+ "gsk4-sys",
"libc",
- "once_cell",
"pango",
- "pkg-config",
]
[[package]]
-name = "gtk-sys"
-version = "0.14.0"
+name = "gsk4-sys"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c14c8d3da0545785a7c5a120345b3abb534010fb8ae0f2ef3f47c027fba303e"
+checksum = "5a445ae1e50cbf181a1d5c61b920a7e7e8657b96e0ecdbbf8911a86fad462a32"
dependencies = [
- "atk-sys",
"cairo-sys-rs",
- "gdk-pixbuf-sys",
- "gdk-sys",
- "gio-sys",
+ "gdk4-sys",
"glib-sys",
"gobject-sys",
+ "graphene-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
-name = "gtk3-macros"
-version = "0.14.0"
+name = "gtk4"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e47dca53cb1a8ae3006e869b5711ae7370180db537f6d98e3bcaf23fabfd911f"
+dependencies = [
+ "bitflags",
+ "cairo-rs",
+ "field-offset",
+ "futures-channel",
+ "gdk-pixbuf",
+ "gdk4",
+ "gio",
+ "glib",
+ "graphene-rs",
+ "gsk4",
+ "gtk4-macros",
+ "gtk4-sys",
+ "libc",
+ "once_cell",
+ "pango",
+]
+
+[[package]]
+name = "gtk4-macros"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21de1da96dc117443fb03c2e270b2d34b7de98d0a79a19bbb689476173745b79"
+checksum = "db4676c4f90d8b010e88cb4558f61f47d76d6f6b8e6f6b89e62640f443907f61"
dependencies = [
"anyhow",
- "heck",
"proc-macro-crate",
"proc-macro-error",
"proc-macro2",
@@ -636,42 +690,33 @@ dependencies = [
]
[[package]]
-name = "gui"
-version = "0.1.0"
+name = "gtk4-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65463dc801460e498d5e7ffa6e9ae2cfbed7d05fabd1ca5a8d024adbc89eeda6"
dependencies = [
- "daemon",
- "env_logger 0.9.0",
- "glib",
- "gtk",
- "log",
- "pango",
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "gsk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
]
[[package]]
-name = "h2"
-version = "0.3.14"
+name = "half"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca32592cf21ac7ccab1825cd87f6c9b3d9022c44d086172ed0966bec8af30be"
+checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
+ "crunchy",
]
-[[package]]
-name = "half"
-version = "1.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
-
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -680,157 +725,136 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
-version = "0.3.3"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
-dependencies = [
- "unicode-segmentation",
-]
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
-version = "0.1.19"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
-name = "http"
-version = "0.2.8"
+name = "ident_case"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
-name = "http-body"
-version = "0.4.5"
+name = "indexmap"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
+ "autocfg",
+ "hashbrown",
+ "serde",
]
[[package]]
-name = "httparse"
-version = "1.7.1"
+name = "io-lifetimes"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"
-
-[[package]]
-name = "httpdate"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
-name = "hyper"
-version = "0.14.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac"
+checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
+ "libc",
+ "windows-sys 0.45.0",
]
[[package]]
-name = "hyper-tls"
-version = "0.5.0"
+name = "is-terminal"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
dependencies = [
- "bytes",
- "hyper",
- "native-tls",
- "tokio",
- "tokio-native-tls",
+ "hermit-abi",
+ "io-lifetimes",
+ "rustix",
+ "windows-sys 0.45.0",
]
[[package]]
-name = "idna"
-version = "0.2.3"
+name = "itoa"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
-dependencies = [
- "matches",
- "unicode-bidi",
- "unicode-normalization",
-]
+checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
-name = "indexmap"
-version = "1.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+name = "lact"
+version = "0.2.0"
dependencies = [
- "autocfg",
- "hashbrown",
+ "anyhow",
+ "clap",
+ "lact-cli",
+ "lact-daemon",
+ "lact-gui",
]
[[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+name = "lact-cli"
+version = "0.2.0"
dependencies = [
- "cfg-if",
+ "anyhow",
+ "clap",
+ "lact-client",
]
[[package]]
-name = "ipnet"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
+name = "lact-client"
+version = "0.2.0"
+dependencies = [
+ "anyhow",
+ "lact-schema",
+ "nix",
+ "serde",
+ "serde_json",
+ "tracing",
+]
[[package]]
-name = "itertools"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
+name = "lact-daemon"
+version = "0.2.0"
dependencies = [
- "either",
+ "amdgpu-sysfs",
+ "anyhow",
+ "bincode",
+ "futures",
+ "lact-schema",
+ "nix",
+ "pciid-parser",
+ "serde",
+ "serde_json",
+ "serde_with",
+ "serde_yaml",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "vulkano",
]
[[package]]
-name = "itoa"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
+name = "lact-gui"
+version = "0.2.0"
+dependencies = [
+ "anyhow",
+ "gtk4",
+ "lact-client",
+ "lact-daemon",
+ "once_cell",
+ "pretty_assertions",
+ "tracing",
+ "tracing-subscriber",
+]
[[package]]
-name = "js-sys"
-version = "0.3.59"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2"
+name = "lact-schema"
+version = "0.2.0"
dependencies = [
- "wasm-bindgen",
+ "amdgpu-sysfs",
+ "indexmap",
+ "serde",
+ "serde_json",
]
[[package]]
@@ -841,25 +865,31 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.132"
+version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "libloading"
-version = "0.7.3"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
+[[package]]
+name = "linux-raw-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
+
[[package]]
name = "lock_api"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
@@ -875,10 +905,22 @@ dependencies = [
]
[[package]]
-name = "matches"
-version = "0.1.9"
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata",
+]
[[package]]
name = "memchr"
@@ -896,131 +938,103 @@ dependencies = [
]
[[package]]
-name = "mime"
-version = "0.3.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.5.3"
+name = "memoffset"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
+checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
- "adler",
+ "autocfg",
]
[[package]]
name = "mio"
-version = "0.8.4"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
+checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
dependencies = [
"libc",
"log",
"wasi",
- "windows-sys 0.36.1",
-]
-
-[[package]]
-name = "native-tls"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
+ "windows-sys 0.45.0",
]
[[package]]
name = "nix"
-version = "0.23.1"
+version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
+checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
dependencies = [
"bitflags",
- "cc",
"cfg-if",
"libc",
- "memoffset",
+ "memoffset 0.7.1",
+ "pin-utils",
+ "static_assertions",
]
[[package]]
-name = "num_cpus"
-version = "1.13.1"
+name = "nom8"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
+checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
dependencies = [
- "hermit-abi",
- "libc",
+ "memchr",
]
[[package]]
-name = "once_cell"
-version = "1.13.1"
+name = "nu-ansi-term"
+version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
[[package]]
-name = "openssl"
-version = "0.10.41"
+name = "objc"
+version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
- "bitflags",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
+ "malloc_buf",
]
[[package]]
-name = "openssl-macros"
-version = "0.1.0"
+name = "once_cell"
+version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
-name = "openssl-probe"
-version = "0.1.5"
+name = "os_str_bytes"
+version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
-name = "openssl-sys"
-version = "0.9.75"
+name = "output_vt100"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
+checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [
- "autocfg",
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
+ "winapi",
]
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
[[package]]
name = "pango"
-version = "0.14.8"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "546fd59801e5ca735af82839007edd226fe7d3bb06433ec48072be4439c28581"
+checksum = "243c048be90312220fb3bd578176eed8290568274a93c95040289d39349384bc"
dependencies = [
"bitflags",
+ "gio",
"glib",
"libc",
"once_cell",
@@ -1029,9 +1043,9 @@ dependencies = [
[[package]]
name = "pango-sys"
-version = "0.14.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2367099ca5e761546ba1d501955079f097caa186bb53ce0f718dca99ac1942fe"
+checksum = "4293d0f0b5525eb5c24734d30b0ed02cd02aa734f216883f376b54de49625de8"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -1041,50 +1055,42 @@ dependencies = [
[[package]]
name = "parking_lot"
-version = "0.11.2"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
- "instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
-version = "0.8.5"
+version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
- "instant",
"libc",
"redox_syscall",
"smallvec",
- "winapi",
+ "windows-sys 0.45.0",
]
[[package]]
name = "pciid-parser"
-version = "0.6.0"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5057bd953dfcccbaba6326a1dc2a6f0e7ca1d7b8ceca37bee610b639ef9f4a0"
+checksum = "6e2ef5429455ae06f0c055262d540bf2c190ad51b72bb6cbe8488706c4dff440"
dependencies = [
+ "serde",
"tracing",
- "ureq",
]
-[[package]]
-name = "percent-encoding"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
-
[[package]]
name = "pest"
-version = "2.3.0"
+version = "2.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4"
+checksum = "028accff104c4e513bad663bbcd2ad7cfd5304144404c31ed0a77ac103d00660"
dependencies = [
"thiserror",
"ucd-trie",
@@ -1104,25 +1110,30 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
-version = "0.3.25"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
-name = "ppv-lite86"
-version = "0.2.16"
+name = "pretty_assertions"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
+dependencies = [
+ "ctor",
+ "diff",
+ "output_vt100",
+ "yansi",
+]
[[package]]
name = "proc-macro-crate"
-version = "1.2.1"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
+checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34"
dependencies = [
"once_cell",
- "thiserror",
- "toml",
+ "toml_edit",
]
[[package]]
@@ -1151,52 +1162,22 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.43"
+version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
+checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.21"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
[[package]]
name = "redox_syscall"
version = "0.2.16"
@@ -1208,9 +1189,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.6.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
@@ -1218,71 +1199,19 @@ dependencies = [
]
[[package]]
-name = "regex-syntax"
-version = "0.6.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
-
-[[package]]
-name = "remove_dir_all"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "reqwest"
-version = "0.11.11"
+name = "regex-automata"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
- "base64",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "lazy_static",
- "log",
- "mime",
- "native-tls",
- "percent-encoding",
- "pin-project-lite",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "tokio",
- "tokio-native-tls",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "winreg",
+ "regex-syntax",
]
[[package]]
-name = "ring"
-version = "0.16.20"
+name = "regex-syntax"
+version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
-dependencies = [
- "cc",
- "libc",
- "once_cell",
- "spin",
- "untrusted",
- "web-sys",
- "winapi",
-]
+checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustc_version"
@@ -1294,32 +1223,24 @@ dependencies = [
]
[[package]]
-name = "rustls"
-version = "0.20.6"
+name = "rustix"
+version = "0.36.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
+checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644"
dependencies = [
- "log",
- "ring",
- "sct",
- "webpki",
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.45.0",
]
[[package]]
name = "ryu"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
-
-[[package]]
-name = "schannel"
-version = "0.1.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
-dependencies = [
- "lazy_static",
- "windows-sys 0.36.1",
-]
+checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "scopeguard"
@@ -1327,39 +1248,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
-[[package]]
-name = "sct"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
-dependencies = [
- "ring",
- "untrusted",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
[[package]]
name = "semver"
version = "0.11.0"
@@ -1380,18 +1268,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.144"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
+checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.144"
+version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
+checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
@@ -1400,9 +1288,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.85"
+version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
+checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [
"itoa",
"ryu",
@@ -1410,130 +1298,100 @@ dependencies = [
]
[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
+name = "serde_with"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
"serde",
+ "serde_with_macros",
]
[[package]]
-name = "shared_library"
-version = "0.1.9"
+name = "serde_with_macros"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
+checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [
- "lazy_static",
- "libc",
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
-name = "signal-hook"
-version = "0.3.14"
+name = "serde_yaml"
+version = "0.9.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
+checksum = "8fb06d4b6cdaef0e0c51fa881acb721bed3c924cfaa71d9c94a3b771dfdf6567"
dependencies = [
- "libc",
- "signal-hook-registry",
+ "indexmap",
+ "itoa",
+ "ryu",
+ "serde",
+ "unsafe-libyaml",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
+dependencies = [
+ "lazy_static",
]
[[package]]
name = "signal-hook-registry"
-version = "1.4.0"
+version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "slab"
-version = "0.4.7"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
+checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "socket2"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10c98bba371b9b22a71a9414e420f92ddeb2369239af08200816169d5e2dd7aa"
+checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
dependencies = [
"libc",
"winapi",
]
[[package]]
-name = "spin"
-version = "0.5.2"
+name = "static_assertions"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-
-[[package]]
-name = "structopt"
-version = "0.3.26"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
-dependencies = [
- "clap",
- "lazy_static",
- "structopt-derive",
-]
-
-[[package]]
-name = "structopt-derive"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
-dependencies = [
- "heck",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "strum"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
-
-[[package]]
-name = "strum_macros"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.99"
+version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
@@ -1542,68 +1400,40 @@ dependencies = [
[[package]]
name = "system-deps"
-version = "3.2.0"
+version = "6.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6"
+checksum = "2955b1fe31e1fa2fbd1976b71cc69a606d7d4da16f6de3333d0c92d51419aeff"
dependencies = [
- "anyhow",
"cfg-expr",
"heck",
- "itertools",
"pkg-config",
- "strum",
- "strum_macros",
- "thiserror",
"toml",
"version-compare",
]
-[[package]]
-name = "tempfile"
-version = "3.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
-dependencies = [
- "cfg-if",
- "fastrand",
- "libc",
- "redox_syscall",
- "remove_dir_all",
- "winapi",
-]
-
[[package]]
name = "termcolor"
-version = "1.1.3"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
+checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
-[[package]]
-name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
[[package]]
name = "thiserror"
-version = "1.0.32"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
+checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.32"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
+checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@@ -1611,20 +1441,15 @@ dependencies = [
]
[[package]]
-name = "tinyvec"
-version = "1.6.0"
+name = "thread_local"
+version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
dependencies = [
- "tinyvec_macros",
+ "cfg-if",
+ "once_cell",
]
-[[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.25.0"
@@ -1636,56 +1461,55 @@ dependencies = [
"libc",
"memchr",
"mio",
- "num_cpus",
"pin-project-lite",
+ "signal-hook-registry",
"socket2",
+ "tokio-macros",
"windows-sys 0.42.0",
]
[[package]]
-name = "tokio-native-tls"
-version = "0.3.0"
+name = "tokio-macros"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
+checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
- "native-tls",
- "tokio",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
-name = "tokio-util"
-version = "0.7.3"
+name = "toml"
+version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
+ "serde",
]
[[package]]
-name = "toml"
-version = "0.5.9"
+name = "toml_datetime"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
-dependencies = [
- "serde",
-]
+checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5"
[[package]]
-name = "tower-service"
-version = "0.3.2"
+name = "toml_edit"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b"
+dependencies = [
+ "indexmap",
+ "nom8",
+ "toml_datetime",
+]
[[package]]
name = "tracing"
-version = "0.1.36"
+version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
@@ -1695,9 +1519,9 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.22"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2"
+checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
@@ -1706,110 +1530,72 @@ dependencies = [
[[package]]
name = "tracing-core"
-version = "0.1.29"
+version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
+ "valuable",
]
[[package]]
-name = "try-lock"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
-
-[[package]]
-name = "ucd-trie"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c"
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.3"
+name = "tracing-log"
+version = "0.1.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"
+checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
- "tinyvec",
+ "lazy_static",
+ "log",
+ "tracing-core",
]
[[package]]
-name = "unicode-segmentation"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
-
-[[package]]
-name = "untrusted"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
-
-[[package]]
-name = "ureq"
-version = "2.5.0"
+name = "tracing-subscriber"
+version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97acb4c28a254fd7a4aeec976c46a7fa404eac4d7c134b30c75144846d7cb8f"
+checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
dependencies = [
- "base64",
- "chunked_transfer",
- "flate2",
- "log",
+ "matchers",
+ "nu-ansi-term",
"once_cell",
- "rustls",
- "url",
- "webpki",
- "webpki-roots",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
]
[[package]]
-name = "url"
-version = "2.2.2"
+name = "ucd-trie"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
-dependencies = [
- "form_urlencoded",
- "idna",
- "matches",
- "percent-encoding",
-]
+checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
-name = "vcpkg"
-version = "0.2.15"
+name = "unsafe-libyaml"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2"
[[package]]
-name = "vec_map"
-version = "0.8.2"
+name = "valuable"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version-compare"
-version = "0.0.11"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b"
+checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
[[package]]
name = "version_check"
@@ -1819,147 +1605,57 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vk-parse"
-version = "0.6.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c1538fa783f47fb5a6eb495f024f426599a4fe66ff3773ff2252156c64d350a"
+checksum = "4c6a0bda9bbe6b9e50e6456c80aa8fe4cca3b21e4311a1130c41e4915ec2e32a"
dependencies = [
"xml-rs",
]
[[package]]
name = "vulkano"
-version = "0.26.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e0c9cc7471d065c6066b2a0daaae4232a100fdb6f0aad2a4b12652a2bd8ede0"
+version = "0.32.0"
+source = "git+https://github.com/vulkano-rs/vulkano#6994ce613e2e23ae216ec2c7956dff2f8f0ee208"
dependencies = [
+ "ahash",
"ash",
+ "bytemuck",
+ "core-graphics-types",
"crossbeam-queue",
- "fnv",
"half",
"heck",
"indexmap",
- "lazy_static",
+ "libloading",
+ "objc",
+ "once_cell",
"parking_lot",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_json",
- "shared_library",
"smallvec",
+ "thread_local",
"vk-parse",
+ "vulkano-macros",
]
[[package]]
-name = "want"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
-dependencies = [
- "log",
- "try-lock",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d"
-dependencies = [
- "cfg-if",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f"
-dependencies = [
- "bumpalo",
- "log",
- "once_cell",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da"
+name = "vulkano-macros"
+version = "0.32.0"
+source = "git+https://github.com/vulkano-rs/vulkano#6994ce613e2e23ae216ec2c7956dff2f8f0ee208"
dependencies = [
+ "proc-macro-crate",
"proc-macro2",
"quote",
"syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.82"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a"
-
-[[package]]
-name = "web-sys"
-version = "0.3.59"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "webpki"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
-dependencies = [
- "ring",
- "untrusted",
]
[[package]]
-name = "webpki-roots"
-version = "0.22.4"
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
-dependencies = [
- "webpki",
-]
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
@@ -1994,30 +1690,41 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
name = "windows-sys"
-version = "0.42.0"
+version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
"windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.1",
+ "windows_x86_64_msvc",
]
[[package]]
@@ -2026,48 +1733,24 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
-
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
-[[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
-
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
-[[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
-
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
@@ -2080,29 +1763,20 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
-[[package]]
-name = "winreg"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
-dependencies = [
- "winapi",
-]
-
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
+
+[[package]]
+name = "yansi"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
diff --git a/Cargo.toml b/Cargo.toml
index 83b3b4c2..75cf7cf8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,2 +1,3 @@
[workspace]
-members = ["daemon", "cli", "gui"]
\ No newline at end of file
+resolver = "2"
+members = ["lact*"]
diff --git a/LICENSE b/LICENSE
index c566f68c..9ae4d0b3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021 ilyazzz
+Copyright (c) 2023 Ilya Zlobintsev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..8ed10dbf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+export CARGO_TARGET_DIR ?= ./target
+DESTDIR ?= /usr/local
+
+build-release:
+ cargo build --release
+
+install:
+ install -Dm755 target/release/lact ${DESTDIR}/bin/lact
+ install -Dm755 res/lactd.service ${DESTDIR}/lib/systemd/system/lactd.service
+ install -Dm755 res/io.github.lact-linux.desktop ${DESTDIR}/share/applications/io.github.lact-linux.desktop
+ install -Dm755 res/io.github.lact-linux.png ${DESTDIR}/share/pixmaps/io.github.lact-linux.png
+
+uninstall:
+ rm ${DESTDIR}/bin/lact
+ rm ${DESTDIR}/lib/systemd/system/lactd.service
+ rm ${DESTDIR}/share/applications/io.github.lact-linux.desktop
+ rm ${DESTDIR}/share/pixmaps/io.github.lact-linux.png
diff --git a/README.md b/README.md
index a96f321b..263c8011 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,12 @@
# Linux AMDGPU Control Application
+
+
This application allows you to control your AMD GPU on a Linux system.
-| | | |
+| GPU info | Overclocking | Fan control |
|----------------------------------------------|----------------------------------------------|---------------------------------------------|
-|![Screenshot](https://i.imgur.com/crEN4az.png)|![Screenshot](https://i.imgur.com/x7fTKpT.png)|![Screenshot](https://i.imgur.com/idAER4B.png)
-
+|![image](https://user-images.githubusercontent.com/22796665/221357224-21163f94-1afd-4bb8-96bd-24f9ce1816ce.png)|![image](https://user-images.githubusercontent.com/22796665/221357297-9c03bcb5-0742-459b-bffb-9e75c93df25b.png)|![image](https://user-images.githubusercontent.com/22796665/221357332-6d26a65f-d522-4b04-86a8-c9820b334416.png)
Current features:
@@ -15,25 +16,37 @@ Current features:
- Basic overclocking
Currently missing:
-- Voltage control on Vega20+ GPUs
- Precise clock/voltage curve manipulation (currently can only set the maximum values)
-- Multi-GPU system support *Should work now*
# Installation
- Arch Linux: Install the [AUR Package](https://aur.archlinux.org/packages/lact/) (or the -git version)
-- Debian/Ubuntu/Pop_OS: Download a .deb from [releases](https://github.com/ilyazzz/LACT/releases/). Warning: it has not been tested heavily
-- Otherwise, build from source:
+- Debian/Ubuntu/Derevatives: Download a .deb from [releases](https://github.com/ilya-zlobintsev/LACT/releases/).
+
+ It is only available on Debian 12+ and Ubuntu 22.04+ as older versions don't ship gtk4.
+- Fedora: an rpm is available in [releases](https://github.com/ilya-zlobintsev/LACT/releases/).
+- Otherwise, build from source.
+
+**Why is there no AppImage/Flatpak/other universal format?**
+See [here](./pkg/README.md).
+# Configuration
+
+There is a configuration file available in `/etc/lact/config.yaml`. Most of the settings are accessible through the GUI, but some of them may be useful to be edited manually (like `admin_groups` to specify who has access to the daemon)
# Building from source
-- Install dependencies:
- - Ubuntu/Debian: `sudo apt install cargo rustc libvulkan-dev git libgtk-3-dev make`
- - Fedora: `sudo dnf install git gtk3-devel rust cargo vulkan-headers perl-core`
-- `git clone https://github.com/ilyazzz/LACT && cd LACT`
-- `./deploy.sh`
+Dependencies:
+- rust
+- gtk4
+- pkg-config
+- make
+- hwdata
+Steps:
+- `git clone https://github.com/ilya-zlobintsev/LACT && cd LACT`
+- `make`
+- `sudo make install`
# Usage
@@ -41,65 +54,48 @@ Enable and start the service (otherwise you won't be able to change any settings
```
sudo systemctl enable --now lactd
```
-You can now use the application.
+You can now use the GUI to change settings and view information.
+
+# API
+There is an API available over a unix socket. See [here](API.md) for more information.
# CLI
There is also a cli available.
-- Getting basic information:
+- List system GPUs:
- `lact-cli info`
+ `lact cli list-gpus`
Example output:
```
- GPU Model: Radeon RX 570 Pulse 4GB
- GPU Vendor: Advanced Micro Devices, Inc. [AMD/ATI]
- Driver in use: amdgpu
- VBIOS Version: 113-1E3871U-O4C
- VRAM Size: 4096
- Link Speed: 8.0 GT/s PCIe
+ 1002:687F-1043:0555-0000:0b:00.0 (Vega 10 XL/XT [Radeon RX Vega 56/64])
```
-- Getting current GPU stats:
+- Getting GPU information:
- `lact-cli metrics`
+ `lact cli info`
Example output:
```
- VRAM Usage: 545/4096MiB
- Temperature: 46°C
- Fan Speed: 785/3200RPM
- GPU Clock: 783MHz
- GPU Voltage: 0.975V
- VRAM Clock: 1750MHz
- Power Usage: 38/155W
+ lact cli info
+ GPU Vendor: Advanced Micro Devices, Inc. [AMD/ATI]
+ GPU Model: Vega 10 XL/XT [Radeon RX Vega 56/64]
+ Driver in use: amdgpu
+ VBIOS version: 115-D050PIL-100
+ Link: LinkInfo { current_width: Some("16"), current_speed: Some("8.0 GT/s PCIe"), max_width: Some("16"), max_speed: Some("8.0 GT/s PCIe") }
```
-- Showing the current fan curve:
-
- `lact-cli curve status`
-
- Example output:
-
- ```
- Fan curve:
- 20C°: 0%
- 40C°: 0%
- 60C°: 50%
- 80C°: 88%
- 100C°: 100%
- ```
+The functionality of the CLI is quite limited. If you want to integrate LACT with some application/script, you should use the [API](API.md) instead.
# Reporting issues
- When reporting issues, please include your system info and GPU model.
+When reporting issues, please include your system info and GPU model.
- If there's a crash, run `lact-gui` from the command line to get logs, or use `journalctl -u lactd` to see if the daemon crashed.
+If there's a crash, run `lact gui` from the command line to get logs, or use `journalctl -u lactd` to see if the daemon crashed.
- If there's an issue with GPU model identification please report it [here](https://github.com/ilyazzz/pci-id-parser/), include your GPU model and the output of `cat /sys/class/drm/card*/device/uevent`.
# Alternatives
-If LACT doesn't end up working for you, make sure to check out [CoreCtrl](https://gitlab.com/corectrl/corectrl).
+If LACT doesn't do what you want, make sure to check out [CoreCtrl](https://gitlab.com/corectrl/corectrl).
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
deleted file mode 100644
index 541e0448..00000000
--- a/cli/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "cli"
-version = "0.1.0"
-authors = ["Ilya Zlobintsev "]
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-daemon = { path = "../daemon" }
-structopt = "0.3"
-log = "0.4"
-env_logger = "0.8"
-colored = "2"
\ No newline at end of file
diff --git a/cli/src/main.rs b/cli/src/main.rs
deleted file mode 100644
index 1c1ffd76..00000000
--- a/cli/src/main.rs
+++ /dev/null
@@ -1,236 +0,0 @@
-use colored::*;
-use daemon::daemon_connection::DaemonConnection;
-use structopt::StructOpt;
-
-#[derive(StructOpt)]
-enum ConfigOpt {
- Show,
- AllowOnlineUpdating,
- DisallowOnlineUpdating,
-}
-
-#[derive(StructOpt)]
-enum CurveOpt {
- /// Shows current fan control information
- Status {
- /// Specify a GPU ID as printed in `lact-cli gpus`. By default, all GPUs are printed.
- gpu_id: Option,
- },
-}
-
-#[derive(StructOpt)]
-#[structopt(rename_all = "lower")]
-enum Opt {
- /// Realtime GPU information
- Metrics {
- /// Specify a GPU ID as printed in `lact-cli gpus`. By default, all GPUs are printed.
- gpu_id: Option,
- },
- /// Get GPU list
- Gpus,
- /// General information about the GPU
- Info {
- /// Specify a GPU ID as printed in `lact-cli gpus`. By default, all GPUs are printed.
- gpu_id: Option,
- },
- Config(ConfigOpt),
- /// Fan curve control
- Curve(CurveOpt),
-}
-
-fn main() {
- env_logger::init();
-
- let opt = Opt::from_args();
-
- let d = DaemonConnection::new().unwrap();
- log::trace!("connection established");
-
- match opt {
- Opt::Gpus => {
- let gpus = d.get_gpus();
- println!("{:?}", gpus);
- }
- Opt::Metrics { gpu_id } => {
- let mut gpu_ids: Vec = Vec::new();
-
- if let Some(gpu_id) = gpu_id {
- gpu_ids.push(gpu_id);
- } else {
- for (gpu_id, _) in d.get_gpus().unwrap() {
- gpu_ids.push(gpu_id);
- }
- }
-
- for gpu_id in gpu_ids {
- print_stats(&d, gpu_id);
- }
- }
- Opt::Info { gpu_id } => {
- let mut gpu_ids: Vec = Vec::new();
-
- if let Some(gpu_id) = gpu_id {
- gpu_ids.push(gpu_id);
- } else {
- for (gpu_id, _) in d.get_gpus().unwrap() {
- gpu_ids.push(gpu_id);
- }
- }
-
- for gpu_id in gpu_ids {
- print_info(&d, gpu_id);
- }
- }
- Opt::Curve(curve) => match curve {
- CurveOpt::Status { gpu_id } => {
- let mut gpu_ids: Vec = Vec::new();
-
- if let Some(gpu_id) = gpu_id {
- gpu_ids.push(gpu_id);
- } else {
- for (gpu_id, _) in d.get_gpus().unwrap() {
- gpu_ids.push(gpu_id);
- }
- }
-
- for gpu_id in gpu_ids {
- print_fan_curve(&d, gpu_id);
- }
- }
- },
- Opt::Config(config_opt) => match config_opt {
- ConfigOpt::Show => print_config(&d),
- ConfigOpt::AllowOnlineUpdating => enable_online_update(&d),
- ConfigOpt::DisallowOnlineUpdating => disable_online_update(&d),
- },
- }
-}
-
-fn disable_online_update(d: &DaemonConnection) {
- let mut config = d.get_config().unwrap();
- config.allow_online_update = Some(false);
- d.set_config(config).unwrap();
-}
-
-fn enable_online_update(d: &DaemonConnection) {
- let mut config = d.get_config().unwrap();
- config.allow_online_update = Some(true);
- d.set_config(config).unwrap();
-}
-
-fn print_config(d: &DaemonConnection) {
- let config = d.get_config().unwrap();
-
- println!(
- "{} {:?}",
- "Online PCI DB updating:".purple(),
- config.allow_online_update
- );
-}
-
-fn print_fan_curve(d: &DaemonConnection, gpu_id: u32) {
- let fan_control = d.get_fan_control(gpu_id).unwrap();
-
- if fan_control.enabled {
- println!("{}", "Fan curve:".yellow());
-
- for (temp, fan_speed) in fan_control.curve {
- println!(
- "{}{}: {}{}",
- temp.to_string().yellow(),
- "C°".yellow(),
- fan_speed.round().to_string().bold(),
- "%".bold()
- );
- }
- } else {
- println!("{}", "Automatic fan control used".yellow());
- }
-}
-
-fn print_info(d: &DaemonConnection, gpu_id: u32) {
- let gpu_info = d.get_gpu_info(gpu_id).unwrap();
- println!(
- "{} {}",
- "GPU Model:".blue(),
- gpu_info.vendor_data.card_model.unwrap_or_default().bold()
- );
- println!(
- "{} {}",
- "GPU Vendor:".blue(),
- gpu_info.vendor_data.gpu_vendor.unwrap_or_default().bold()
- );
- println!("{} {}", "Driver in use:".blue(), gpu_info.driver.bold());
- println!(
- "{} {}",
- "VBIOS Version:".blue(),
- gpu_info.vbios_version.bold()
- );
- println!(
- "{} {}",
- "VRAM Size:".blue(),
- gpu_info.vram_size.to_string().bold()
- );
- println!("{} {}", "Link Speed:".blue(), gpu_info.link_speed.bold());
-}
-
-fn print_stats(d: &DaemonConnection, gpu_id: u32) {
- let gpu_stats = d.get_gpu_stats(gpu_id).unwrap();
- println!(
- "{} {}/{}{}",
- "VRAM Usage:".green(),
- gpu_stats.mem_used.unwrap_or_default().to_string().bold(),
- gpu_stats.mem_total.unwrap_or_default().to_string().bold(),
- "MiB".bold(),
- );
- println!(
- "{} {}{}",
- "Temperature:".green(),
- gpu_stats
- .temperatures
- .get("edge")
- .unwrap()
- .current
- .to_string()
- .bold(),
- "°C".bold(),
- );
- println!(
- "{} {}/{}{}",
- "Fan Speed:".green(),
- gpu_stats.fan_speed.unwrap_or_default().to_string().bold(),
- gpu_stats
- .max_fan_speed
- .unwrap_or_default()
- .to_string()
- .bold(),
- "RPM".bold(),
- );
- println!(
- "{} {}{}",
- "GPU Clock:".green(),
- gpu_stats.gpu_freq.unwrap_or_default().to_string().bold(),
- "MHz".bold(),
- );
- println!(
- "{} {}{}",
- "GPU Voltage:".green(),
- (gpu_stats.voltage.unwrap_or_default() as f64 / 1000.0)
- .to_string()
- .bold(),
- "V".bold(),
- );
- println!(
- "{} {}{}",
- "VRAM Clock:".green(),
- gpu_stats.mem_freq.unwrap_or_default().to_string().bold(),
- "MHz".bold(),
- );
- println!(
- "{} {}/{}{}",
- "Power Usage:".green(),
- gpu_stats.power_avg.unwrap_or_default().to_string().bold(),
- gpu_stats.power_cap.unwrap_or_default().to_string().bold(),
- "W".bold(),
- );
-}
diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml
deleted file mode 100644
index eb8c3ee9..00000000
--- a/daemon/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "daemon"
-version = "0.1.0"
-authors = ["Ilya Zlobintsev "]
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bincode = "1.3"
-serde = { version = "1.0", features = ["derive", "rc"] }
-serde_json = "1.0"
-vulkano = "0.26"
-log = "0.4"
-env_logger = "0.9"
-rand = "0.8"
-signal-hook = "0.3"
-reqwest = { version = "0.11", features = ["blocking", "json"] }
-nix = "0.23"
-pciid-parser = { version = "0.6.0", features = ["online"] }
diff --git a/daemon/src/config.rs b/daemon/src/config.rs
deleted file mode 100644
index 73a30e6e..00000000
--- a/daemon/src/config.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::collections::{BTreeMap, HashMap};
-use std::fs;
-use std::io;
-use std::path::PathBuf;
-
-use crate::gpu_controller::PowerProfile;
-
-#[derive(Debug)]
-pub enum ConfigError {
- IoError(io::Error),
- ParseError(serde_json::Error),
-}
-
-impl From for ConfigError {
- fn from(error: io::Error) -> Self {
- ConfigError::IoError(error)
- }
-}
-
-impl From for ConfigError {
- fn from(error: serde_json::Error) -> Self {
- ConfigError::ParseError(error)
- }
-}
-
-#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq)]
-pub struct GpuIdentifier {
- pub pci_id: String,
- pub card_model: Option,
- pub gpu_model: Option,
- pub path: PathBuf,
-}
-
-impl PartialEq for GpuIdentifier {
- fn eq(&self, other: &Self) -> bool {
- self.pci_id == other.pci_id
- && self.gpu_model == other.gpu_model
- && self.card_model == other.card_model
- }
-}
-
-#[derive(Serialize, Deserialize, Clone, Debug)]
-pub struct GpuConfig {
- pub fan_control_enabled: bool,
- pub fan_curve: BTreeMap,
- pub power_cap: i64,
- pub power_profile: PowerProfile,
- pub gpu_max_clock: i64,
- pub gpu_max_voltage: Option,
- pub vram_max_clock: i64,
-}
-
-impl GpuConfig {
- pub fn new() -> Self {
- let mut fan_curve: BTreeMap = BTreeMap::new();
- fan_curve.insert(20, 0f64);
- fan_curve.insert(40, 0f64);
- fan_curve.insert(60, 50f64);
- fan_curve.insert(80, 80f64);
- fan_curve.insert(100, 100f64);
-
- GpuConfig {
- fan_curve,
- fan_control_enabled: false,
- power_cap: -1,
- power_profile: PowerProfile::Auto,
- gpu_max_clock: 0,
- gpu_max_voltage: None,
- vram_max_clock: 0,
- }
- }
-}
-
-#[derive(Serialize, Deserialize, Clone, Debug)]
-pub struct Config {
- pub gpu_configs: HashMap,
- pub allow_online_update: Option,
- pub config_path: PathBuf,
- pub group: String,
-}
-
-impl Config {
- pub fn new(config_path: &PathBuf) -> Self {
- let gpu_configs: HashMap = HashMap::new();
-
- Config {
- gpu_configs,
- allow_online_update: None,
- config_path: config_path.clone(),
- group: String::from("wheel"),
- }
- }
-
- pub fn read_from_file(path: &PathBuf) -> Result {
- let json = fs::read_to_string(path)?;
-
- Ok(serde_json::from_str::(&json)?)
- }
-
- pub fn save(&self) -> Result<(), ConfigError> {
- let json = serde_json::to_string_pretty(self)?;
- log::info!("saving {}", json.to_string());
-
- Ok(fs::write(&self.config_path, &json.to_string())?)
- }
-}
-
-/*#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn write_config() -> Result<(), ConfigError> {
- let c = Config::new();
- c.save(PathBuf::from("/tmp/config.json"))
- }
-}*/
diff --git a/daemon/src/daemon_connection.rs b/daemon/src/daemon_connection.rs
deleted file mode 100644
index 2955c10c..00000000
--- a/daemon/src/daemon_connection.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use crate::config::Config;
-use crate::gpu_controller::{FanControlInfo, GpuStats};
-use crate::gpu_controller::{GpuInfo, PowerProfile};
-use crate::Daemon;
-use crate::DaemonError;
-use crate::{Action, DaemonResponse, SOCK_PATH};
-use std::collections::{BTreeMap, HashMap};
-
-#[derive(Clone, Copy)]
-pub struct DaemonConnection {}
-
-pub const BUFFER_SIZE: usize = 4096;
-
-impl DaemonConnection {
- pub fn new() -> Result {
- let addr = nix::sys::socket::SockAddr::Unix(
- nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
- );
- let socket = nix::sys::socket::socket(
- nix::sys::socket::AddressFamily::Unix,
- nix::sys::socket::SockType::Stream,
- nix::sys::socket::SockFlag::empty(),
- None,
- )
- .expect("Creating socket failed");
- nix::sys::socket::connect(socket, &addr).expect("Socket connect failed");
-
- nix::unistd::write(socket, &bincode::serialize(&Action::CheckAlive).unwrap())
- .expect("Writing check alive to socket failed");
-
- nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
- .expect("Could not shut down");
-
- let mut buffer = Vec::::new();
- buffer.resize(BUFFER_SIZE, 0);
- loop {
- match nix::unistd::read(socket, &mut buffer) {
- Ok(0) => {
- break;
- }
- Ok(n) => {
- assert!(n < buffer.len());
- if n < buffer.len() {
- buffer.resize(n, 0);
- }
- break;
- }
- Err(e) => {
- panic!("Error reading from socket: {}", e);
- }
- }
- }
- nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Both)
- .expect("Could not shut down");
-
- nix::unistd::close(socket).expect("Failed to close");
-
- let result: Result =
- bincode::deserialize(&buffer).expect("failed to deserialize message");
-
- match result {
- Ok(_) => Ok(DaemonConnection {}),
- Err(_) => Err(DaemonError::ConnectionFailed),
- }
- }
-
- fn send_action(&self, action: Action) -> Result {
- let addr = nix::sys::socket::SockAddr::Unix(
- nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
- );
- let socket = nix::sys::socket::socket(
- nix::sys::socket::AddressFamily::Unix,
- nix::sys::socket::SockType::Stream,
- nix::sys::socket::SockFlag::empty(),
- None,
- )
- .expect("Socket failed");
- nix::sys::socket::connect(socket, &addr).expect("connect failed");
-
- let b = bincode::serialize(&action).unwrap();
- nix::unistd::write(socket, &b).expect("Writing action to socket failed");
-
- nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Write)
- .expect("Could not shut down");
-
- let buffer = Daemon::read_buffer(socket);
-
- nix::sys::socket::shutdown(socket, nix::sys::socket::Shutdown::Both)
- .expect("Failed to shut down");
-
- nix::unistd::close(socket).expect("Failed to close");
-
- bincode::deserialize(&buffer).expect("failed to deserialize message")
- }
-
- pub fn get_gpu_stats(&self, gpu_id: u32) -> Result {
- match self.send_action(Action::GetStats(gpu_id))? {
- DaemonResponse::GpuStats(stats) => Ok(stats),
- _ => unreachable!(),
- }
- }
-
- pub fn get_gpu_info(&self, gpu_id: u32) -> Result {
- match self.send_action(Action::GetInfo(gpu_id))? {
- DaemonResponse::GpuInfo(info) => Ok(info),
- _ => unreachable!("impossible enum variant"),
- }
- }
-
- pub fn start_fan_control(&self, gpu_id: u32) -> Result<(), DaemonError> {
- match self.send_action(Action::StartFanControl(gpu_id))? {
- DaemonResponse::OK => Ok(()),
- _ => Err(DaemonError::HWMonError),
- }
- }
-
- pub fn stop_fan_control(&self, gpu_id: u32) -> Result<(), DaemonError> {
- match self.send_action(Action::StopFanControl(gpu_id))? {
- DaemonResponse::OK => Ok(()),
- _ => Err(DaemonError::HWMonError),
- }
- }
-
- pub fn get_fan_control(&self, gpu_id: u32) -> Result {
- match self.send_action(Action::GetFanControl(gpu_id))? {
- DaemonResponse::FanControlInfo(info) => Ok(info),
- _ => unreachable!(),
- }
- }
-
- pub fn set_fan_curve(&self, gpu_id: u32, curve: BTreeMap) -> Result<(), DaemonError> {
- match self.send_action(Action::SetFanCurve(gpu_id, curve))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn set_power_cap(&self, gpu_id: u32, cap: i64) -> Result<(), DaemonError> {
- match self.send_action(Action::SetPowerCap(gpu_id, cap))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn set_power_profile(&self, gpu_id: u32, profile: PowerProfile) -> Result<(), DaemonError> {
- match self.send_action(Action::SetPowerProfile(gpu_id, profile))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- /*pub fn set_gpu_power_state(&self, gpu_id: u32, num: u32, clockspeed: i64, voltage: Option) -> Result<(), DaemonError> {
- match self.send_action(Action::SetGPUPowerState(gpu_id, num, clockspeed, voltage))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }*/
-
- pub fn set_gpu_max_power_state(
- &self,
- gpu_id: u32,
- clockspeed: i64,
- voltage: Option,
- ) -> Result<(), DaemonError> {
- match self.send_action(Action::SetGPUMaxPowerState(gpu_id, clockspeed, voltage))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn set_vram_max_clock(&self, gpu_id: u32, clockspeed: i64) -> Result<(), DaemonError> {
- match self.send_action(Action::SetVRAMMaxClock(gpu_id, clockspeed))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn commit_gpu_power_states(&self, gpu_id: u32) -> Result<(), DaemonError> {
- match self.send_action(Action::CommitGPUPowerStates(gpu_id))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn reset_gpu_power_states(&self, gpu_id: u32) -> Result<(), DaemonError> {
- match self.send_action(Action::ResetGPUPowerStates(gpu_id))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-
- pub fn get_gpus(&self) -> Result>, DaemonError> {
- match self.send_action(Action::GetGpus)? {
- DaemonResponse::Gpus(gpus) => Ok(gpus),
- _ => unreachable!(),
- }
- }
-
- pub fn shutdown(&self) {
- let addr = nix::sys::socket::SockAddr::Unix(
- nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
- );
- let socket = nix::sys::socket::socket(
- nix::sys::socket::AddressFamily::Unix,
- nix::sys::socket::SockType::Stream,
- nix::sys::socket::SockFlag::empty(),
- None,
- )
- .expect("Socket failed");
- nix::sys::socket::connect(socket, &addr).expect("connect failed");
- nix::unistd::write(socket, &mut &bincode::serialize(&Action::Shutdown).unwrap())
- .expect("Writing shutdown to socket failed");
- }
-
- pub fn get_config(&self) -> Result {
- match self.send_action(Action::GetConfig)? {
- DaemonResponse::Config(config) => Ok(config),
- _ => unreachable!(),
- }
- }
-
- pub fn set_config(&self, config: Config) -> Result<(), DaemonError> {
- match self.send_action(Action::SetConfig(config))? {
- DaemonResponse::OK => Ok(()),
- _ => unreachable!(),
- }
- }
-}
diff --git a/daemon/src/gpu_controller.rs b/daemon/src/gpu_controller.rs
deleted file mode 100644
index 518bdf16..00000000
--- a/daemon/src/gpu_controller.rs
+++ /dev/null
@@ -1,1120 +0,0 @@
-use crate::{
- config::{GpuConfig, GpuIdentifier},
- hw_mon::{HWMon, HWMonError, Temperature},
-};
-use pciid_parser::{schema::DeviceInfo, Database};
-use serde::{Deserialize, Serialize};
-use std::collections::{BTreeMap, HashMap};
-use std::fs;
-use std::num::ParseIntError;
-use std::path::PathBuf;
-use vulkano::device::physical::PhysicalDevice;
-use vulkano::instance::{Instance, InstanceExtensions};
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum GpuControllerError {
- NotSupported,
- PermissionDenied,
- UnknownError,
- ParseError(String),
-}
-
-impl From for GpuControllerError {
- fn from(err: std::io::Error) -> GpuControllerError {
- match err.kind() {
- std::io::ErrorKind::PermissionDenied => GpuControllerError::PermissionDenied,
- std::io::ErrorKind::NotFound => GpuControllerError::NotSupported,
- _ => GpuControllerError::UnknownError,
- }
- }
-}
-
-impl From for GpuControllerError {
- fn from(err: ParseIntError) -> GpuControllerError {
- GpuControllerError::ParseError(err.to_string())
- }
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub enum PowerProfile {
- Auto,
- Low,
- High,
-}
-
-impl Default for PowerProfile {
- fn default() -> Self {
- PowerProfile::Auto
- }
-}
-
-impl PowerProfile {
- pub fn from_str(profile: &str) -> Result {
- match profile {
- "auto" | "Automatic" => Ok(PowerProfile::Auto),
- "high" | "Highest Clocks" => Ok(PowerProfile::High),
- "low" | "Lowest Clocks" => Ok(PowerProfile::Low),
- _ => Err(GpuControllerError::ParseError(
- "unrecognized GPU power profile".to_string(),
- )),
- }
- }
-
- pub fn to_string(&self) -> String {
- match self {
- PowerProfile::Auto => "auto".to_string(),
- PowerProfile::High => "high".to_string(),
- PowerProfile::Low => "low".to_string(),
- }
- }
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub enum ClocksTable {
- Old(ClocksTableOld),
- New(ClocksTableNew),
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct ClocksTableOld {
- pub gpu_power_levels: BTreeMap, //
- pub mem_power_levels: BTreeMap,
- pub gpu_clocks_range: (i64, i64),
- pub mem_clocks_range: (i64, i64),
- pub voltage_range: (i64, i64), //IN MILLIVOLTS
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct ClocksTableNew {
- pub current_gpu_clocks: (i64, i64),
- pub current_max_mem_clock: i64,
- // pub vddc_curve: [(i64, i64); 3],
- pub gpu_clocks_range: (i64, i64),
- pub mem_clocks_range: (i64, i64),
- // pub voltage_range: (i64, i64), //IN MILLIVOLTS
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct GpuStats {
- pub mem_used: Option,
- pub mem_total: Option,
- pub mem_freq: Option,
- pub gpu_freq: Option,
- pub temperatures: HashMap,
- pub power_avg: Option,
- pub power_cap: Option,
- pub power_cap_max: Option,
- pub fan_speed: Option,
- pub max_fan_speed: Option,
- pub voltage: Option,
- pub gpu_usage: Option,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct FanControlInfo {
- pub enabled: bool,
- pub curve: BTreeMap,
-}
-#[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct VulkanInfo {
- pub device_name: String,
- pub api_version: String,
- pub features: HashMap,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct GpuInfo {
- pub vendor_data: VendorData,
- pub model_id: String,
- pub vendor_id: String,
- pub driver: String,
- pub vbios_version: String,
- pub vram_size: u64, //in MiB
- pub link_speed: String,
- pub link_width: u8,
- pub vulkan_info: VulkanInfo,
- pub pci_slot: String,
- pub power_profile: Option,
- pub clocks_table: Option,
- pub power_cap: Option,
- pub power_cap_max: Option,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, Default)]
-pub struct VendorData {
- pub gpu_vendor: Option,
- pub gpu_model: Option,
- pub card_vendor: Option,
- pub card_model: Option,
-}
-
-impl From> for VendorData {
- fn from(info: DeviceInfo) -> Self {
- Self {
- gpu_vendor: info.vendor_name.map(str::to_owned),
- gpu_model: info.device_name.map(str::to_owned),
- card_vendor: info.subvendor_name.map(str::to_owned),
- card_model: info.subdevice_name.map(str::to_owned),
- }
- }
-}
-
-#[derive(Deserialize, Serialize)]
-pub struct GpuController {
- pub hw_path: PathBuf,
- hw_mon: Option,
- gpu_info: GpuInfo,
- config: GpuConfig,
-}
-
-impl GpuController {
- pub fn new(hw_path: PathBuf, config: GpuConfig, pci_db: &Option) -> Self {
- let mut controller = GpuController {
- hw_path: hw_path.clone(),
- hw_mon: None,
- config: GpuConfig::new(),
- gpu_info: GpuInfo::default(),
- };
-
- controller.gpu_info = controller.get_info_initial(pci_db);
-
- controller.load_config(&config);
-
- controller
- }
-
- pub fn load_config(&mut self, config: &GpuConfig) {
- self.hw_mon = match fs::read_dir(self.hw_path.join("hwmon")) {
- Ok(mut path) => {
- let path = path.next().unwrap().unwrap().path();
- let hw_mon = HWMon::new(
- &path,
- config.fan_control_enabled,
- config.fan_curve.clone(),
- Some(config.power_cap),
- );
- Some(hw_mon)
- }
- _ => None,
- };
-
- #[allow(unused_must_use)]
- {
- self.set_power_profile(config.power_profile.clone());
-
- self.set_gpu_max_power_state(config.gpu_max_clock, config.gpu_max_voltage);
-
- self.set_vram_max_clockspeed(config.vram_max_clock);
-
- self.commit_gpu_power_states();
- }
- }
-
- pub fn get_config(&self) -> GpuConfig {
- self.config.clone()
- }
-
- pub fn get_identifier(&self) -> GpuIdentifier {
- let gpu_info = self.get_info();
- GpuIdentifier {
- pci_id: gpu_info.pci_slot.clone(),
- card_model: gpu_info.vendor_data.card_model.clone(),
- gpu_model: gpu_info.vendor_data.gpu_model.clone(),
- path: self.hw_path.clone(),
- }
- }
-
- pub fn get_info(&self) -> GpuInfo {
- let mut info = self.gpu_info.clone();
-
- info.power_profile = match self.get_power_profile() {
- Ok(p) => Some(p),
- Err(_) => None,
- };
-
- info.clocks_table = match self.get_clocks_table() {
- Ok(t) => Some(t),
- Err(_) => None,
- };
-
- if let Some(hw_mon) = &self.hw_mon {
- info.power_cap = hw_mon.get_power_cap();
- info.power_cap_max = hw_mon.get_power_cap_max();
- }
-
- info
- }
-
- fn get_info_initial(&self, pci_db: &Option) -> GpuInfo {
- let uevent =
- fs::read_to_string(self.hw_path.join("uevent")).expect("Failed to read uevent");
-
- let mut driver = String::new();
- let mut vendor_id = String::new();
- let mut model_id = String::new();
- let mut card_vendor_id = String::new();
- let mut card_model_id = String::new();
- let mut pci_slot = String::new();
-
- for line in uevent.split('\n') {
- let split = line.split('=').collect::>();
- match split.get(0).unwrap() {
- &"DRIVER" => driver = split.get(1).unwrap().to_string(),
- &"PCI_ID" => {
- let ids = split
- .last()
- .expect("failed to get split")
- .split(':')
- .collect::>();
- vendor_id = ids.get(0).unwrap().to_string();
- model_id = ids.get(1).unwrap().to_string();
- }
- &"PCI_SUBSYS_ID" => {
- let ids = split
- .last()
- .expect("failed to get split")
- .split(':')
- .collect::>();
- card_vendor_id = ids.get(0).unwrap().to_string();
- card_model_id = ids.get(1).unwrap().to_string();
- }
- &"PCI_SLOT_NAME" => pci_slot = split.get(1).unwrap().to_string(),
- _ => (),
- }
- }
-
- let vbios_version = match fs::read_to_string(self.hw_path.join("vbios_version")) {
- Ok(v) => v,
- Err(_) => "".to_string(),
- }
- .trim()
- .to_string();
-
- let vram_size = match fs::read_to_string(self.hw_path.join("mem_info_vram_total")) {
- Ok(a) => a.trim().parse::().unwrap() / 1024 / 1024,
- Err(_) => 0,
- };
-
- let link_speed = match fs::read_to_string(self.hw_path.join("current_link_speed")) {
- Ok(a) => a.trim().to_string(),
- Err(_) => "".to_string(),
- };
-
- let link_width = match fs::read_to_string(self.hw_path.join("current_link_width")) {
- Ok(a) => a.trim().parse::().unwrap(),
- Err(_) => 0,
- };
-
- let vulkan_info = GpuController::get_vulkan_info(&model_id);
-
- let vendor_data = match pci_db {
- Some(db) => db
- .get_device_info(&vendor_id, &model_id, &card_vendor_id, &card_model_id)
- .into(),
- None => match Database::read() {
- Ok(db) => db
- .get_device_info(&vendor_id, &model_id, &card_vendor_id, &card_model_id)
- .into(),
- Err(err) => {
- println!(
- "{:?} pci.ids not found! Make sure you have 'hwdata' installed",
- err
- );
- VendorData::default()
- }
- },
- };
-
- log::info!("Vendor data: {:?}", vendor_data);
-
- GpuInfo {
- vendor_data,
- model_id,
- vendor_id,
- driver,
- vbios_version,
- vram_size,
- link_speed,
- link_width,
- vulkan_info,
- pci_slot,
- power_profile: None,
- clocks_table: None,
- power_cap: None,
- power_cap_max: None,
- }
- }
-
- pub fn get_stats(&self) -> Result {
- let mem_total = match fs::read_to_string(self.hw_path.join("mem_info_vram_total")) {
- Ok(a) => Some(a.trim().parse::().unwrap() / 1024 / 1024),
- Err(_) => None,
- };
-
- let mem_used = match fs::read_to_string(self.hw_path.join("mem_info_vram_used")) {
- Ok(a) => Some(a.trim().parse::().unwrap() / 1024 / 1024),
- Err(_) => None,
- };
-
- let gpu_usage = match fs::read_to_string(self.hw_path.join("gpu_busy_percent")) {
- Ok(a) => Some(a.trim().parse::().unwrap()),
- Err(_) => None,
- };
-
- let (
- mem_freq,
- gpu_freq,
- temperatures,
- power_avg,
- power_cap,
- power_cap_max,
- fan_speed,
- max_fan_speed,
- voltage,
- ) = match &self.hw_mon {
- Some(hw_mon) => (
- hw_mon.get_mem_freq(),
- hw_mon.get_gpu_freq(),
- hw_mon.get_temps(),
- hw_mon.get_power_avg(),
- hw_mon.get_power_cap(),
- hw_mon.get_power_cap_max(),
- hw_mon.get_fan_speed(),
- hw_mon.get_fan_max_speed(),
- hw_mon.get_voltage(),
- ),
- None => return Err(HWMonError::NoHWMon),
- };
-
- Ok(GpuStats {
- mem_total,
- mem_used,
- mem_freq,
- gpu_freq,
- temperatures,
- power_avg,
- power_cap,
- power_cap_max,
- fan_speed,
- max_fan_speed,
- voltage,
- gpu_usage,
- })
- }
-
- pub fn start_fan_control(&mut self) -> Result<(), HWMonError> {
- match &self.hw_mon {
- Some(hw_mon) => match hw_mon.start_fan_control() {
- Ok(_) => {
- self.config.fan_control_enabled = true;
- Ok(())
- }
- Err(e) => Err(e),
- },
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- pub fn stop_fan_control(&mut self) -> Result<(), HWMonError> {
- match &self.hw_mon {
- Some(hw_mon) => match hw_mon.stop_fan_control() {
- Ok(_) => {
- self.config.fan_control_enabled = false;
- Ok(())
- }
- Err(e) => Err(e),
- },
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- pub fn get_fan_control(&self) -> Result {
- match &self.hw_mon {
- Some(hw_mon) => match hw_mon.get_fan_speed() {
- Some(_) => {
- let control = hw_mon.get_fan_control();
- Ok(FanControlInfo {
- enabled: control.0,
- curve: control.1,
- })
- }
- None => Err(HWMonError::Unsupported),
- },
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- pub fn set_fan_curve(&mut self, curve: BTreeMap) -> Result<(), HWMonError> {
- match &self.hw_mon {
- Some(hw_mon) => {
- hw_mon.set_fan_curve(curve.clone());
- self.config.fan_curve = curve;
- Ok(())
- }
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- pub fn set_power_cap(&mut self, cap: i64) -> Result<(), HWMonError> {
- match &mut self.hw_mon {
- Some(hw_mon) => {
- hw_mon.set_power_cap(cap).unwrap();
- self.config.power_cap = cap;
- Ok(())
- }
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- pub fn get_power_cap(&self) -> Result<(i64, i64), HWMonError> {
- match &self.hw_mon {
- Some(hw_mon) => {
- let min = hw_mon
- .get_power_cap()
- .ok_or_else(|| HWMonError::Unsupported)?;
- let max = hw_mon
- .get_power_cap_max()
- .ok_or_else(|| HWMonError::Unsupported)?;
-
- Ok((min, max))
- }
- None => Err(HWMonError::NoHWMon),
- }
- }
-
- fn get_power_profile(&self) -> Result {
- match fs::read_to_string(self.hw_path.join("power_dpm_force_performance_level")) {
- Ok(s) => Ok(PowerProfile::from_str(&s.trim()).unwrap()),
- Err(_) => Err(GpuControllerError::NotSupported),
- }
- }
-
- pub fn set_power_profile(&mut self, profile: PowerProfile) -> Result<(), GpuControllerError> {
- match fs::write(
- self.hw_path.join("power_dpm_force_performance_level"),
- profile.to_string(),
- ) {
- Ok(_) => {
- self.config.power_profile = profile;
- Ok(())
- }
- Err(_) => Err(GpuControllerError::NotSupported),
- }
- }
-
- fn get_clocks_table(&self) -> Result {
- match fs::read_to_string(self.hw_path.join("pp_od_clk_voltage")) {
- Ok(table) => Self::parse_clocks_table(&table),
- Err(_) => Err(GpuControllerError::NotSupported),
- }
- }
-
- fn parse_clocks_table(table: &str) -> Result {
- if table.contains("CURVE") {
- Ok(ClocksTable::New(Self::parse_clocks_table_new(table)?))
- } else {
- Ok(ClocksTable::Old(Self::parse_clocks_table_old(table)?))
- }
- }
-
- fn parse_clocks_table_old(table: &str) -> Result {
- let mut clocks_table = ClocksTableOld::default();
-
- let mut lines_iter = table.trim().split("\n").into_iter();
-
- log::trace!("Reading clocks table");
-
- while let Some(line) = lines_iter.next() {
- let line = line.trim();
- log::trace!("Parsing line {}", line);
-
- match line {
- "OD_SCLK:" | "OD_MCLK:" => {
- let is_vram = match line {
- "OD_SCLK:" => false,
- "OD_MCLK:" => true,
- _ => unreachable!(),
- };
-
- log::trace!("Parsing clock levels");
-
- // If `next()` is used on the main iterator directly, it will consume the `OD_MCLK:` aswell,
- // which means the outer loop won't recognize that the next lines are of a different clock type.
- // Thus, it is better to count how many lines were of the clock levels and then substract that amount from the main iterator.
- let mut i = 0;
- let mut lines = lines_iter.clone();
-
- while let Some(line) = lines.next() {
- let line = line.trim();
- log::trace!("Parsing power level line {}", line);
-
- // Probably shouldn't unwrap, will fail on empty lines in clocks table
- if let Some(_) = line.chars().next().unwrap().to_digit(10) {
- let (num, clock, voltage) =
- GpuController::parse_clock_voltage_line(line)?;
-
- log::trace!("Power level {}: {}MHz {}mV", num, clock, voltage);
-
- if is_vram {
- clocks_table.mem_power_levels.insert(num, (clock, voltage));
- } else {
- clocks_table.gpu_power_levels.insert(num, (clock, voltage));
- }
-
- i += 1;
- } else {
- // Probably a better way to do this
- for _ in 0..i {
- lines_iter.next().unwrap();
- }
- log::trace!("Finished reading clock levels");
- break;
- }
- }
- }
- "OD_RANGE:" => {
- log::trace!("Parsing clock and voltage ranges");
-
- while let Some(line) = lines_iter.next() {
- let mut split = line.split_whitespace();
-
- let name = split.next().ok_or_else(|| {
- GpuControllerError::ParseError("failed to get range name".to_string())
- })?;
- let min = split.next().ok_or_else(|| {
- GpuControllerError::ParseError(
- "failed to get range minimal value".to_string(),
- )
- })?;
- let max = split.next().ok_or_else(|| {
- GpuControllerError::ParseError(
- "failed to get range maximum value".to_string(),
- )
- })?;
-
- match name {
- "SCLK:" => {
- let min_clock: i64 = min.replace("MHz", "").parse()?;
- let max_clock: i64 = max.replace("MHz", "").parse()?;
-
- clocks_table.gpu_clocks_range = (min_clock, max_clock);
- }
- "MCLK:" => {
- let min_clock: i64 = min.replace("MHz", "").parse()?;
- let max_clock: i64 = max.replace("MHz", "").parse()?;
-
- clocks_table.mem_clocks_range = (min_clock, max_clock);
- }
- "VDDC:" => {
- let min_voltage: i64 = min.replace("mV", "").parse()?;
- let max_voltage: i64 = max.replace("mV", "").parse()?;
-
- clocks_table.voltage_range = (min_voltage, max_voltage);
- }
- _ => {
- return Err(GpuControllerError::ParseError(
- "unrecognized voltage range type".to_string(),
- ))
- }
- }
- }
- }
- _ => {
- return Err(GpuControllerError::ParseError(
- "unrecognized line type".to_string(),
- ))
- }
- }
- }
-
- log::trace!("Successfully parsed the clocks table");
- Ok(clocks_table)
- }
-
- fn parse_clocks_table_new(table: &str) -> Result {
- log::trace!("Detected clocks table format for Vega20 or newer");
-
- let mut clocks_table = ClocksTableNew::default();
-
- let mut lines_iter = table.trim().split("\n").into_iter();
-
- log::trace!("Reading clocks table");
-
- while let Some(line) = &lines_iter.next() {
- let line = line.trim();
- log::trace!("Parsing line {}", line);
-
- match line {
- "OD_SCLK:" => {
- let min_clock_line = lines_iter
- .next()
- .ok_or_else(|| {
- GpuControllerError::ParseError(
- "unexpeceted clocks file end".to_string(),
- )
- })?
- .trim()
- .to_lowercase();
-
- let min_clock: i64 = min_clock_line
- .strip_prefix("0:")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line prefix in {}",
- min_clock_line
- ))
- })?
- .strip_suffix("mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line suffix in {}",
- min_clock_line
- ))
- })?
- .trim()
- .parse()?;
-
- let max_clock_line = lines_iter
- .next()
- .ok_or_else(|| {
- GpuControllerError::ParseError(
- "unexpeceted clocks file end".to_string(),
- )
- })?
- .trim()
- .to_lowercase();
-
- let max_clock: i64 = max_clock_line
- .strip_prefix("1:")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line prefix in {}",
- min_clock_line
- ))
- })?
- .strip_suffix("mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line suffix in {}",
- min_clock_line
- ))
- })?
- .trim()
- .parse()?;
-
- clocks_table.current_gpu_clocks = (min_clock, max_clock);
- }
- "OD_MCLK:" => {
- let max_clock_line = lines_iter
- .next()
- .ok_or_else(|| {
- GpuControllerError::ParseError("unexpected clocks file end".to_string())
- })?
- .trim()
- .to_lowercase();
-
- let max_clock = max_clock_line
- .strip_prefix("1:")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line prefix in {}",
- max_clock_line
- ))
- })?
- .strip_suffix("mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError(format!(
- "invalid clock line suffix in {}",
- max_clock_line
- ))
- })?
- .trim()
- .parse()?;
-
- clocks_table.current_max_mem_clock = max_clock;
- }
- "OD_RANGE:" => {
- while let Some(line) = &lines_iter.next() {
- let line = line.trim();
- log::trace!("Parsing OD_RANGE line {}", &line);
-
- match &line[..5] {
- "SCLK:" => {
- let mut split = line.split_whitespace();
-
- // Skips the 'SCLK'
- split.next().unwrap();
-
- let min_clock = split
- .next()
- .unwrap()
- .strip_suffix("Mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError("missing suffix".to_string())
- })?
- .parse()?;
-
- let max_clock = split
- .next()
- .unwrap()
- .strip_suffix("Mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError("missing suffix".to_string())
- })?
- .parse()?;
-
- clocks_table.gpu_clocks_range = (min_clock, max_clock);
- }
- "MCLK:" => {
- let mut split = line.split_whitespace();
-
- // Skips the 'SCLK'
- split.next().unwrap();
-
- let min_clock = split
- .next()
- .unwrap()
- .strip_suffix("Mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError("missing suffix".to_string())
- })?
- .parse()?;
-
- let max_clock = split
- .next()
- .unwrap()
- .strip_suffix("Mhz")
- .ok_or_else(|| {
- GpuControllerError::ParseError("missing suffix".to_string())
- })?
- .parse()?;
-
- clocks_table.mem_clocks_range = (min_clock, max_clock);
- }
- _ => {
- log::trace!("OD_RANGE ended");
- break;
- }
- }
- }
- }
- _ => {
- log::trace!("Skipping line");
- continue;
- }
- }
- }
-
- Ok(clocks_table)
- }
-
- /*pub fn set_gpu_power_state(
- &mut self,
- num: u32,
- clockspeed: i64,
- voltage: Option,
- ) -> Result<(), GpuControllerError> {
- let mut line = format!("s {} {}", num, clockspeed);
-
- if let Some(voltage) = voltage {
- line.push_str(&format!(" {}", voltage));
- }
- line.push_str("\n");
-
- log::info!("Setting gpu power state {}", line);
- log::info!("Writing {} to pp_od_clk_voltage", line);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), line)?;
-
- self.config
- .gpu_power_states
- .insert(num, (clockspeed, voltage.unwrap()));
-
- Ok(())
- }*/
-
- pub fn set_gpu_max_power_state(
- &mut self,
- clockspeed: i64,
- voltage: Option,
- ) -> Result<(), GpuControllerError> {
- match self.get_clocks_table()? {
- ClocksTable::Old(clocks_table) => {
- let profile = { clocks_table.gpu_power_levels.iter().next_back().unwrap().0 };
-
- let mut line = format!("s {} {}", profile, clockspeed);
-
- if let Some(voltage) = voltage {
- line.push_str(&format!(" {}", voltage));
- }
- line.push_str("\n");
-
- log::info!("Writing {} to pp_od_clk_voltage", line);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), line)?;
-
- self.config.gpu_max_clock = clockspeed;
- self.config.gpu_max_voltage = voltage;
- }
- ClocksTable::New(_) => {
- let s_line = format!("s 1 {}\n", clockspeed);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), s_line)?;
-
- if let Some(voltage) = voltage {
- let vc_line = format!("vc 2 {} {}\n", clockspeed, voltage);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), vc_line)?;
- }
- }
- }
-
- Ok(())
- }
-
- pub fn set_vram_max_clockspeed(&mut self, clockspeed: i64) -> Result<(), GpuControllerError> {
- match self.get_clocks_table()? {
- ClocksTable::Old(clocks_table) => {
- let (profile, voltage) = {
- let power_level = clocks_table.mem_power_levels.iter().next_back().unwrap();
- log::info!("Using mem power level {:?}", power_level);
- (power_level.0, power_level.1 .1)
- };
-
- let line = format!("m {} {} {}\n", profile, clockspeed, voltage);
-
- log::info!("Writing {} to pp_od_clk_voltage", line);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), line)?;
-
- self.config.vram_max_clock = clockspeed;
- }
- ClocksTable::New(_) => {
- let s_line = format!("m 1 {}\n", clockspeed);
-
- fs::write(self.hw_path.join("pp_od_clk_voltage"), s_line)?;
- }
- }
-
- Ok(())
- }
-
- pub fn commit_gpu_power_states(&mut self) -> Result<(), GpuControllerError> {
- fs::write(self.hw_path.join("pp_od_clk_voltage"), b"c\n")?;
- Ok(())
- }
-
- pub fn reset_gpu_power_states(&mut self) -> Result<(), GpuControllerError> {
- fs::write(self.hw_path.join("pp_od_clk_voltage"), b"r\n")?;
- Ok(())
- }
-
- fn get_vulkan_info(pci_id: &str) -> VulkanInfo {
- let mut device_name = String::from("Not supported");
- let mut api_version = String::new();
- let mut features = HashMap::new();
-
- let pci_id = u32::from_str_radix(pci_id, 16).expect("Invalid device ID");
-
- match Instance::new(
- None,
- vulkano::Version::V1_5,
- &InstanceExtensions::none(),
- None,
- ) {
- Ok(instance) => {
- for physical in PhysicalDevice::enumerate(&instance) {
- let properties = physical.properties();
-
- if properties.device_id == pci_id {
- api_version = physical.api_version().to_string();
- device_name = properties.device_name.clone();
-
- let features_string = format!("{:?}", physical.supported_features());
- let features_string = features_string
- .replace("Features", "")
- .replace("{", "")
- .replace("}", "");
-
- for feature in features_string.split(',') {
- // let (name, supported) = feature.split_once(':').unwrap(); Use this once it's in stable
- let mut split = feature.split(':');
- let name = split.next().unwrap().trim();
- let supported = split.next().unwrap().trim();
-
- let supported: bool = supported.parse().unwrap();
-
- features.insert(name.to_string(), supported);
- }
-
- break;
- }
- }
- }
- Err(_) => (),
- }
-
- VulkanInfo {
- device_name,
- api_version,
- features,
- }
- }
-
- fn parse_clock_voltage_line(line: &str) -> Result<(u32, i64, i64), GpuControllerError> {
- log::trace!("Parsing line {}", line);
-
- let line = line.to_uppercase();
- let line_parts: Vec<&str> = line.split_whitespace().collect();
-
- let num: u32 = line_parts
- .get(0)
- .ok_or_else(|| {
- GpuControllerError::ParseError("failed to read the power level number".to_string())
- })?
- .chars()
- .nth(0)
- .unwrap()
- .to_digit(10)
- .unwrap();
- let clock: i64 = line_parts
- .get(1)
- .ok_or_else(|| {
- GpuControllerError::ParseError("failed to read the clockspeed".to_string())
- })?
- .strip_suffix("MHZ")
- .ok_or_else(|| GpuControllerError::ParseError("failed to strip \"MHZ\"".to_string()))?
- .parse()?;
- let voltage: i64 = line_parts
- .get(2)
- .ok_or_else(|| {
- GpuControllerError::ParseError("failed to read the voltage".to_string())
- })?
- .strip_suffix("MV")
- .ok_or_else(|| GpuControllerError::ParseError("failed to strip \"mV\"".to_string()))?
- .parse()?;
-
- Ok((num, clock, voltage))
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn init() {
- let _ = env_logger::builder().is_test(true).try_init();
- }
-
- // pp_od_clk_voltage taken from an RX 580
- #[test]
- fn parse_clocks_table_polaris() {
- init();
-
- let pp_od_clk_voltage = r#"
- OD_SCLK:
- 0: 300MHz 750mV
- 1: 600MHz 769mV
- 2: 900MHz 912mV
- 3: 1145MHz 1125mV
- 4: 1215MHz 1150mV
- 5: 1257MHz 1150mV
- 6: 1300MHz 1150mV
- 7: 1366MHz 1150mV
- OD_MCLK:
- 0: 300MHz 750mV
- 1: 1000MHz 825mV
- 2: 1750MHz 975mV
- OD_RANGE:
- SCLK: 300MHz 2000MHz
- MCLK: 300MHz 2250MHz
- VDDC: 750mV 1200mV"#;
-
- match GpuController::parse_clocks_table(pp_od_clk_voltage).unwrap() {
- ClocksTable::Old(clocks_table) => {
- log::trace!("{:?}", clocks_table);
-
- assert_eq!(clocks_table.gpu_clocks_range, (300, 2000));
- assert_eq!(clocks_table.mem_clocks_range, (300, 2250));
- assert_eq!(clocks_table.voltage_range, (750, 1200));
-
- assert_eq!(
- clocks_table.gpu_power_levels.get(&6).unwrap(),
- &(1300, 1150)
- );
- assert_eq!(clocks_table.mem_power_levels.get(&1).unwrap(), &(1000, 825));
- }
- _ => panic!("Invalid clocks format detected"),
- }
- }
-
- // pp_od_clk_voltage taken from a Vega 56
- #[test]
- fn parse_clocks_table_vega() {
- init();
-
- let pp_od_clk_voltage = r#"
- OD_SCLK:
- 0: 852Mhz 800mV
- 1: 991Mhz 900mV
- 2: 1138Mhz 950mV
- 3: 1269Mhz 1000mV
- 4: 1312Mhz 1050mV
- 5: 1474Mhz 1100mV
- 6: 1538Mhz 1150mV
- 7: 1590Mhz 1157mV
- OD_MCLK:
- 0: 167Mhz 800mV
- 1: 500Mhz 800mV
- 2: 700Mhz 900mV
- 3: 900Mhz 950mV
- OD_RANGE:
- SCLK: 852MHz 2400MHz
- MCLK: 167MHz 1500MHz
- VDDC: 800mV 1200mV"#;
-
- let clocks_table = GpuController::parse_clocks_table(pp_od_clk_voltage).unwrap();
-
- log::trace!("{:?}", clocks_table);
- }
-
- // pp_od_clk_voltage taken from an RX 5700 XT
- #[test]
- fn parse_clocks_table_navi() {
- init();
-
- let pp_od_clk_voltage = r#"
- OD_SCLK:
- 0: 800Mhz
- 1: 2100Mhz
- OD_MCLK:
- 1: 875MHz
- OD_VDDC_CURVE:
- 0: 800MHz 711mV
- 1: 1450MHz 801mV
- 2: 2100MHz 1191mV
- OD_RANGE:
- SCLK: 800Mhz 2150Mhz
- MCLK: 625Mhz 950Mhz
- VDDC_CURVE_SCLK[0]: 800Mhz 2150Mhz
- VDDC_CURVE_VOLT[0]: 750mV 1200mV
- VDDC_CURVE_SCLK[1]: 800Mhz 2150Mhz
- VDDC_CURVE_VOLT[1]: 750mV 1200mV
- VDDC_CURVE_SCLK[2]: 800Mhz 2150Mhz
- VDDC_CURVE_VOLT[2]: 750mV 1200mV
- "#;
-
- match GpuController::parse_clocks_table(pp_od_clk_voltage).unwrap() {
- ClocksTable::New(clocks_table) => {
- log::trace!("{:?}", clocks_table);
-
- assert_eq!(clocks_table.gpu_clocks_range, (800, 2150));
- assert_eq!(clocks_table.mem_clocks_range, (625, 950));
-
- assert_eq!(clocks_table.current_gpu_clocks, (800, 2100));
- assert_eq!(clocks_table.current_max_mem_clock, 875);
- }
- _ => panic!("Invalid clocks format detected"),
- }
- }
-}
diff --git a/daemon/src/hw_mon.rs b/daemon/src/hw_mon.rs
deleted file mode 100644
index 2729a615..00000000
--- a/daemon/src/hw_mon.rs
+++ /dev/null
@@ -1,306 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::collections::{BTreeMap, HashMap};
-use std::path::PathBuf;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, RwLock};
-use std::time::Duration;
-use std::{fs, thread};
-
-#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
-pub struct Temperature {
- pub current: i64,
- pub crit: i64,
- pub crit_hyst: i64,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum HWMonError {
- PermissionDenied,
- InvalidValue,
- Unsupported,
- NoHWMon,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct HWMon {
- hwmon_path: PathBuf,
- fan_control: Arc,
- fan_curve: Arc>>,
-}
-
-impl HWMon {
- pub fn new(
- hwmon_path: &PathBuf,
- fan_control_enabled: bool,
- fan_curve: BTreeMap,
- power_cap: Option,
- ) -> HWMon {
- let mut mon = HWMon {
- hwmon_path: hwmon_path.clone(),
- fan_control: Arc::new(AtomicBool::new(false)),
- fan_curve: Arc::new(RwLock::new(fan_curve)),
- };
-
- if fan_control_enabled {
- mon.start_fan_control().unwrap();
- }
- if let Some(cap) = power_cap {
- #[allow(unused_must_use)]
- {
- mon.set_power_cap(cap);
- }
- }
-
- mon
- }
-
- pub fn get_fan_max_speed(&self) -> Option {
- match fs::read_to_string(self.hwmon_path.join("fan1_max")) {
- Ok(speed) => Some(speed.trim().parse().unwrap()),
- Err(_) => None,
- }
- }
-
- pub fn get_fan_speed(&self) -> Option {
- /*if self.fan_control.load(Ordering::SeqCst) {
- let pwm1 = fs::read_to_string(self.hwmon_path.join("pwm1"))
- .expect("Couldn't read pwm1")
- .trim()
- .parse::()
- .unwrap();
-
- self.fan_max_speed / 255 * pwm1
- }
- else {
- fs::read_to_string(self.hwmon_path.join("fan1_input"))
- .expect("Couldn't read fan speed")
- .trim()
- .parse::()
- .unwrap()
- }*/
- match fs::read_to_string(self.hwmon_path.join("fan1_input")) {
- Ok(a) => Some(a.trim().parse::().unwrap()),
- _ => None,
- }
- }
-
- pub fn get_mem_freq(&self) -> Option {
- let filename = self.hwmon_path.join("freq2_input");
-
- match fs::read_to_string(filename) {
- Ok(freq) => Some(freq.trim().parse::().unwrap() / 1000 / 1000),
- Err(_) => None,
- }
- }
-
- pub fn get_gpu_freq(&self) -> Option {
- let filename = self.hwmon_path.join("freq1_input");
-
- match fs::read_to_string(filename) {
- Ok(freq) => Some(freq.trim().parse::().unwrap() / 1000 / 1000),
- Err(_) => None,
- }
- }
-
- pub fn get_temps(&self) -> HashMap {
- let mut temps = HashMap::new();
-
- for i in 1..3 {
- let label_filename = self.hwmon_path.join(format!("temp{}_label", i));
-
- match fs::read_to_string(label_filename) {
- Ok(label) => {
- // If there's a label identifying the sensor, there should always be input and crit files too. But just in case using .unwrap_or_default()
- let current = {
- let filename = self.hwmon_path.join(format!("temp{}_input", i));
- fs::read_to_string(filename)
- .unwrap_or_default()
- .trim()
- .parse::()
- .unwrap_or_default()
- / 1000
- };
-
- let crit = {
- let filename = self.hwmon_path.join(format!("temp{}_crit", i));
- fs::read_to_string(filename)
- .unwrap_or_default()
- .trim()
- .parse::()
- .unwrap_or_default()
- / 1000
- };
-
- let crit_hyst = {
- let filename = self.hwmon_path.join(format!("temp{}_crit_hyst", i));
- fs::read_to_string(filename)
- .unwrap_or_default()
- .trim()
- .parse::()
- .unwrap_or_default()
- / 1000
- };
-
- temps.insert(
- label.trim().to_string(),
- Temperature {
- current,
- crit,
- crit_hyst,
- },
- );
- }
- Err(_) => break,
- }
- }
-
- temps
- }
-
- pub fn get_voltage(&self) -> Option {
- let filename = self.hwmon_path.join("in0_input");
-
- match fs::read_to_string(filename) {
- Ok(voltage) => Some(voltage.trim().parse::().unwrap()),
- Err(_) => None,
- }
- }
-
- pub fn get_power_cap_max(&self) -> Option {
- let filename = self.hwmon_path.join("power1_cap_max");
-
- match fs::read_to_string(filename) {
- Ok(power_cap) => Some(power_cap.trim().parse::().unwrap() / 1000000),
- _ => None,
- }
- }
-
- pub fn get_power_cap(&self) -> Option {
- let filename = self.hwmon_path.join("power1_cap");
-
- match fs::read_to_string(filename) {
- Ok(a) => Some(a.trim().parse::().unwrap() / 1000000),
- _ => None,
- }
- }
-
- pub fn set_power_cap(&mut self, cap: i64) -> Result<(), HWMonError> {
- if cap
- > self
- .get_power_cap_max()
- .ok_or_else(|| HWMonError::Unsupported)?
- {
- return Err(HWMonError::InvalidValue);
- }
-
- let cap = cap * 1000000;
- log::trace!("setting power cap to {}", cap);
-
- match fs::write(self.hwmon_path.join("power1_cap"), cap.to_string()) {
- Ok(_) => Ok(()),
- Err(_) => Err(HWMonError::PermissionDenied),
- }
- }
-
- pub fn get_power_avg(&self) -> Option {
- let filename = self.hwmon_path.join("power1_average");
-
- match fs::read_to_string(filename) {
- Ok(a) => Some(a.trim().parse::().unwrap() / 1000000),
- Err(_) => None,
- }
- }
-
- pub fn set_fan_curve(&self, curve: BTreeMap) {
- log::trace!("trying to set curve");
- let mut current = self.fan_curve.write().unwrap();
- current.clear();
-
- for (k, v) in curve.iter() {
- current.insert(k.clone(), v.clone());
- }
- log::trace!("set curve to {:?}", current);
- }
-
- pub fn start_fan_control(&self) -> Result<(), HWMonError> {
- if self.fan_control.load(Ordering::SeqCst) {
- return Ok(());
- }
- self.fan_control.store(true, Ordering::SeqCst);
-
- match fs::write(self.hwmon_path.join("pwm1_enable"), "1") {
- Ok(_) => {
- let s = self.clone();
-
- thread::spawn(move || {
- while s.fan_control.load(Ordering::SeqCst) {
- let temps = s.get_temps();
- log::trace!("Temps: {:?}", temps);
-
- // Use junction temp when available, otherwise fall back to edge
- let temps = match temps.get("junction") {
- Some(temp) => temp,
- None => temps.get("edge").unwrap(),
- };
-
- if temps.current >= temps.crit || temps.current <= temps.crit_hyst {
- println!("CRITICAL TEMPERATURE DETECTED! FORCING MAX FAN SPEED");
- fs::write(s.hwmon_path.join("pwm1"), 255.to_string())
- .expect("Failed to set gpu temp in critical scenario (Warning: GPU Overheating!)");
- }
-
- log::trace!("Current gpu temp: {}", temps.current);
-
- let curve = s.fan_curve.read().unwrap();
-
- for (t_low, s_low) in curve.iter() {
- match curve.range(t_low..).nth(1) {
- Some((t_high, s_high)) => {
- if (t_low..t_high).contains(&&temps.current) {
- let speed_ratio = (temps.current - t_low) as f64
- / (t_high - t_low) as f64; //The ratio of which speed to choose within the range of current lower and upper speeds
- let speed_percent =
- s_low + ((s_high - s_low) * speed_ratio);
- let pwm = (255f64 * (speed_percent / 100f64)) as i64;
- log::trace!("pwm: {}", pwm);
-
- fs::write(s.hwmon_path.join("pwm1"), pwm.to_string())
- .expect("Failed to write to pwm1");
-
- log::trace!("In the range of {}..{}c {}..{}%, setting speed {}% ratio {}", t_low, t_high, s_low, s_high, speed_percent, speed_ratio);
- break;
- }
- }
- None => continue,
- }
- }
- drop(curve); //needed to release rwlock so that the curve can be changed
-
- thread::sleep(Duration::from_millis(1000));
- }
- });
- Ok(())
- }
- Err(_) => Err(HWMonError::PermissionDenied),
- }
- }
-
- pub fn stop_fan_control(&self) -> Result<(), HWMonError> {
- match fs::write(self.hwmon_path.join("pwm1_enable"), "2") {
- Ok(_) => {
- self.fan_control.store(false, Ordering::SeqCst);
- log::trace!("Stopping fan control");
- Ok(())
- }
- Err(_) => Err(HWMonError::PermissionDenied),
- }
- }
-
- pub fn get_fan_control(&self) -> (bool, BTreeMap) {
- log::trace!("Fan control: {}", self.fan_control.load(Ordering::SeqCst));
- (
- self.fan_control.load(Ordering::SeqCst),
- self.fan_curve.read().unwrap().clone(),
- )
- }
-}
diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs
deleted file mode 100644
index 13ed0d60..00000000
--- a/daemon/src/lib.rs
+++ /dev/null
@@ -1,498 +0,0 @@
-pub mod config;
-pub mod daemon_connection;
-pub mod gpu_controller;
-pub mod hw_mon;
-
-use config::{Config, GpuConfig};
-use gpu_controller::PowerProfile;
-use pciid_parser::Database;
-use rand::prelude::*;
-use serde::{Deserialize, Serialize};
-use std::path::PathBuf;
-use std::{
- collections::{BTreeMap, HashMap},
- fs,
-};
-
-use crate::gpu_controller::GpuController;
-
-// Abstract socket allows anyone to connect without worrying about permissions
-// https://unix.stackexchange.com/questions/579612/unix-domain-sockets-for-non-root-user
-pub const SOCK_PATH: &str = "amdgpu-configurator.sock";
-pub const BUFFER_SIZE: usize = 16384;
-
-pub struct Daemon {
- gpu_controllers: HashMap,
- listener: std::os::unix::io::RawFd,
- config: Config,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum Action {
- CheckAlive,
- GetConfig,
- SetConfig(Config),
- GetGpus,
- GetInfo(u32),
- GetStats(u32),
- StartFanControl(u32),
- StopFanControl(u32),
- GetFanControl(u32),
- SetFanCurve(u32, BTreeMap),
- SetPowerCap(u32, i64),
- SetPowerProfile(u32, PowerProfile),
- // SetGPUPowerState(u32, u32, i64, Option),
- SetGPUMaxPowerState(u32, i64, Option),
- SetVRAMMaxClock(u32, i64),
- CommitGPUPowerStates(u32),
- ResetGPUPowerStates(u32),
- Shutdown,
-}
-
-impl Daemon {
- pub fn new(unprivileged: bool) -> Daemon {
- let addr = nix::sys::socket::SockAddr::Unix(
- nix::sys::socket::UnixAddr::new_abstract(SOCK_PATH.as_bytes()).unwrap(),
- );
- let listener = nix::sys::socket::socket(
- nix::sys::socket::AddressFamily::Unix,
- nix::sys::socket::SockType::Stream,
- nix::sys::socket::SockFlag::empty(),
- None,
- )
- .expect("Socket failed");
- nix::sys::socket::bind(listener, &addr).expect("Bind failed");
- nix::sys::socket::listen(listener, 128).expect("Listen failed");
-
- let config_path = PathBuf::from("/etc/lact.json");
- let mut config = if unprivileged {
- Config::new(&config_path)
- } else {
- match Config::read_from_file(&config_path) {
- Ok(c) => {
- log::info!("Loaded config from {}", c.config_path.to_string_lossy());
- c
- }
- Err(_) => {
- log::info!("Config not found, creating");
- let c = Config::new(&config_path);
- //c.save().unwrap();
- c
- }
- }
- };
-
- log::info!("Using config {:?}", config);
-
- let gpu_controllers = Self::load_gpu_controllers(&mut config);
-
- if !unprivileged {
- config.save().unwrap();
- }
-
- Daemon {
- listener,
- gpu_controllers,
- config,
- }
- }
-
- fn load_gpu_controllers(config: &mut Config) -> HashMap {
- let pci_db = match config.allow_online_update {
- Some(true) => match Database::get_online() {
- Ok(db) => Some(db),
- Err(e) => {
- log::info!("Error updating PCI db: {:?}", e);
- None
- }
- },
- Some(false) | None => None,
- };
-
- let mut gpu_controllers: HashMap = HashMap::new();
-
- 'entries: for entry in
- fs::read_dir("/sys/class/drm").expect("Could not open /sys/class/drm")
- {
- let entry = entry.unwrap();
- if entry.file_name().len() == 5 {
- if entry.file_name().to_str().unwrap().split_at(4).0 == "card" {
- log::info!("Initializing {:?}", entry.path());
-
- let mut controller =
- GpuController::new(entry.path().join("device"), GpuConfig::new(), &pci_db);
-
- let current_identifier = controller.get_identifier();
-
- log::info!(
- "Searching the config for GPU with identifier {:?}",
- current_identifier
- );
-
- log::info!("{}", &config.gpu_configs.len());
- for (id, (gpu_identifier, gpu_config)) in &config.gpu_configs {
- log::info!("Comparing with {:?}", gpu_identifier);
- if current_identifier == *gpu_identifier {
- controller.load_config(&gpu_config);
- gpu_controllers.insert(id.clone(), controller);
- log::info!("already known");
- continue 'entries;
- }
-
- /*if gpu_info.pci_slot == gpu_identifier.pci_id
- && gpu_info.vendor_data.card_model == gpu_identifier.card_model
- && gpu_info.vendor_data.gpu_model == gpu_identifier.gpu_model
- {
- controller.load_config(&gpu_config);
- gpu_controllers.insert(id.clone(), controller);
- log::info!("already known");
- continue 'entries;
- }*/
- }
-
- log::info!("initializing for the first time");
-
- let id: u32 = random();
-
- config
- .gpu_configs
- .insert(id, (controller.get_identifier(), controller.get_config()));
- gpu_controllers.insert(id, controller);
- }
- }
- }
-
- gpu_controllers
- }
-
- pub fn listen(mut self) {
- loop {
- let stream = nix::sys::socket::accept(self.listener).expect("Accept failed");
- if stream < 0 {
- log::error!("Error from accept");
- break;
- } else {
- Daemon::handle_connection(&mut self, stream);
- }
- }
- }
-
- pub fn read_buffer(stream: i32) -> Vec {
- log::trace!("Reading buffer");
- let mut buffer = Vec::::new();
- buffer.resize(BUFFER_SIZE, 0);
- loop {
- match nix::unistd::read(stream, &mut buffer) {
- Ok(0) => {
- break;
- }
- Ok(n) => {
- assert!(n < buffer.len());
- if n < buffer.len() {
- buffer.resize(n, 0);
- }
- break;
- }
- Err(e) => {
- panic!("Error reading from socket: {}", e);
- }
- }
- }
-
- buffer
- }
-
- fn handle_connection(&mut self, stream: i32) {
- let buffer = Self::read_buffer(stream);
-
- //log::trace!("finished reading, buffer size {}", buffer.len());
- log::trace!("Attempting to deserialize {:?}", &buffer);
- //log::trace!("{:?}", action);
-
- match bincode::deserialize::(&buffer) {
- Ok(action) => {
- log::trace!("Executing action {:?}", action);
- let response: Result = match action {
- Action::CheckAlive => Ok(DaemonResponse::OK),
- Action::GetGpus => {
- let mut gpus: HashMap> = HashMap::new();
- for (id, controller) in &self.gpu_controllers {
- gpus.insert(*id, controller.get_info().vendor_data.gpu_model.clone());
- }
- Ok(DaemonResponse::Gpus(gpus))
- }
- Action::GetStats(i) => match self.gpu_controllers.get(&i) {
- Some(controller) => match controller.get_stats() {
- Ok(stats) => Ok(DaemonResponse::GpuStats(stats)),
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::GetInfo(i) => match self.gpu_controllers.get(&i) {
- Some(controller) => {
- Ok(DaemonResponse::GpuInfo(controller.get_info().clone()))
- }
- None => Err(DaemonError::InvalidID),
- },
- Action::StartFanControl(i) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.start_fan_control() {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::StopFanControl(i) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.stop_fan_control() {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::GetFanControl(i) => match self.gpu_controllers.get(&i) {
- Some(controller) => match controller.get_fan_control() {
- Ok(info) => Ok(DaemonResponse::FanControlInfo(info)),
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::SetFanCurve(i, curve) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.set_fan_curve(curve) {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::SetPowerCap(i, cap) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.set_power_cap(cap) {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::HWMonError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::SetPowerProfile(i, profile) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.set_power_profile(profile) {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- },
- None => Err(DaemonError::InvalidID),
- },
- /*Action::SetGPUPowerState(i, num, clockspeed, voltage) => {
- match self.gpu_controllers.get_mut(&i) {
- Some(controller) => {
- match controller.set_gpu_power_state(num, clockspeed, voltage) {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- }
- }
- None => Err(DaemonError::InvalidID),
- }
- }*/
- Action::SetGPUMaxPowerState(i, clockspeed, voltage) => {
- match self.gpu_controllers.get_mut(&i) {
- Some(controller) => {
- match controller.set_gpu_max_power_state(clockspeed, voltage) {
- Ok(()) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- }
- }
- None => Err(DaemonError::InvalidID),
- }
- }
- Action::SetVRAMMaxClock(i, clockspeed) => {
- match self.gpu_controllers.get_mut(&i) {
- Some(controller) => {
- match controller.set_vram_max_clockspeed(clockspeed) {
- Ok(()) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- }
- }
- None => Err(DaemonError::InvalidID),
- }
- }
- Action::CommitGPUPowerStates(i) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.commit_gpu_power_states() {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::ResetGPUPowerStates(i) => match self.gpu_controllers.get_mut(&i) {
- Some(controller) => match controller.reset_gpu_power_states() {
- Ok(_) => {
- self.config.gpu_configs.insert(
- i,
- (controller.get_identifier(), controller.get_config()),
- );
- self.config.save().unwrap();
- Ok(DaemonResponse::OK)
- }
- Err(_) => Err(DaemonError::ControllerError),
- },
- None => Err(DaemonError::InvalidID),
- },
- Action::Shutdown => {
- for (id, controller) in &mut self.gpu_controllers {
- #[allow(unused_must_use)]
- {
- controller.reset_gpu_power_states();
- controller.commit_gpu_power_states();
- controller.set_power_profile(PowerProfile::Auto);
-
- if self
- .config
- .gpu_configs
- .get(id)
- .unwrap()
- .1
- .fan_control_enabled
- {
- controller.stop_fan_control();
- }
- }
- }
- std::process::exit(0);
- }
- Action::SetConfig(config) => {
- self.config = config;
- self.gpu_controllers.clear();
- self.gpu_controllers = Self::load_gpu_controllers(&mut self.config);
- self.config.save().expect("Failed to save config");
- Ok(DaemonResponse::OK)
- }
- Action::GetConfig => Ok(DaemonResponse::Config(self.config.clone())),
- };
-
- let buffer = bincode::serialize(&response).unwrap();
-
- log::trace!("Responding, buffer length {}", buffer.len());
- nix::unistd::write(stream, &buffer).expect("Writing response to socket failed");
-
- nix::sys::socket::shutdown(stream, nix::sys::socket::Shutdown::Both)
- .expect("Failed to shut down");
- nix::unistd::close(stream).expect("Failed to close");
-
- log::trace!("Finished responding");
- }
- Err(_) => {
- println!("Failed deserializing action");
- }
- }
- }
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum DaemonResponse {
- OK,
- GpuInfo(gpu_controller::GpuInfo),
- GpuStats(gpu_controller::GpuStats),
- Gpus(HashMap>),
- PowerCap((i64, i64)),
- FanControlInfo(gpu_controller::FanControlInfo),
- Config(Config),
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub enum DaemonError {
- ConnectionFailed,
- InvalidID,
- HWMonError,
- ControllerError,
-}
-
-#[cfg(test)]
-mod tests {
- use crate::gpu_controller::VendorData;
-
- use super::*;
-
- fn init() {
- let _ = env_logger::builder().is_test(true).try_init();
- }
-
- #[test]
- fn recognize_polaris() {
- init();
-
- let db = Database::get_online().unwrap();
-
- let vendor_data: VendorData = db.get_device_info("1002", "67df", "1da2", "e387").into();
-
- assert_eq!(
- vendor_data.gpu_vendor,
- Some("Advanced Micro Devices, Inc. [AMD/ATI]".to_string())
- );
-
- assert_eq!(
- vendor_data.gpu_model,
- Some("Ellesmere [Radeon RX 470/480/570/570X/580/580X/590]".to_string())
- );
-
- assert_eq!(
- vendor_data.card_model,
- Some("Radeon RX 580 Pulse 4GB".to_string())
- );
- }
-}
diff --git a/daemon/src/main.rs b/daemon/src/main.rs
deleted file mode 100644
index ed17e1fe..00000000
--- a/daemon/src/main.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-use std::thread;
-
-use daemon::{daemon_connection::DaemonConnection, Daemon};
-use signal_hook::consts::{SIGINT, SIGTERM};
-use signal_hook::iterator::Signals;
-
-fn main() {
- env_logger::init();
- let d = Daemon::new(false);
- let mut signals = Signals::new(&[SIGTERM, SIGINT]).unwrap();
-
- thread::spawn(move || {
- for _ in signals.forever() {
- log::info!("Shutting down");
- let d = DaemonConnection::new().unwrap();
- d.shutdown();
- }
- });
-
- d.listen();
-}
diff --git a/deb/DEBIAN/conffiles b/deb/DEBIAN/conffiles
deleted file mode 100644
index e69de29b..00000000
diff --git a/deb/DEBIAN/control b/deb/DEBIAN/control
deleted file mode 100644
index 21ea5bc0..00000000
--- a/deb/DEBIAN/control
+++ /dev/null
@@ -1,9 +0,0 @@
-Package: lact
-Version: 0.1
-Architecture: all
-Essential: no
-Section: admin
-Priority: optional
-Depends: libgtk-3-0
-Maintainer: Ilya Zlobintsev
-Description: AMDGPU Control Utility
diff --git a/deb/usr/share/applications/lact.desktop b/deb/usr/share/applications/lact.desktop
deleted file mode 100644
index 532759fa..00000000
--- a/deb/usr/share/applications/lact.desktop
+++ /dev/null
@@ -1,5 +0,0 @@
-[Desktop Entry]
-Type=Application
-Name=LACT
-Description=AMDGPU Control Application
-Exec=lact-gui
\ No newline at end of file
diff --git a/deploy.sh b/deploy.sh
deleted file mode 100755
index c21196a4..00000000
--- a/deploy.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-cargo build --release &&
-sudo install -Dm755 target/release/daemon /usr/local/bin/lact-daemon &&
-sudo install -Dm755 target/release/gui /usr/local/bin/lact-gui &&
-sudo install -Dm755 target/release/cli /usr/local/bin/lact-cli &&
-sudo install -Dm644 lactd.service /etc/systemd/system/lactd.service &&
-sudo mkdir -p /usr/local/share/applications &&
-sudo install -Dm644 lact.desktop /usr/local/share/applications/ &&
-sudo systemctl daemon-reload
-sudo systemctl enable lactd &&
-sudo systemctl restart lactd
diff --git a/gui/Cargo.toml b/gui/Cargo.toml
deleted file mode 100644
index 5116b30d..00000000
--- a/gui/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-name = "gui"
-version = "0.1.0"
-authors = ["Ilya Zlobintsev "]
-edition = "2018"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-daemon = { path = "../daemon" }
-
-gtk = { version = "0.14", features = ["v3_22"] }
-pango = "0.14"
-glib = "0.14"
-
-log = "0.4"
-env_logger = "0.9"
\ No newline at end of file
diff --git a/gui/src/app.rs b/gui/src/app.rs
deleted file mode 100644
index ddcb2ce6..00000000
--- a/gui/src/app.rs
+++ /dev/null
@@ -1,296 +0,0 @@
-mod apply_revealer;
-mod header;
-mod root_stack;
-
-extern crate gtk;
-
-use std::sync::Arc;
-use std::thread;
-use std::time::Duration;
-use std::{
- fs,
- sync::atomic::{AtomicU32, Ordering},
-};
-
-use apply_revealer::ApplyRevealer;
-use daemon::daemon_connection::DaemonConnection;
-use daemon::gpu_controller::GpuStats;
-use daemon::DaemonError;
-use gtk::prelude::*;
-use gtk::*;
-
-use header::Header;
-use root_stack::RootStack;
-
-#[derive(Clone)]
-pub struct App {
- pub window: Window,
- pub header: Header,
- root_stack: RootStack,
- apply_revealer: ApplyRevealer,
- daemon_connection: DaemonConnection,
-}
-
-impl App {
- pub fn new(daemon_connection: DaemonConnection) -> Self {
- let window = Window::new(WindowType::Toplevel);
-
- let header = Header::new();
-
- window.set_titlebar(Some(&header.container));
- window.set_title("LACT");
-
- window.set_default_size(500, 600);
-
- window.connect_delete_event(move |_, _| {
- main_quit();
- Inhibit(false)
- });
-
- let root_stack = RootStack::new();
-
- header.set_switcher_stack(&root_stack.container);
-
- let root_box = Box::new(Orientation::Vertical, 5);
-
- root_box.add(&root_stack.container);
-
- let apply_revealer = ApplyRevealer::new();
-
- root_box.add(&apply_revealer.container);
-
- window.add(&root_box);
-
- App {
- window,
- header,
- root_stack,
- apply_revealer,
- daemon_connection,
- }
- }
-
- pub fn run(&self) -> Result<(), DaemonError> {
- self.window.show_all();
-
- let current_gpu_id = Arc::new(AtomicU32::new(0));
-
- {
- let current_gpu_id = current_gpu_id.clone();
- let app = self.clone();
-
- self.header.connect_gpu_selection_changed(move |gpu_id| {
- log::info!("GPU Selection changed");
- app.set_info(gpu_id);
- current_gpu_id.store(gpu_id, Ordering::SeqCst);
- });
- }
-
- let gpus = self.daemon_connection.get_gpus()?;
-
- self.header.set_gpus(gpus);
-
- // Show apply button on setting changes
- {
- let apply_revealer = self.apply_revealer.clone();
-
- self.root_stack
- .thermals_page
- .connect_settings_changed(move || {
- log::info!("Settings changed, showing apply button");
- apply_revealer.show();
- });
-
- let apply_revealer = self.apply_revealer.clone();
-
- self.root_stack.oc_page.connect_settings_changed(move || {
- log::info!("Settings changed, showing apply button");
- apply_revealer.show();
- });
- }
-
- {
- let app = self.clone();
- let current_gpu_id = current_gpu_id.clone();
-
- self.root_stack.oc_page.connect_clocks_reset(move || {
- log::info!("Resetting clocks, but not applying");
-
- let gpu_id = current_gpu_id.load(Ordering::SeqCst);
-
- app.daemon_connection
- .reset_gpu_power_states(gpu_id)
- .expect("Failed to reset clocks");
-
- app.set_info(gpu_id);
-
- app.apply_revealer.show();
- })
- }
-
- // Apply settings
- {
- let current_gpu_id = current_gpu_id.clone();
- let app = self.clone();
-
- self.apply_revealer.connect_apply_button_clicked(move || {
- log::info!("Applying settings");
-
- let gpu_id = current_gpu_id.load(Ordering::SeqCst);
-
- {
- let thermals_settings = app.root_stack.thermals_page.get_thermals_settings();
-
- if thermals_settings.automatic_fan_control_enabled {
- app.daemon_connection
- .stop_fan_control(gpu_id)
- .unwrap_or(println!("Failed to stop fan control"));
- } else {
- app.daemon_connection
- .start_fan_control(gpu_id)
- .unwrap_or(println!("Failed to start fan control"));
- }
-
- app.daemon_connection
- .set_fan_curve(gpu_id, thermals_settings.curve)
- .unwrap_or(println!("Failed to set fan curve"));
- }
-
- if let Some(clocks_settings) = app.root_stack.oc_page.get_clocks() {
- app.daemon_connection
- .set_gpu_max_power_state(
- gpu_id,
- clocks_settings.gpu_clock,
- Some(clocks_settings.gpu_voltage),
- )
- .expect("Failed to set GPU clockspeed/voltage");
-
- app.daemon_connection
- .set_vram_max_clock(gpu_id, clocks_settings.vram_clock)
- .expect("Failed to set VRAM Clock");
-
- app.daemon_connection
- .commit_gpu_power_states(gpu_id)
- .expect("Failed to commit power states");
- }
-
- if let Some(profile) = app.root_stack.oc_page.get_power_profile() {
- app.daemon_connection
- .set_power_profile(gpu_id, profile)
- .expect("Failed to set power profile");
- }
-
- if let Some(cap) = app.root_stack.oc_page.get_power_cap() {
- app.daemon_connection
- .set_power_cap(gpu_id, cap)
- .expect("Failed to set power cap");
- }
-
- app.set_info(gpu_id);
- });
- }
-
- self.start_stats_update_loop(current_gpu_id.clone());
-
- Ok(gtk::main())
- }
-
- fn set_info(&self, gpu_id: u32) {
- let gpu_info = self.daemon_connection.get_gpu_info(gpu_id).unwrap();
- log::trace!("Setting info {:?}", &gpu_info);
-
- self.root_stack.info_page.set_info(&gpu_info);
-
- log::trace!("Setting clocks");
- self.root_stack.oc_page.set_info(&gpu_info);
-
- log::trace!("Setting power profile {:?}", gpu_info.power_profile);
- self.root_stack
- .oc_page
- .set_power_profile(&gpu_info.power_profile);
-
- log::trace!("Setting fan control info");
- match self.daemon_connection.get_fan_control(gpu_id) {
- Ok(fan_control_info) => self
- .root_stack
- .thermals_page
- .set_ventilation_info(fan_control_info),
- Err(_) => self.root_stack.thermals_page.hide_fan_controls(),
- }
-
- {
- // It's overkill to both show and hide the frame, but it needs to be done in set_info because show_all overrides the default hidden state of the frame.
- match fs::read_to_string("/sys/module/amdgpu/parameters/ppfeaturemask") {
- Ok(ppfeaturemask) => {
- const PP_OVERDRIVE_MASK: i32 = 0x4000;
-
- let ppfeaturemask = ppfeaturemask.trim().strip_prefix("0x").unwrap();
-
- log::trace!("ppfeaturemask {}", ppfeaturemask);
-
- let ppfeaturemask: u64 =
- u64::from_str_radix(ppfeaturemask, 16).expect("Invalid ppfeaturemask");
-
- if (ppfeaturemask & PP_OVERDRIVE_MASK as u64) > 0 {
- self.root_stack.oc_page.warning_frame.hide();
- } else {
- self.root_stack.oc_page.warning_frame.show();
- }
- }
- Err(_) => {
- log::info!("Failed to read feature mask! This is expected if your system doesn't have an AMD GPU.");
- self.root_stack.oc_page.warning_frame.hide();
- }
- }
- }
-
- self.apply_revealer.hide();
- }
-
- fn start_stats_update_loop(&self, current_gpu_id: Arc) {
- let context = glib::MainContext::default();
-
- let _guard = context.acquire();
-
- // The loop that gets stats
- let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
- {
- let daemon_connection = self.daemon_connection.clone();
-
- thread::spawn(move || loop {
- let gpu_id = current_gpu_id.load(Ordering::SeqCst);
-
- if let Ok(stats) = daemon_connection.get_gpu_stats(gpu_id) {
- sender.send(GuiUpdateMsg::GpuStats(stats)).unwrap();
- }
-
- thread::sleep(Duration::from_millis(500));
- });
- }
-
- // Receiving stats into the gui event loop
- {
- let thermals_page = self.root_stack.thermals_page.clone();
- let oc_page = self.root_stack.oc_page.clone();
-
- receiver.attach(None, move |msg| {
- match msg {
- GuiUpdateMsg::GpuStats(stats) => {
- log::trace!("New stats received, updating");
- thermals_page.set_thermals_info(&stats);
- oc_page.set_stats(&stats);
- } /*GuiUpdateMsg::FanControlInfo(fan_control_info) => {
- thermals_page.set_ventilation_info(fan_control_info)
- }*/
- }
-
- glib::Continue(true)
- });
- }
- }
-}
-
-enum GuiUpdateMsg {
- // FanControlInfo(FanControlInfo),
- GpuStats(GpuStats),
-}
diff --git a/gui/src/app/apply_revealer.rs b/gui/src/app/apply_revealer.rs
deleted file mode 100644
index b940a690..00000000
--- a/gui/src/app/apply_revealer.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct ApplyRevealer {
- pub container: Revealer,
- apply_button: Button,
-}
-
-impl ApplyRevealer {
- pub fn new() -> Self {
- let container = Revealer::new();
-
- container.set_transition_duration(150);
-
- let apply_button = Button::new();
-
- apply_button.set_label("Apply");
-
- container.add(&apply_button);
-
- Self {
- container,
- apply_button,
- }
- }
-
- pub fn show(&self) {
- self.container.set_reveal_child(true);
- }
-
- pub fn hide(&self) {
- self.container.set_reveal_child(false);
- }
-
- pub fn connect_apply_button_clicked(&self, f: F) {
- self.apply_button.connect_clicked(move |_| {
- f();
- });
- }
-}
diff --git a/gui/src/app/root_stack.rs b/gui/src/app/root_stack.rs
deleted file mode 100644
index 60bd65f4..00000000
--- a/gui/src/app/root_stack.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-mod info_page;
-mod oc_page;
-mod software_page;
-mod thermals_page;
-
-use gtk::prelude::*;
-use gtk::*;
-
-use info_page::InformationPage;
-use oc_page::OcPage;
-use software_page::SoftwarePage;
-use thermals_page::ThermalsPage;
-
-#[derive(Clone)]
-pub struct RootStack {
- pub container: Stack,
- pub info_page: InformationPage,
- pub thermals_page: ThermalsPage,
- pub software_page: SoftwarePage,
- pub oc_page: OcPage,
-}
-
-impl RootStack {
- pub fn new() -> Self {
- let container = Stack::new();
-
- let info_page = InformationPage::new();
-
- container.add_titled(&info_page.container, "info_page", "Information");
-
- let oc_page = OcPage::new();
-
- container.add_titled(&oc_page.container, "oc_page", "OC");
-
- let thermals_page = ThermalsPage::new();
-
- container.add_titled(&thermals_page.container, "thermals_page", "Thermals");
-
- let software_page = SoftwarePage::new();
-
- container.add_titled(&software_page.container, "software_page", "Software");
-
- Self {
- container,
- info_page,
- thermals_page,
- oc_page,
- software_page,
- }
- }
-}
diff --git a/gui/src/app/root_stack/info_page/vulkan_info.rs b/gui/src/app/root_stack/info_page/vulkan_info.rs
deleted file mode 100644
index 5f6f4cc1..00000000
--- a/gui/src/app/root_stack/info_page/vulkan_info.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-use daemon::gpu_controller::VulkanInfo;
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct VulkanInfoFrame {
- pub container: Frame,
- device_name_label: Label,
- version_label: Label,
- features_box: Box,
-}
-
-impl VulkanInfoFrame {
- pub fn new() -> Self {
- let container = Frame::new(None);
-
- container.set_label_widget(Some(&{
- let label = Label::new(None);
- label.set_markup("Vulkan Information");
- label
- }));
- container.set_label_align(0.5, 0.5);
-
- container.set_shadow_type(ShadowType::None);
-
- let grid = Grid::new();
-
- grid.set_margin_start(5);
- grid.set_margin_end(5);
- grid.set_margin_bottom(5);
- grid.set_margin_top(5);
-
- grid.set_column_homogeneous(true);
-
- grid.set_row_spacing(7);
- grid.set_column_spacing(5);
-
- grid.attach(
- &{
- let label = Label::new(Some("Device name:"));
- label.set_halign(Align::End);
- label
- },
- 0,
- 0,
- 2,
- 1,
- );
-
- let device_name_label = Label::new(None);
- device_name_label.set_halign(Align::Start);
-
- grid.attach(&device_name_label, 2, 0, 3, 1);
-
- grid.attach(
- &{
- let label = Label::new(Some("Version:"));
- label.set_halign(Align::End);
- label
- },
- 0,
- 1,
- 2,
- 1,
- );
-
- let version_label = Label::new(None);
- version_label.set_halign(Align::Start);
-
- grid.attach(&version_label, 2, 1, 3, 1);
-
- let features_expander = Expander::new(Some("Feature support"));
-
- grid.attach(&features_expander, 0, 2, 5, 1);
-
- let features_scrolled_window = ScrolledWindow::new(NONE_ADJUSTMENT, NONE_ADJUSTMENT);
-
- features_scrolled_window.set_vexpand(true);
-
- let features_box = Box::new(Orientation::Vertical, 5);
-
- features_box.set_halign(Align::Center);
-
- features_scrolled_window.add(&features_box);
-
- features_expander.add(&features_scrolled_window);
-
- container.add(&grid);
-
- Self {
- container,
- device_name_label,
- version_label,
- features_box,
- }
- }
-
- pub fn set_info(&self, vulkan_info: &VulkanInfo) {
- log::trace!("Setting vulkan info: {:?}", vulkan_info);
-
- self.device_name_label
- .set_markup(&format!("{}", vulkan_info.device_name));
- self.version_label
- .set_markup(&format!("{}", vulkan_info.api_version));
-
- for (feature, supported) in vulkan_info.features.iter() {
- let vbox = Box::new(Orientation::Horizontal, 5);
-
- let feature_name_label = Label::new(Some(feature));
-
- vbox.pack_start(&feature_name_label, false, false, 0);
-
- let feature_supported_checkbutton = CheckButton::new();
-
- feature_supported_checkbutton.set_sensitive(false);
- feature_supported_checkbutton.set_active(*supported);
-
- vbox.pack_start(&feature_supported_checkbutton, false, false, 0);
-
- self.features_box.pack_end(&vbox, false, false, 0);
- }
- }
-}
diff --git a/gui/src/app/root_stack/oc_page.rs b/gui/src/app/root_stack/oc_page.rs
deleted file mode 100644
index 1ce6be94..00000000
--- a/gui/src/app/root_stack/oc_page.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-mod clocks_frame;
-mod power_cap_frame;
-mod power_profile_frame;
-mod stats_grid;
-mod warning_frame;
-
-use clocks_frame::ClocksSettings;
-use daemon::gpu_controller::{GpuInfo, GpuStats, PowerProfile};
-use gtk::prelude::*;
-use gtk::*;
-
-use clocks_frame::ClocksFrame;
-use power_cap_frame::PowerCapFrame;
-use power_profile_frame::PowerProfileFrame;
-use stats_grid::StatsGrid;
-use warning_frame::WarningFrame;
-
-#[derive(Clone)]
-pub struct OcPage {
- pub container: Box,
- stats_grid: StatsGrid,
- power_profile_frame: PowerProfileFrame,
- power_cap_frame: PowerCapFrame,
- clocks_frame: ClocksFrame,
- pub warning_frame: WarningFrame,
-}
-
-impl OcPage {
- pub fn new() -> Self {
- let container = Box::new(Orientation::Vertical, 5);
-
- let warning_frame = WarningFrame::new();
-
- container.pack_start(&warning_frame.container, false, true, 5);
-
- let stats_grid = StatsGrid::new();
-
- container.pack_start(&stats_grid.container, false, true, 5);
-
- let power_cap_frame = PowerCapFrame::new();
-
- container.pack_start(&power_cap_frame.container, false, true, 0);
-
- let power_profile_frame = PowerProfileFrame::new();
-
- container.pack_start(&power_profile_frame.container, false, true, 0);
-
- let clocks_frame = ClocksFrame::new();
-
- container.pack_start(&clocks_frame.container, false, true, 0);
-
- Self {
- container,
- stats_grid,
- power_profile_frame,
- clocks_frame,
- warning_frame,
- power_cap_frame,
- }
- }
-
- pub fn set_stats(&self, stats: &GpuStats) {
- self.stats_grid.set_stats(stats);
- }
-
- pub fn connect_clocks_reset(&self, f: F) {
- self.clocks_frame.connect_clocks_reset(move || {
- f();
- });
- }
-
- pub fn connect_settings_changed(&self, f: F) {
- {
- let f = f.clone();
- self.power_profile_frame
- .connect_power_profile_changed(move || {
- f();
- });
- }
- {
- let f = f.clone();
- self.clocks_frame.connect_clocks_changed(move || {
- f();
- })
- }
- {
- self.power_cap_frame.connect_cap_changed(move || {
- f();
- })
- }
- }
-
- pub fn set_power_profile(&self, profile: &Option) {
- match profile {
- Some(profile) => {
- self.power_profile_frame.show();
- self.power_profile_frame.set_active_profile(profile);
- }
- None => self.power_profile_frame.hide(),
- }
- }
-
- pub fn get_power_profile(&self) -> Option {
- match self.power_profile_frame.get_visibility() {
- true => Some(self.power_profile_frame.get_selected_power_profile()),
- false => None,
- }
- }
-
- pub fn set_info(&self, info: &GpuInfo) {
- match &info.clocks_table {
- Some(clocks_table) => {
- self.clocks_frame.show();
- self.clocks_frame.set_clocks(clocks_table);
- }
- None => self.clocks_frame.hide(),
- }
-
- self.power_cap_frame
- .set_data(info.power_cap, info.power_cap_max);
- }
-
- pub fn get_clocks(&self) -> Option {
- match self.clocks_frame.get_visibility() {
- true => Some(self.clocks_frame.get_settings()),
- false => None,
- }
- }
-
- pub fn get_power_cap(&self) -> Option {
- self.power_cap_frame.get_cap()
- }
-}
diff --git a/gui/src/app/root_stack/oc_page/clocks_frame.rs b/gui/src/app/root_stack/oc_page/clocks_frame.rs
deleted file mode 100644
index 6605b128..00000000
--- a/gui/src/app/root_stack/oc_page/clocks_frame.rs
+++ /dev/null
@@ -1,228 +0,0 @@
-use daemon::gpu_controller::ClocksTable;
-use gtk::prelude::*;
-use gtk::*;
-
-pub struct ClocksSettings {
- pub gpu_clock: i64,
- pub vram_clock: i64,
- pub gpu_voltage: i64,
-}
-
-#[derive(Clone)]
-pub struct ClocksFrame {
- pub container: Frame,
- gpu_clock_adjustment: Adjustment,
- gpu_voltage_adjustment: Adjustment,
- vram_clock_adjustment: Adjustment,
- apply_button: Button,
-}
-
-impl ClocksFrame {
- pub fn new() -> Self {
- let container = Frame::new(None);
-
- container.set_margin_start(10);
- container.set_margin_end(10);
-
- container.set_shadow_type(ShadowType::None);
-
- container.set_label_widget(Some(&{
- let label = Label::new(None);
- label.set_markup("Maximum Clocks");
- label
- }));
- container.set_label_align(0.2, 0.0);
-
- let gpu_clock_adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
-
- let gpu_voltage_adjustment = Adjustment::new(1.0, 0.0, 0.0, 0.05, 0.0, 0.0);
-
- let vram_clock_adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
-
- let root_grid = Grid::new();
-
- root_grid.set_row_spacing(5);
- root_grid.set_column_spacing(10);
-
- {
- let gpu_clock_scale = Scale::new(Orientation::Horizontal, Some(&gpu_clock_adjustment));
-
- gpu_clock_scale.set_hexpand(true); // Affects the grid column and all scales
-
- gpu_clock_scale.set_value_pos(PositionType::Right);
-
- root_grid.attach(&gpu_clock_scale, 1, 0, 1, 1);
-
- root_grid.attach_next_to(
- &Label::new(Some("GPU Clock (MHz)")),
- Some(&gpu_clock_scale),
- PositionType::Left,
- 1,
- 1,
- );
-
- let gpu_voltage_scale =
- Scale::new(Orientation::Horizontal, Some(&gpu_voltage_adjustment));
-
- gpu_voltage_scale.set_value_pos(PositionType::Right);
-
- gpu_voltage_scale.set_digits(3);
- gpu_voltage_scale.set_round_digits(3);
-
- root_grid.attach(&gpu_voltage_scale, 1, 1, 1, 1);
-
- root_grid.attach_next_to(
- &Label::new(Some("GPU Voltage (V)")),
- Some(&gpu_voltage_scale),
- PositionType::Left,
- 1,
- 1,
- );
-
- let vram_clock_scale =
- Scale::new(Orientation::Horizontal, Some(&vram_clock_adjustment));
-
- vram_clock_scale.set_value_pos(PositionType::Right);
-
- root_grid.attach(&vram_clock_scale, 1, 2, 1, 1);
-
- root_grid.attach_next_to(
- &Label::new(Some("VRAM Clock (MHz)")),
- Some(&vram_clock_scale),
- PositionType::Left,
- 1,
- 1,
- );
- }
-
- let apply_button = Button::new();
-
- {
- apply_button.set_label("Reset");
-
- root_grid.attach(&apply_button, 0, 3, 2, 1);
-
- container.add(&root_grid);
- }
-
- Self {
- container,
- gpu_clock_adjustment,
- gpu_voltage_adjustment,
- vram_clock_adjustment,
- apply_button,
- }
- }
-
- pub fn get_visibility(&self) -> bool {
- self.container.get_visible()
- }
-
- pub fn set_clocks(&self, clocks_table: &ClocksTable) {
- match clocks_table {
- ClocksTable::Old(clocks_table) => {
- self.gpu_clock_adjustment
- .set_lower(clocks_table.gpu_clocks_range.0 as f64);
- self.gpu_clock_adjustment
- .set_upper(clocks_table.gpu_clocks_range.1 as f64);
-
- self.gpu_voltage_adjustment
- .set_lower(clocks_table.voltage_range.0 as f64 / 1000.0);
- self.gpu_voltage_adjustment
- .set_upper(clocks_table.voltage_range.1 as f64 / 1000.0);
-
- self.vram_clock_adjustment
- .set_lower(clocks_table.mem_clocks_range.0 as f64);
- self.vram_clock_adjustment
- .set_upper(clocks_table.mem_clocks_range.1 as f64);
-
- let (gpu_clockspeed, gpu_voltage) =
- clocks_table.gpu_power_levels.iter().next_back().unwrap().1;
-
- self.gpu_clock_adjustment.set_value(*gpu_clockspeed as f64);
-
- self.gpu_voltage_adjustment
- .set_value(*gpu_voltage as f64 / 1000.0);
-
- let (vram_clockspeed, _) =
- clocks_table.mem_power_levels.iter().next_back().unwrap().1;
-
- self.vram_clock_adjustment
- .set_value(*vram_clockspeed as f64);
- }
- ClocksTable::New(clocks_table) => {
- self.gpu_clock_adjustment
- .set_lower(clocks_table.gpu_clocks_range.0 as f64);
- self.gpu_clock_adjustment
- .set_upper(clocks_table.gpu_clocks_range.1 as f64);
-
- /* self.gpu_voltage_adjustment
- .set_lower(clocks_table.voltage_range.0 as f64 / 1000.0);
- self.gpu_voltage_adjustment
- .set_upper(clocks_table.voltage_range.1 as f64 / 1000.0);*/
-
- self.vram_clock_adjustment
- .set_lower(clocks_table.mem_clocks_range.0 as f64);
- self.vram_clock_adjustment
- .set_upper(clocks_table.mem_clocks_range.1 as f64);
-
- self.gpu_clock_adjustment
- .set_value(clocks_table.current_gpu_clocks.1 as f64);
-
- // self.gpu_voltage_adjustment
- // .set_value(*clocks_table.gpu_voltage as f64 / 1000.0);
-
- self.vram_clock_adjustment
- .set_value(clocks_table.current_max_mem_clock as f64);
- }
- }
- }
-
- pub fn get_settings(&self) -> ClocksSettings {
- let gpu_clock = self.gpu_clock_adjustment.value() as i64;
-
- let vram_clock = self.vram_clock_adjustment.value() as i64;
-
- let gpu_voltage = (self.gpu_voltage_adjustment.value() * 1000.0) as i64;
-
- ClocksSettings {
- gpu_clock,
- vram_clock,
- gpu_voltage,
- }
- }
-
- pub fn connect_clocks_reset(&self, f: F) {
- self.apply_button.connect_clicked(move |_| {
- f();
- });
- }
-
- pub fn connect_clocks_changed(&self, f: F) {
- {
- let f = f.clone();
- self.gpu_clock_adjustment.connect_value_changed(move |_| {
- f();
- });
- }
- {
- let f = f.clone();
- self.vram_clock_adjustment.connect_value_changed(move |_| {
- f();
- });
- }
- {
- self.gpu_voltage_adjustment.connect_value_changed(move |_| {
- f();
- });
- }
- }
-
- pub fn hide(&self) {
- self.container.set_visible(false);
- }
-
- pub fn show(&self) {
- self.container.set_visible(true);
- }
-}
diff --git a/gui/src/app/root_stack/oc_page/power_cap_frame.rs b/gui/src/app/root_stack/oc_page/power_cap_frame.rs
deleted file mode 100644
index 683eecb4..00000000
--- a/gui/src/app/root_stack/oc_page/power_cap_frame.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct PowerCapFrame {
- pub container: Frame,
- label: Label,
- adjustment: Adjustment,
-}
-
-impl PowerCapFrame {
- pub fn new() -> Self {
- let container = Frame::new(None);
-
- container.set_shadow_type(ShadowType::None);
-
- container.set_label_widget(Some(&{
- let label = Label::new(None);
- label.set_markup("Power Usage Limit");
- label
- }));
- container.set_label_align(0.2, 0.0);
-
- let root_box = Box::new(Orientation::Horizontal, 0);
-
- let label = Label::new(None);
-
- root_box.pack_start(&label, false, true, 5);
-
- let adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 10.0, 0.0);
- {
- let label = label.clone();
- adjustment.connect_value_changed(move |adj| {
- label.set_markup(&format!("{}/{} W", adj.value().round(), adj.upper()));
- });
- }
-
- let scale = Scale::new(Orientation::Horizontal, Some(&adjustment));
-
- scale.set_draw_value(false);
-
- root_box.pack_start(&scale, true, true, 5);
-
- container.add(&root_box);
-
- Self {
- container,
- label,
- adjustment,
- }
- }
-
- pub fn set_data(&self, power_cap: Option, power_cap_max: Option) {
- if let Some(power_cap_max) = power_cap_max {
- self.adjustment.set_upper(power_cap_max as f64);
- } else {
- self.container.set_visible(false);
- }
- if let Some(power_cap) = power_cap {
- self.adjustment.set_value(power_cap as f64);
- } else {
- self.container.set_visible(false);
- }
- }
-
- pub fn get_cap(&self) -> Option {
- // Using match gives a warning that floats shouldn't be used in patterns
- let cap = self.adjustment.value();
- if cap == 0.0 {
- None
- } else {
- Some(cap as i64)
- }
- }
-
- pub fn connect_cap_changed(&self, f: F) {
- self.adjustment.connect_value_changed(move |_| {
- f();
- });
- }
-}
diff --git a/gui/src/app/root_stack/oc_page/power_profile_frame.rs b/gui/src/app/root_stack/oc_page/power_profile_frame.rs
deleted file mode 100644
index 43a054f3..00000000
--- a/gui/src/app/root_stack/oc_page/power_profile_frame.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use daemon::gpu_controller::PowerProfile;
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct PowerProfileFrame {
- pub container: Frame,
- combo_box: ComboBoxText,
- description_label: Label,
-}
-
-impl PowerProfileFrame {
- pub fn new() -> Self {
- let container = Frame::new(None);
-
- container.set_shadow_type(ShadowType::None);
-
- container.set_label_widget(Some(&{
- let label = Label::new(None);
- label.set_markup("Power Profile");
- label
- }));
- container.set_label_align(0.2, 0.0);
-
- let root_box = Box::new(Orientation::Horizontal, 5);
-
- let combo_box = ComboBoxText::new();
-
- combo_box.append(Some("0"), "Automatic");
- combo_box.append(Some("1"), "Highest clocks");
- combo_box.append(Some("2"), "Lowest clocks");
-
- root_box.pack_start(&combo_box, false, true, 5);
-
- let description_label = Label::new(Some("A description is supposed to be here"));
-
- root_box.pack_start(&description_label, false, true, 5);
-
- {
- let description_label = description_label.clone();
- combo_box.connect_changed(move |combobox| match combobox.active().unwrap() {
- 0 => description_label
- .set_text("Automatically adjust GPU and VRAM clocks. (Default)"),
- 1 => description_label
- .set_text("Always use the highest clockspeeds for GPU and VRAM."),
- 2 => description_label
- .set_text("Always use the lowest clockspeeds for GPU and VRAM."),
- _ => unreachable!(),
- });
- }
-
- container.add(&root_box);
- Self {
- container,
- combo_box,
- description_label,
- }
- }
-
- pub fn set_active_profile(&self, profile: &PowerProfile) {
- match profile {
- PowerProfile::Auto => self.combo_box.set_active_id(Some("0")),
- PowerProfile::High => self.combo_box.set_active_id(Some("1")),
- PowerProfile::Low => self.combo_box.set_active_id(Some("2")),
- };
- }
-
- pub fn connect_power_profile_changed(&self, f: F) {
- self.combo_box.connect_changed(move |_| {
- f();
- });
- }
-
- pub fn get_selected_power_profile(&self) -> PowerProfile {
- match self.combo_box.active().unwrap() {
- 0 => PowerProfile::Auto,
- 1 => PowerProfile::High,
- 2 => PowerProfile::Low,
- _ => unreachable!(),
- }
- }
-
- pub fn show(&self) {
- self.container.set_visible(true);
- }
-
- pub fn hide(&self) {
- self.container.set_visible(false);
- }
-
- pub fn get_visibility(&self) -> bool {
- self.container.get_visible()
- }
-}
diff --git a/gui/src/app/root_stack/oc_page/warning_frame.rs b/gui/src/app/root_stack/oc_page/warning_frame.rs
deleted file mode 100644
index 70a3456e..00000000
--- a/gui/src/app/root_stack/oc_page/warning_frame.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct WarningFrame {
- pub container: Frame,
-}
-
-impl WarningFrame {
- pub fn new() -> Self {
- let container = Frame::new(Some("Overclocking information"));
-
- container.set_label_align(0.3, 0.5);
-
- let warning_label = Label::new(None);
-
- warning_label.set_line_wrap(true);
- warning_label.set_markup("Overclocking support is not enabled! To enable overclocking support, you need to add amdgpu.ppfeaturemask=0xffffffff to your kernel boot options. Look for the documentation of your distro.");
- warning_label.set_selectable(true);
-
- container.add(&warning_label);
-
- Self { container }
- }
-
- pub fn show(&self) {
- self.container.set_visible(true);
- }
-
- pub fn hide(&self) {
- self.container.set_visible(false);
- }
-}
diff --git a/gui/src/app/root_stack/software_page.rs b/gui/src/app/root_stack/software_page.rs
deleted file mode 100644
index 48e8e7eb..00000000
--- a/gui/src/app/root_stack/software_page.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Debug, Clone)]
-pub struct SoftwarePage {
- pub container: Grid,
- lact_version_label: Label,
-}
-
-impl SoftwarePage {
- pub fn new() -> Self {
- let container = Grid::new();
-
- container.set_margin_start(5);
- container.set_margin_end(5);
- container.set_margin_bottom(5);
- container.set_margin_top(5);
-
- container.set_column_spacing(10);
-
- container.attach(
- &{
- let label = Label::new(None);
- label.set_markup("LACT Version:");
- label.set_halign(Align::End);
- label.set_hexpand(true);
- label
- },
- 0,
- 0,
- 1,
- 1,
- );
- let lact_version_label = Label::new(None);
-
- let lact_version = env!("CARGO_PKG_VERSION");
- let lact_release_type = match cfg!(debug_assertions) {
- true => "debug",
- false => "release",
- };
-
- lact_version_label.set_markup(&format!("{}-{}", lact_version, lact_release_type));
-
- lact_version_label.set_hexpand(true);
- lact_version_label.set_halign(Align::Start);
-
- container.attach(&lact_version_label, 1, 0, 1, 1);
-
- Self {
- container,
- lact_version_label,
- }
- }
-}
diff --git a/gui/src/app/root_stack/thermals_page.rs b/gui/src/app/root_stack/thermals_page.rs
deleted file mode 100644
index d6a69f95..00000000
--- a/gui/src/app/root_stack/thermals_page.rs
+++ /dev/null
@@ -1,208 +0,0 @@
-mod fan_curve_frame;
-
-use daemon::gpu_controller::{FanControlInfo, GpuStats};
-use gtk::prelude::*;
-use gtk::*;
-use std::collections::BTreeMap;
-
-use fan_curve_frame::FanCurveFrame;
-
-pub struct ThermalsSettings {
- pub automatic_fan_control_enabled: bool,
- pub curve: BTreeMap,
-}
-
-#[derive(Clone)]
-pub struct ThermalsPage {
- pub container: Box,
- temp_label: Label,
- fan_speed_label: Label,
- fan_control_enabled_switch: Switch,
- fan_curve_frame: FanCurveFrame,
-}
-
-impl ThermalsPage {
- pub fn new() -> Self {
- let container = Box::new(Orientation::Vertical, 5);
-
- let grid = Grid::new();
-
- grid.set_margin_start(5);
- grid.set_margin_end(5);
- grid.set_margin_bottom(5);
- grid.set_margin_top(5);
-
- grid.set_column_homogeneous(true);
-
- grid.set_row_spacing(7);
- grid.set_column_spacing(5);
-
- grid.attach(
- &{
- let label = Label::new(Some("Temperatures:"));
- label.set_halign(Align::End);
- label
- },
- 0,
- 0,
- 1,
- 1,
- );
-
- let temp_label = Label::new(None);
- temp_label.set_halign(Align::Start);
-
- grid.attach(&temp_label, 2, 0, 1, 1);
-
- grid.attach(
- &{
- let label = Label::new(Some("Fan speed:"));
- label.set_halign(Align::End);
- label
- },
- 0,
- 1,
- 1,
- 1,
- );
-
- let fan_speed_label = Label::new(None);
- fan_speed_label.set_halign(Align::Start);
-
- grid.attach(&fan_speed_label, 2, 1, 1, 1);
-
- grid.attach(
- &{
- let label = Label::new(Some("Automatic fan control:"));
- label.set_halign(Align::End);
- label
- },
- 0,
- 2,
- 1,
- 1,
- );
-
- let fan_control_enabled_switch = Switch::new();
-
- fan_control_enabled_switch.set_active(true);
- fan_control_enabled_switch.set_halign(Align::Start);
-
- grid.attach(&fan_control_enabled_switch, 2, 2, 1, 1);
-
- container.pack_start(&grid, false, false, 5);
-
- let fan_curve_frame = FanCurveFrame::new();
-
- container.pack_start(&fan_curve_frame.container, true, true, 5);
-
- // Show/hide fan curve when the switch is toggled
- {
- let fan_curve_frame = fan_curve_frame.clone();
- fan_control_enabled_switch.connect_changed_active(move |switch| {
- log::trace!("Fan control switch toggled");
- if switch.state() {
- {
- glib::idle_add(|| {
- let diag = MessageDialog::new(None::<&Window>, DialogFlags::empty(), MessageType::Warning, ButtonsType::Ok,
- "Warning! Due to a driver bug, a reboot may be required for fan control to properly switch back to automatic.");
- diag.run();
- diag.hide();
- glib::Continue(false)
- });
- }
-
- fan_curve_frame.hide();
- } else {
- fan_curve_frame.show();
- }
- });
- }
-
- Self {
- container,
- temp_label,
- fan_speed_label,
- fan_control_enabled_switch,
- fan_curve_frame,
- }
- }
-
- pub fn set_thermals_info(&self, stats: &GpuStats) {
- self.temp_label.set_markup(&format!("{}", {
- let mut temperatures = Vec::new();
-
- for (label, temp) in stats.temperatures.iter() {
- temperatures.push(format!("{}: {}°C", label, temp.current));
- }
-
- temperatures.sort();
-
- if !temperatures.is_empty() {
- temperatures.join("\n")
- } else {
- String::from("No sensors found")
- }
- }));
-
- match stats.fan_speed {
- Some(fan_speed) => self.fan_speed_label.set_markup(&format!(
- "{} RPM ({}%)",
- fan_speed,
- (fan_speed as f64 / stats.max_fan_speed.unwrap() as f64 * 100.0).round()
- )),
- None => self.fan_speed_label.set_text("No fan detected"),
- }
- }
-
- pub fn set_ventilation_info(&self, fan_control_info: FanControlInfo) {
- log::info!("Setting fan control info {:?}", fan_control_info);
-
- self.fan_control_enabled_switch.set_visible(true);
-
- self.fan_control_enabled_switch
- .set_active(!fan_control_info.enabled);
-
- if !fan_control_info.enabled {
- self.fan_curve_frame.hide();
- } else {
- self.fan_curve_frame.show();
- }
-
- self.fan_curve_frame.set_curve(&fan_control_info.curve);
- }
-
- pub fn connect_settings_changed(&self, f: F) {
- // Fan control switch toggled
- {
- let f = f.clone();
- self.fan_control_enabled_switch
- .connect_changed_active(move |_| {
- f();
- });
- }
-
- // Fan curve adjusted
- {
- let f = f.clone();
- self.fan_curve_frame.connect_adjusted(move || {
- f();
- });
- }
- }
-
- pub fn get_thermals_settings(&self) -> ThermalsSettings {
- let automatic_fan_control_enabled = self.fan_control_enabled_switch.state();
- let curve = self.fan_curve_frame.get_curve();
-
- ThermalsSettings {
- automatic_fan_control_enabled,
- curve,
- }
- }
-
- pub fn hide_fan_controls(&self) {
- self.fan_control_enabled_switch.set_visible(false);
- self.fan_curve_frame.hide();
- }
-}
diff --git a/gui/src/app/root_stack/thermals_page/fan_curve_frame.rs b/gui/src/app/root_stack/thermals_page/fan_curve_frame.rs
deleted file mode 100644
index 60f0fdab..00000000
--- a/gui/src/app/root_stack/thermals_page/fan_curve_frame.rs
+++ /dev/null
@@ -1,217 +0,0 @@
-use std::collections::BTreeMap;
-
-use gtk::prelude::*;
-use gtk::*;
-
-#[derive(Clone)]
-pub struct FanCurveFrame {
- pub container: Frame,
- adjustment_1: Adjustment,
- adjustment_2: Adjustment,
- adjustment_3: Adjustment,
- adjustment_4: Adjustment,
- adjustment_5: Adjustment,
-}
-
-impl FanCurveFrame {
- pub fn new() -> Self {
- let container = Frame::new(Some("Fan Curve"));
-
- container.set_margin_start(10);
- container.set_margin_end(10);
- container.set_margin_bottom(10);
- container.set_margin_top(10);
-
- container.set_label_align(0.35, 0.5);
-
- // container.set_shadow_type(ShadowType::None);
- //
- let root_grid = Grid::new();
-
- // PWM Percentage Labels
- {
- root_grid.attach(
- &{
- let label = Label::new(Some("PWM %"));
- label.set_angle(90.0);
- label.set_vexpand(true); // This expands the entire top section of the grid, including the scales
- label
- },
- 0,
- 0,
- 1,
- 5,
- );
-
- root_grid.attach(
- &{
- let label = Label::new(Some("0"));
- label.set_angle(90.0);
- label
- },
- 1,
- 4,
- 1,
- 1,
- );
- root_grid.attach(
- &{
- let label = Label::new(Some("25"));
- label.set_angle(90.0);
- label
- },
- 1,
- 3,
- 1,
- 1,
- );
- root_grid.attach(
- &{
- let label = Label::new(Some("50"));
- label.set_angle(90.0);
- label
- },
- 1,
- 2,
- 1,
- 1,
- );
- root_grid.attach(
- &{
- let label = Label::new(Some("75"));
- label.set_angle(90.0);
- label
- },
- 1,
- 1,
- 1,
- 1,
- );
- root_grid.attach(
- &{
- let label = Label::new(Some("100"));
- label.set_angle(90.0);
- label
- },
- 1,
- 0,
- 1,
- 1,
- );
- }
-
- // Temperature threshold labels
- {
- root_grid.attach(
- &{
- let label = Label::new(Some("Temperature °C"));
- label.set_hexpand(true);
- label
- },
- 2,
- 7,
- 5,
- 1,
- );
-
- root_grid.attach(&Label::new(Some("20")), 2, 6, 1, 1);
- root_grid.attach(&Label::new(Some("40")), 3, 6, 1, 1);
- root_grid.attach(&Label::new(Some("60")), 4, 6, 1, 1);
- root_grid.attach(&Label::new(Some("80")), 5, 6, 1, 1);
- root_grid.attach(&Label::new(Some("100")), 6, 6, 1, 1);
- }
-
- // The actual adjustments
- let adjustment_1 = Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0); // 20 °C
- let adjustment_2 = Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0); // 40 °C
- let adjustment_3 = Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0); // 60 °C
- let adjustment_4 = Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0); // 80 °C
- let adjustment_5 = Adjustment::new(0.0, 0.0, 100.0, 1.0, 0.0, 0.0); // 100 °C
-
- // Scales for the adjustments
- {
- let adjustments = [
- &adjustment_1,
- &adjustment_2,
- &adjustment_3,
- &adjustment_4,
- &adjustment_5,
- ];
-
- for i in 0..adjustments.len() {
- let adj = adjustments[i];
-
- root_grid.attach(
- &{
- let scale = Scale::new(Orientation::Vertical, Some(adj));
- scale.set_draw_value(false);
- scale.set_inverted(true);
- scale
- },
- i as i32 + 2,
- 0,
- 1,
- 5,
- );
- }
- }
-
- container.add(&root_grid);
-
- Self {
- container,
- adjustment_1,
- adjustment_2,
- adjustment_3,
- adjustment_4,
- adjustment_5,
- }
- }
-
- pub fn set_curve(&self, curve: &BTreeMap) {
- self.adjustment_1.set_value(*curve.get(&20).unwrap());
- self.adjustment_2.set_value(*curve.get(&40).unwrap());
- self.adjustment_3.set_value(*curve.get(&60).unwrap());
- self.adjustment_4.set_value(*curve.get(&80).unwrap());
- self.adjustment_5.set_value(*curve.get(&100).unwrap());
- }
-
- pub fn get_curve(&self) -> BTreeMap {
- let mut curve = BTreeMap::new();
-
- curve.insert(20, self.adjustment_1.value());
- curve.insert(40, self.adjustment_2.value());
- curve.insert(60, self.adjustment_3.value());
- curve.insert(80, self.adjustment_4.value());
- curve.insert(100, self.adjustment_5.value());
-
- curve
- }
-
- pub fn show(&self) {
- log::info!("Manual fan control enaged, showing fan curve");
- self.container.set_visible(true);
- }
-
- pub fn hide(&self) {
- log::info!("Manual fan control disenaged, hiding fan curve");
- self.container.set_visible(false);
- }
-
- pub fn connect_adjusted(&self, f: F) {
- let adjustments = [
- &self.adjustment_1,
- &self.adjustment_2,
- &self.adjustment_3,
- &self.adjustment_4,
- &self.adjustment_5,
- ];
-
- for adj in adjustments.iter() {
- let f = f.clone();
- adj.connect_value_changed(move |_| {
- f();
- });
- }
- }
-}
diff --git a/gui/src/main.rs b/gui/src/main.rs
deleted file mode 100644
index 359092a6..00000000
--- a/gui/src/main.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use std::thread;
-
-use app::App;
-use daemon::{daemon_connection::DaemonConnection, Daemon};
-use gtk::prelude::*;
-use gtk::*;
-
-mod app;
-
-fn main() {
- env_logger::init();
- if gtk::init().is_err() {
- panic!("Cannot initialize GTK");
- }
-
- let connection = connect_daemon();
-
- ask_for_online_update(&connection);
-
- let app = App::new(connection);
-
- app.run().unwrap();
-}
-
-fn ask_for_online_update(connection: &DaemonConnection) {
- let mut config = connection.get_config().unwrap();
-
- if let None = config.allow_online_update {
- log::trace!("Online access permission not configured! Showing the dialog");
-
- let diag = MessageDialog::new(
- None::<&Window>,
- DialogFlags::empty(),
- MessageType::Warning,
- ButtonsType::YesNo,
- "Do you wish to use the online database for GPU identification?",
- );
- match diag.run() {
- ResponseType::Yes => config.allow_online_update = Some(true),
- ResponseType::No => config.allow_online_update = Some(false),
- _ => unreachable!(),
- }
- diag.hide();
-
- connection.set_config(config).unwrap();
- }
-}
-
-fn connect_daemon() -> DaemonConnection {
- match DaemonConnection::new() {
- Ok(connection) => {
- println!("Connection to daemon established");
- connection
- }
- Err(e) => {
- println!("Error {:?} connecting to daemon", e);
- println!("Starting unprivileged daemon instance");
-
- thread::spawn(move || {
- let daemon = Daemon::new(true);
- daemon.listen();
- });
-
- let dialog = MessageDialog::new(
- None::<>k::Window>,
- DialogFlags::empty(),
- gtk::MessageType::Warning,
- gtk::ButtonsType::Ok,
- "Unable to connect to daemon. Running in unprivileged mode.",
- );
-
- dialog.run();
- dialog.close();
-
- DaemonConnection::new().unwrap()
- }
- }
-}
diff --git a/lact-cli/Cargo.toml b/lact-cli/Cargo.toml
new file mode 100644
index 00000000..638115ca
--- /dev/null
+++ b/lact-cli/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "lact-cli"
+version = "0.2.0"
+edition = "2021"
+
+[dependencies]
+lact-client = { path = "../lact-client" }
+anyhow = "1.0.69"
+clap = { version = "4.1.6", features = ["derive"] }
diff --git a/lact-cli/src/args.rs b/lact-cli/src/args.rs
new file mode 100644
index 00000000..6ac7e074
--- /dev/null
+++ b/lact-cli/src/args.rs
@@ -0,0 +1,35 @@
+use clap::{Parser, Subcommand};
+use lact_client::DaemonClient;
+
+#[derive(Parser)]
+#[command(author, version, about)]
+pub struct CliArgs {
+ pub gpu_id: Option,
+ #[command(subcommand)]
+ pub subcommand: CliCommand,
+}
+
+#[derive(Subcommand)]
+pub enum CliCommand {
+ /// List GPUs
+ ListGpus,
+ /// Show GPU info
+ Info,
+}
+
+impl CliArgs {
+ pub fn gpu_ids(&self, client: &DaemonClient) -> Vec {
+ match self.gpu_id {
+ Some(ref id) => vec![id.clone()],
+ None => {
+ let buffer = client.list_devices().expect("Could not list GPUs");
+ buffer
+ .inner()
+ .expect("Could not deserialize GPUs response")
+ .into_iter()
+ .map(|entry| entry.id.to_owned())
+ .collect()
+ }
+ }
+ }
+}
diff --git a/lact-cli/src/lib.rs b/lact-cli/src/lib.rs
new file mode 100644
index 00000000..3ff01101
--- /dev/null
+++ b/lact-cli/src/lib.rs
@@ -0,0 +1,49 @@
+pub mod args;
+
+use anyhow::{Context, Result};
+use args::{CliArgs, CliCommand};
+use lact_client::DaemonClient;
+
+pub fn run(args: CliArgs) -> Result<()> {
+ let client = DaemonClient::connect()?;
+
+ let f = match args.subcommand {
+ CliCommand::ListGpus => list_gpus,
+ CliCommand::Info => info,
+ };
+ f(&args, &client)
+}
+
+fn list_gpus(_: &CliArgs, client: &DaemonClient) -> Result<()> {
+ let buffer = client.list_devices()?;
+ for entry in buffer.inner()? {
+ let id = entry.id;
+ if let Some(name) = entry.name {
+ println!("{id} ({name})");
+ } else {
+ println!("{id}");
+ }
+ }
+ Ok(())
+}
+
+fn info(args: &CliArgs, client: &DaemonClient) -> Result<()> {
+ for id in args.gpu_ids(client) {
+ let info_buffer = client.get_device_info(&id)?;
+ let info = info_buffer.inner()?;
+ let pci_info = info.pci_info.context("GPU reports no pci info")?;
+
+ if let Some(ref vendor) = pci_info.device_pci_info.vendor {
+ println!("GPU Vendor: {vendor}");
+ }
+ if let Some(ref model) = pci_info.device_pci_info.model {
+ println!("GPU Model: {model}");
+ }
+ println!("Driver in use: {}", info.driver);
+ if let Some(ref vbios_version) = info.vbios_version {
+ println!("VBIOS version: {vbios_version}");
+ }
+ println!("Link: {:?}", info.link_info);
+ }
+ Ok(())
+}
diff --git a/lact-client/Cargo.toml b/lact-client/Cargo.toml
new file mode 100644
index 00000000..804b08e6
--- /dev/null
+++ b/lact-client/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "lact-client"
+version = "0.2.0"
+edition = "2021"
+
+[dependencies]
+lact-schema = { path = "../lact-schema" }
+anyhow = "1.0.69"
+nix = { version = "0.26.2", default-features = false }
+serde = "1.0.152"
+tracing = "0.1.37"
+serde_json = "1.0.93"
diff --git a/lact-client/src/lib.rs b/lact-client/src/lib.rs
new file mode 100644
index 00000000..55a32d05
--- /dev/null
+++ b/lact-client/src/lib.rs
@@ -0,0 +1,143 @@
+#[macro_use]
+mod macros;
+
+pub use lact_schema as schema;
+
+use anyhow::{anyhow, Context};
+use nix::unistd::getuid;
+use schema::{
+ request::SetClocksCommand, ClocksInfo, DeviceInfo, DeviceListEntry, DeviceStats, FanCurveMap,
+ PerformanceLevel, Request, Response, SystemInfo,
+};
+use serde::Deserialize;
+use std::{
+ io::{BufRead, BufReader, Write},
+ marker::PhantomData,
+ ops::DerefMut,
+ os::unix::net::UnixStream,
+ path::PathBuf,
+ sync::{Arc, Mutex},
+};
+use tracing::info;
+
+#[derive(Clone)]
+pub struct DaemonClient {
+ stream: Arc, UnixStream)>>,
+ pub embedded: bool,
+}
+
+impl DaemonClient {
+ pub fn connect() -> anyhow::Result {
+ let path =
+ get_socket_path().context("Could not connect to daemon: socket file not found")?;
+ info!("connecting to service at {path:?}");
+ let stream = UnixStream::connect(path).context("Could not connect to daemon")?;
+ Self::from_stream(stream, false)
+ }
+
+ pub fn from_stream(stream: UnixStream, embedded: bool) -> anyhow::Result {
+ let reader = BufReader::new(stream.try_clone()?);
+ Ok(Self {
+ stream: Arc::new(Mutex::new((reader, stream))),
+ embedded,
+ })
+ }
+
+ fn make_request<'a, T: Deserialize<'a>>(
+ &self,
+ request: Request,
+ ) -> anyhow::Result> {
+ let mut stream_guard = self.stream.lock().map_err(|err| anyhow!("{err}"))?;
+ let (reader, writer) = stream_guard.deref_mut();
+
+ if !reader.buffer().is_empty() {
+ return Err(anyhow!("Another request was not processed properly"));
+ }
+
+ let request_payload = serde_json::to_string(&request)?;
+ writer.write_all(request_payload.as_bytes())?;
+ writer.write_all(b"\n")?;
+
+ let mut response_payload = String::new();
+ reader.read_line(&mut response_payload)?;
+
+ Ok(ResponseBuffer {
+ buf: response_payload,
+ _phantom: PhantomData,
+ })
+ }
+
+ pub fn list_devices<'a>(&self) -> anyhow::Result>>> {
+ self.make_request(Request::ListDevices)
+ }
+
+ pub fn set_fan_control(
+ &self,
+ id: &str,
+ enabled: bool,
+ curve: Option,
+ ) -> anyhow::Result<()> {
+ self.make_request::<()>(Request::SetFanControl { id, enabled, curve })?
+ .inner()?;
+ Ok(())
+ }
+
+ pub fn set_power_cap(&self, id: &str, cap: Option) -> anyhow::Result<()> {
+ self.make_request(Request::SetPowerCap { id, cap })?.inner()
+ }
+
+ request_plain!(get_system_info, SystemInfo, SystemInfo);
+ request_with_id!(get_device_info, DeviceInfo, DeviceInfo);
+ request_with_id!(get_device_stats, DeviceStats, DeviceStats);
+ request_with_id!(get_device_clocks_info, DeviceClocksInfo, ClocksInfo);
+
+ pub fn set_performance_level(
+ &self,
+ id: &str,
+ performance_level: PerformanceLevel,
+ ) -> anyhow::Result<()> {
+ self.make_request(Request::SetPerformanceLevel {
+ id,
+ performance_level,
+ })?
+ .inner()
+ }
+
+ pub fn set_clocks_value(&self, id: &str, command: SetClocksCommand) -> anyhow::Result<()> {
+ self.make_request(Request::SetClocksValue { id, command })?
+ .inner()
+ }
+}
+
+fn get_socket_path() -> Option {
+ let root_path = PathBuf::from("/var/run/lactd.sock");
+
+ if root_path.exists() {
+ return Some(root_path);
+ }
+
+ let uid = getuid();
+ let user_path = PathBuf::from(format!("/var/run/user/{}/lactd.sock", uid));
+
+ if user_path.exists() {
+ Some(user_path)
+ } else {
+ None
+ }
+}
+
+pub struct ResponseBuffer {
+ buf: String,
+ _phantom: PhantomData,
+}
+
+impl<'a, T: Deserialize<'a>> ResponseBuffer {
+ pub fn inner(&'a self) -> anyhow::Result {
+ let response: Response = serde_json::from_str(&self.buf)
+ .context("Could not deserialize response from daemon")?;
+ match response {
+ Response::Ok(data) => Ok(data),
+ Response::Error(err) => Err(anyhow!("Got error from daemon: {err}")),
+ }
+ }
+}
diff --git a/lact-client/src/macros.rs b/lact-client/src/macros.rs
new file mode 100644
index 00000000..1895899a
--- /dev/null
+++ b/lact-client/src/macros.rs
@@ -0,0 +1,15 @@
+macro_rules! request_with_id {
+ ($name:ident, $variant:ident, $response:ty) => {
+ pub fn $name(&self, id: &str) -> anyhow::Result> {
+ self.make_request(Request::$variant { id })
+ }
+ };
+}
+
+macro_rules! request_plain {
+ ($name:ident, $variant:ident, $response:ty) => {
+ pub fn $name(&self) -> anyhow::Result> {
+ self.make_request(Request::$variant)
+ }
+ };
+}
diff --git a/lact-daemon/Cargo.toml b/lact-daemon/Cargo.toml
new file mode 100644
index 00000000..b6ca2024
--- /dev/null
+++ b/lact-daemon/Cargo.toml
@@ -0,0 +1,36 @@
+[package]
+name = "lact-daemon"
+version = "0.2.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+amdgpu-sysfs = { version = "0.9.3", features = ["serde"] }
+anyhow = "1.0"
+bincode = "1.3"
+nix = "0.26"
+pciid-parser = { version = "0.6", features = ["serde"] }
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+serde_yaml = "0.9"
+tokio = { version = "1.25.0", features = [
+ "rt",
+ "macros",
+ "net",
+ "io-util",
+ "time",
+ "signal",
+ "sync",
+] }
+tracing = "0.1"
+tracing-subscriber = "0.3"
+vulkano = { git = "https://github.com/vulkano-rs/vulkano" }
+lact-schema = { path = "../lact-schema" }
+futures = { version = "0.3.26", default-features = false, features = [
+ "std",
+ "alloc",
+] }
+serde_with = { version = "2.2.0", default-features = false, features = [
+ "macros",
+] }
diff --git a/lact-daemon/src/config.rs b/lact-daemon/src/config.rs
new file mode 100644
index 00000000..1e121622
--- /dev/null
+++ b/lact-daemon/src/config.rs
@@ -0,0 +1,126 @@
+use crate::server::gpu_controller::fan_control::FanCurve;
+use anyhow::Context;
+use lact_schema::PerformanceLevel;
+use nix::unistd::getuid;
+use serde::{Deserialize, Serialize};
+use serde_with::skip_serializing_none;
+use std::{collections::HashMap, env, fs, path::PathBuf};
+use tracing::debug;
+
+const FILE_NAME: &str = "config.yaml";
+const DEFAULT_ADMIN_GROUPS: [&str; 2] = ["wheel", "sudo"];
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
+pub struct Config {
+ pub daemon: Daemon,
+ pub gpus: HashMap,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+pub struct Daemon {
+ pub log_level: String,
+ pub admin_groups: Vec,
+}
+
+impl Default for Daemon {
+ fn default() -> Self {
+ Self {
+ log_level: "info".to_owned(),
+ admin_groups: DEFAULT_ADMIN_GROUPS.map(str::to_owned).to_vec(),
+ }
+ }
+}
+
+#[skip_serializing_none]
+#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
+pub struct Gpu {
+ pub fan_control_enabled: bool,
+ pub fan_control_settings: Option,
+ pub power_cap: Option,
+ pub performance_level: Option,
+ pub max_core_clock: Option,
+ pub max_memory_clock: Option,
+ pub max_voltage: Option,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub struct FanControlSettings {
+ pub temperature_key: String,
+ pub interval_ms: u64,
+ pub curve: FanCurve,
+}
+
+impl Config {
+ pub fn load() -> anyhow::Result