feat: add Flatpak package (#519)

* feat: WIP

* feat: add wip manifest

* fix: replace /var/run with /run

* feat: add flatpak build to github actions

* feat: add flatpak setup script

* fix: build in release

* chore: check autostart mark by default

* feat: update app id

* chore: merge flatpak manifest modules

* chore: add cleanup section

* chore: update manifest file

* chore: pin github actions to specific commits

* chore: update app id again

* doc: add flatpak documentation

* chore: metainfo updates

* fix: desktop file entrypoint

* doc: add service permissions note to flatpak

* chore: improve flatpak manifest

* fix: libdrm x-checker-data indentation
This commit is contained in:
Ilya Zlobintsev
2025-04-04 21:38:19 +03:00
committed by GitHub
parent 17a7b61fdc
commit 658e4930ea
34 changed files with 4703 additions and 158 deletions
+21 -9
View File
@@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Import gpg key
run: |
@@ -80,11 +80,24 @@ jobs:
gpg --armor --export > $PWD/release-artifacts/lact.pubkey
- name: Upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ matrix.target-os }}-${{ matrix.recipe }}
path: release-artifacts/*
build-flatpak:
runs-on: ubuntu-latest
container:
image: bilelmoussaoui/flatpak-github-actions:gnome-47
options: --privileged
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: flatpak/flatpak-github-actions/flatpak-builder@fc80c13788c1ba0f45add99b19cf26b616ccab4f # v6
with:
bundle: io.github.ilya_zlobintsev.LACT.flatpak
manifest-path: flatpak/io.github.ilya_zlobintsev.LACT.yaml
cache-key: flatpak-builder-${{ github.sha }}
create-test-release:
needs: build-packages
runs-on: ubuntu-latest
@@ -92,15 +105,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
path: downloaded-artifacts/
- name: Create release
uses: ncipollo/release-action@v1.12.0
uses: ncipollo/release-action@a2e71bdd4e7dab70ca26a852f29600c98b33153e # v1.12.0
with:
removeArtifacts: true
allowUpdates: true
@@ -117,7 +130,6 @@ jobs:
git push -f origin test-build
shell: bash
create-stable-release:
needs: build-packages
runs-on: ubuntu-latest
@@ -125,15 +137,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Download artifacts
uses: actions/download-artifact@v4
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
with:
path: downloaded-artifacts/
- name: Create release
uses: ncipollo/release-action@v1.12.0
uses: ncipollo/release-action@a2e71bdd4e7dab70ca26a852f29600c98b33153e # v1.12.0
with:
artifacts: "downloaded-artifacts/*/*"
name: ${{ github.ref_name }}
+2 -2
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3
- name: Install yq
run: |
sudo curl -L https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64 -o /usr/local/bin/yq
@@ -40,7 +40,7 @@ jobs:
git commit -m "chore: Update spec files for release ${{ github.event.release.tag_name }}"
git push origin $branch_name
- name: Create Pull Request
uses: actions/github-script@v6
uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6
with:
script: |
const { repo, owner } = context.repo;
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2
- name: Update repos
run: sudo apt update
- name: Install dependencies
@@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-24.04
if: ${{ github.event_name == 'push' || !github.event.pull_request.draft }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@ee0669bd1cc54295c223e0bb666b733df41de1c5 # v2
- name: install rustfmt
run: rustup component add rustfmt
- name: Check formatting
+2
View File
@@ -6,3 +6,5 @@ AppDir/
appimage-build/
*.stignore
pkg/output
build/
.flatpak-builder/
Generated
+7
View File
@@ -383,6 +383,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af"
[[package]]
name = "configparser"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b"
[[package]]
name = "console"
version = "0.15.11"
@@ -1260,6 +1266,7 @@ name = "lact"
version = "0.7.3"
dependencies = [
"anyhow",
"configparser",
"divan",
"lact-cli",
"lact-daemon",
+8 -6
View File
@@ -16,9 +16,10 @@ build-release-headless:
install-resources:
install -Dm644 res/lactd.service $(DESTDIR)$(PREFIX)/lib/systemd/system/lactd.service
install -Dm644 res/io.github.lact-linux.desktop $(DESTDIR)$(PREFIX)/share/applications/io.github.lact-linux.desktop
install -Dm644 res/io.github.lact-linux.png $(DESTDIR)$(PREFIX)/share/pixmaps/io.github.lact-linux.png
install -Dm644 res/io.github.lact-linux.svg $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
install -Dm644 res/io.github.ilya_zlobintsev.LACT.desktop $(DESTDIR)$(PREFIX)/share/applications/io.github.ilya_zlobintsev.LACT.desktop
install -Dm644 res/io.github.ilya_zlobintsev.LACT.png $(DESTDIR)$(PREFIX)/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
install -Dm644 res/io.github.ilya_zlobintsev.LACT.svg $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
install -Dm644 res/io.github.ilya_zlobintsev.LACT.metainfo.xml $(DESTDIR)$(PREFIX)/share/metainfo/io.github.ilya_zlobintsev.LACT.metainfo.xml
install: install-resources
install -Dm755 target/release/lact $(DESTDIR)$(PREFIX)/bin/lact
@@ -29,6 +30,7 @@ install-debug: install-resources
uninstall:
rm $(DESTDIR)$(PREFIX)/bin/lact
rm $(DESTDIR)$(PREFIX)/lib/systemd/system/lactd.service
rm $(DESTDIR)$(PREFIX)/share/applications/io.github.lact-linux.desktop
rm $(DESTDIR)$(PREFIX)/share/pixmaps/io.github.lact-linux.png
rm $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
rm $(DESTDIR)$(PREFIX)/share/applications/io.github.ilya_zlobintsev.LACT.desktop
rm $(DESTDIR)$(PREFIX)/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
rm $(DESTDIR)$(PREFIX)/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
rm $(DESTDIR)$(PREFIX)/share/metainfo/io.github.ilya_zlobintsev.LACT.metainfo.xml
+150 -86
View File
@@ -1,14 +1,15 @@
# Linux GPU Control Application
<img src="res/io.github.lact-linux.png" alt="icon" width="100"/>
<img src="res/io.github.ilya_zlobintsev.LACT.png" alt="icon" width="100"/>
This application allows you to control your AMD, Nvidia or Intel GPU on a Linux system.
This application allows you to control your AMD, Nvidia or Intel GPU on a Linux
system.
| GPU info | Overclocking | Fan control |
|----------------------------------------------|----------------------------------------------|---------------------------------------------|
|![image](https://i.imgur.com/gur90cK.png)|![image](https://i.imgur.com/BAL3MgC.png)|![image](https://i.imgur.com/VsAVdOR.png)|
| Historical data |
|![image](https://i.imgur.com/GOmKh1M.png)|
| GPU info | Overclocking | Fan control |
| ----------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| ![image](https://i.imgur.com/gur90cK.png) | ![image](https://i.imgur.com/BAL3MgC.png) | ![image](https://i.imgur.com/VsAVdOR.png) |
| Historical data | | |
| ![image](https://i.imgur.com/GOmKh1M.png) | | |
Current features:
@@ -18,9 +19,11 @@ Current features:
- Overclocking (GPU/VRAM clockspeed and voltage)
- Power states configuration (AMD only)
All of the functionality works regardless of the desktop session (there is no dependency on X11 extensions).
All of the functionality works regardless of the desktop session (there is no
dependency on X11 extensions).
# Quick links
- [Installation](#installation)
- [Hardware support](https://github.com/ilya-zlobintsev/LACT/wiki/Hardware-Support)
- [Enable overclocking on AMD](https://github.com/ilya-zlobintsev/LACT/wiki/Overclocking-(AMD))
@@ -31,85 +34,127 @@ All of the functionality works regardless of the desktop session (there is no de
# Installation
- Arch Linux: Install the package from official repositories: `pacman -S lact` (or `lact-git` from AUR for development builds).
- Debian/Ubuntu/Derivatives: Download a .deb from [releases](https://github.com/ilya-zlobintsev/LACT/releases/).
- Arch Linux: Install the package from official repositories: `pacman -S lact`
(or `lact-git` from AUR for development builds).
- Debian/Ubuntu/Derivatives: 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: use the [Copr repository](https://copr.fedorainfracloud.org/coprs/ilyaz/LACT/), or download an RPM from [releases](https://github.com/ilya-zlobintsev/LACT/releases/).
- Gentoo: Available in [GURU](https://github.com/gentoo/guru/tree/master/sys-apps/lact).
- OpenSUSE: an RPM is available in [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: use the
[Copr repository](https://copr.fedorainfracloud.org/coprs/ilyaz/LACT/), or
download an RPM from
[releases](https://github.com/ilya-zlobintsev/LACT/releases/).
- Gentoo: Available in
[GURU](https://github.com/gentoo/guru/tree/master/sys-apps/lact).
- OpenSUSE: an RPM is available in
[releases](https://github.com/ilya-zlobintsev/LACT/releases/).
Only tumbleweed is supported as leap does not have the required dependencies in the repos.
- NixOS: There is a package available in [nixpkgs](https://search.nixos.org/packages?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=lact)
- Otherwise, build from source.
Only tumbleweed is supported as leap does not have the required dependencies
in the repos.
- NixOS: There is a package available in
[nixpkgs](https://search.nixos.org/packages?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=lact)
- Flatpak (universal): Available in [releases](https://github.com/ilya-zlobintsev/LACT/releases/) (not yet published on Flathub).
**Why is there no AppImage/Flatpak/other universal format?**
See [here](./pkg/README.md#why-is-there-no-appimageflatpakdocker).
See the [Flatpak documentation](./flatpak/README.md) for setup notes.
- Build from source.
Note: Nvidia support requires the Nvidia proprietary driver with CUDA libraries installed.
Note: Nvidia support requires the Nvidia proprietary driver with CUDA libraries
installed.
## Development builds
To get latest fixes or features that have not yet been released in a stable version, there are packages built from the latest commit that you can install from the [test release](https://github.com/ilya-zlobintsev/LACT/releases/tag/test-build) or using the `lact-git` AUR package on Arch-based distros.
To get latest fixes or features that have not yet been released in a stable
version, there are packages built from the latest commit that you can install
from the
[test release](https://github.com/ilya-zlobintsev/LACT/releases/tag/test-build)
or using the `lact-git` AUR package on Arch-based distros.
Note: the date of the test release is not the date when the packages were built, the actual date is specified next to the attached package files.
Note: the date that GitHub shows next to the test release is not when the packages were built,
the actual date is specified next to the attached package files.
# Usage
Enable and start the service (otherwise you won't be able to change any settings):
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 GUI to change settings and view information.
# Hardware support
See the [Wiki page](https://github.com/ilya-zlobintsev/LACT/wiki/Hardware-Support)
See the
[Wiki page](https://github.com/ilya-zlobintsev/LACT/wiki/Hardware-Support)
# 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_group` and `admin_user` to specify who has access to the daemon)
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_group` and `admin_user` to specify who has access
to the daemon)
See [CONFIG.md](./docs/CONFIG.md) for more information.
**Socket permissions setup:**
By default, LACT uses either ether the `wheel` or `sudo` group (whichever is available) for the ownership of the unix socket that the GUI needs to connect to.
By default, LACT uses either ether the `wheel` or `sudo` group (whichever is
available) for the ownership of the unix socket that the GUI needs to connect
to.
On most desktop configurations (such as the default setup on Arch-based, most Debian-based or Fedora systems) this includes the default user, so you do not need to configure this.
On most desktop configurations (such as the default setup on Arch-based, most
Debian-based or Fedora systems) this includes the default user, so you do not
need to configure this.
However, some systems may have different user configuration. In particular, this has been reported to be a problem on OpenSUSE.
However, some systems may have different user configuration. In particular, this
has been reported to be a problem on OpenSUSE.
To fix socket permissions in such configurations, edit `/etc/lact/config.yaml`
and under the `daemon` section either:
To fix socket permissions in such configurations, edit `/etc/lact/config.yaml` and under the `daemon` section either:
- Set `admin_user` to your username
- Set `admin_group` to a group that your user is a part of
Then restart the service (`sudo systemctl restart lactd`).
- Set `admin_group` to a group that your user is a part of Then restart the
service (`sudo systemctl restart lactd`).
# Overclocking (AMD)
Some functionality requires enabling an option in the amdgpu driver, see the [wiki page](https://github.com/ilya-zlobintsev/LACT/wiki/Overclocking-(AMD)) for more information.
Some functionality requires enabling an option in the amdgpu driver, see the
[wiki page](https://github.com/ilya-zlobintsev/LACT/wiki/Overclocking-(AMD)) for
more information.
## Power profiles daemon note!
If you are using `power-profiles-daemon` (which is installed by default on many distributions), by default it will override the amdgpu performance level setting according to its own profile.
If you are using `power-profiles-daemon` (which is installed by default on many
distributions), by default it will override the amdgpu performance level setting
according to its own profile.
To avoid this, create a file at
`/etc/systemd/system/power-profiles-daemon.service.d/override.conf` with the
following contents:
To avoid this, create a file at `/etc/systemd/system/power-profiles-daemon.service.d/override.conf` with the following contents:
```
[Service]
ExecStart=
ExecStart=/usr/libexec/power-profiles-daemon --block-action=amdgpu_dpm
```
Note: the `/usr/libexec` path might be different on your system, check it in `systemctl status power-profiles-daemon`
Note: the `/usr/libexec` path might be different on your system, check it in
`systemctl status power-profiles-daemon`
See https://github.com/ilya-zlobintsev/LACT/issues/370 for more information.
# Suspend/Resume
As some of the GPU settings may get reset when suspending the system, LACT will reload them on system resume. This may not work on distributions which don't use systemd, as it relies on the `org.freedesktop.login2` DBus interface.
As some of the GPU settings may get reset when suspending the system, LACT will
reload them on system resume. This may not work on distributions which don't use
systemd, as it relies on the `org.freedesktop.login2` DBus interface.
# Building from source
Dependencies:
- rust 1.76+
- gtk 4.6+
- git
@@ -121,37 +166,47 @@ Dependencies:
- vulkan-tools
Command to install all dependencies:
- Fedora: `sudo dnf install rust cargo make git clang gtk4-devel libdrm-devel vulkan-tools`
- Arch: `sudo pacman -S --needed base-devel git clang make rust gtk4 hwdata vulkan-tools`
- Fedora:
`sudo dnf install rust cargo make git clang gtk4-devel libdrm-devel vulkan-tools`
- Arch:
`sudo pacman -S --needed base-devel git clang make rust gtk4 hwdata vulkan-tools`
Steps:
- `git clone https://github.com/ilya-zlobintsev/LACT && cd LACT`
- `make`
- `sudo make install`
It's possible to change which features LACT gets built with.
To do so, replace the `make` command with the following variation:
It's possible to change which features LACT gets built with. To do so, replace
the `make` command with the following variation:
Headless build with no GUI:
```
make build-release-headless
```
Build GUI with libadwaita support:
```
make build-release-libadwaita
```
# Remote management
It's possible to have the LACT daemon running on one machine, and then manage it remotely from another.
It's possible to have the LACT daemon running on one machine, and then manage it
remotely from another.
This is disabled by default, as the TCP connection **does not have any authentication or encryption mechanism!**
Make sure to only use it in trusted networks and/or set up appropriate firewall rules.
This is disabled by default, as the TCP connection **does not have any
authentication or encryption mechanism!** Make sure to only use it in trusted
networks and/or set up appropriate firewall rules.
To enable it, edit `/etc/lact/config.yaml` and add `tcp_listen_address` with your desired address and in the `daemon` section.
To enable it, edit `/etc/lact/config.yaml` and add `tcp_listen_address` with
your desired address and in the `daemon` section.
Example:
```yaml
daemon:
tcp_listen_address: 0.0.0.0:12853
@@ -162,68 +217,77 @@ daemon:
After this restart the service (`sudo systemctl restart lactd`).
To connect to a remote instance with the GUI, run it with `lact gui --tcp-address 192.168.1.10:12853`.
To connect to a remote instance with the GUI, run it with
`lact gui --tcp-address 192.168.1.10:12853`.
# CLI
There is also a cli available.
- List system GPUs:
- List system GPUs:
`lact cli list-gpus`
`lact cli list-gpus`
Example output:
Example output:
```
10DE:2704-1462:5110-0000:09:00.0 (AD103 [GeForce RTX 4080])
```
```
10DE:2704-1462:5110-0000:09:00.0 (AD103 [GeForce RTX 4080])
```
- Getting GPU information:
`lact cli info`
`lact cli info`
Example output:
Example output:
```
$ lact cli info
GPU 10DE:2704-1462:5110-0000:09:00.0:
=====================================
GPU Model: NVIDIA GeForce RTX 4080 (0x10DE:0x2704)
Card Manufacturer: Micro-Star International Co., Ltd. [MSI] (0x1462)
Card Model: Unknown (0x5110)
Driver Used: nvidia 570.124.04
VBIOS Version: 95.03.1E.00.60
VRAM Size: 16376 MiB
GPU Family: Ada
Cuda Cores: 9728
SM Count: 76
ROP Count: 112 (14 * 8)
VRAM Type: GDDR6x
VRAM Manufacturer: Micron
L2 Cache: 65536 KiB
Resizeable bar: Enabled
CPU Accessible VRAM: 16384
Link Speed: 8 GT/s PCIe gen 3 x8
```
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.
```
$ lact cli info
GPU 10DE:2704-1462:5110-0000:09:00.0:
=====================================
GPU Model: NVIDIA GeForce RTX 4080 (0x10DE:0x2704)
Card Manufacturer: Micro-Star International Co., Ltd. [MSI] (0x1462)
Card Model: Unknown (0x5110)
Driver Used: nvidia 570.124.04
VBIOS Version: 95.03.1E.00.60
VRAM Size: 16376 MiB
GPU Family: Ada
Cuda Cores: 9728
SM Count: 76
ROP Count: 112 (14 * 8)
VRAM Type: GDDR6x
VRAM Manufacturer: Micron
L2 Cache: 65536 KiB
Resizeable bar: Enabled
CPU Accessible VRAM: 16384
Link Speed: 8 GT/s PCIe gen 3 x8
```
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.
If you're having an issue with changing the GPU's configuration, it's highly recommended to include a debug snapshot in the bug report.
You can generate one using the option in the dropdown menu:
If you're having an issue with changing the GPU's configuration, it's highly
recommended to include a debug snapshot in the bug report. You can generate one
using the option in the dropdown menu:
![image](https://github.com/ilya-zlobintsev/LACT/assets/22796665/36dda5e3-981b-47e7-914e-6e29f30616b4)
The snapshot is an archive which includes the SysFS that LACT uses to interact with the GPU.
If there's a crash, run `lact gui` from the command line to get GUI logs, check daemon logs in `journalctl -u lactd` for errors,
and see `dmesg` for kernel logs that might include information about driver and system issues.
The snapshot is an archive which includes the SysFS that LACT uses to interact
with the GPU.
If there's a crash, run `lact gui` from the command line to get GUI logs, check
daemon logs in `journalctl -u lactd` for errors, and see `dmesg` for kernel logs
that might include information about driver and system issues.
# Other tools
Here's a list of other useful tools for AMD GPUs on Linux:
- [CoreCtrl](https://gitlab.com/corectrl/corectrl) - direct alternative to LACT, provides similar functionality in addition to CPU configuration with a Qt UI
- [amdgpu_top](https://github.com/Umio-Yasuno/amdgpu_top) - tool for detailed real-time statistics on AMD GPUs
- [Tuxclocker](https://github.com/Lurkki14/tuxclocker) - Qt overclocking tool, has support for AMD GPUs
- [CoreCtrl](https://gitlab.com/corectrl/corectrl) - direct alternative to LACT,
provides similar functionality in addition to CPU configuration with a Qt UI
- [amdgpu_top](https://github.com/Umio-Yasuno/amdgpu_top) - tool for detailed
real-time statistics on AMD GPUs
- [Tuxclocker](https://github.com/Lurkki14/tuxclocker) - Qt overclocking tool,
has support for AMD GPUs
+1 -1
View File
@@ -1,6 +1,6 @@
# Description
The LACT Daemon exposes a JSON API over a unix socket or TCP, available on `/var/run/lactd.sock` or an arbitrary TCP port. You can configure who has access to the unix socket in `/etc/lact/config.yaml` in the `daemon.admin_group` or `daemon.admin_user` field. The TCP listener is disabled by default for security reasons, see [this README section](../README.md#remote-management) for how to enable it.
The LACT Daemon exposes a JSON API over a unix socket or TCP, available on `/run/lactd.sock` or an arbitrary TCP port. You can configure who has access to the unix socket in `/etc/lact/config.yaml` in the `daemon.admin_group` or `daemon.admin_user` field. The TCP listener is disabled by default for security reasons, see [this README section](../README.md#remote-management) for how to enable it.
The API expects newline-separated JSON objects, and returns a JSON object for every request.
+48
View File
@@ -0,0 +1,48 @@
# Flatpak information
LACT is available as a Flatpak package.
However, due to sandbox restrictions, there are some extra steps needed to achieve full functionality.
LACT uses a system daemon to interact with the GPU and manage configuration.
For access to hardware and system settings the daemon needs to run as root.
When you run the flatpak and the daemon is not detected, you will get a prompt to install it outside of the sandbox.
This will automatically set up and start the system service. It is installed at `/etc/systemd/system/lactd.service`.
If the setup was successful, you will now be able to use all of the functionality.
Service status can be checked with `systemctl status lactd`.
It is also possible to skip the service setup if you want to use LACT only for information and monitoring. This can work entirely in the Flatpak sandbox and does not require extra permissions.
> Note: the setup script requires Polkit to be functional.
## Service permissions
The setup script will automatically configure the daemon in such a way that the user who ran the setup has access to it.
It will not happen if you had an existing LACT config before setting up the Flatpak.
In this scenario you have to manually edit `/etc/lact/config.yaml` and set `admin_user` in the `daemon` section.
See this [README section](../README.md#configuration) for more information.
**Flatpak specifically requires `admin_user` to be set** (and it is configured by default in the setup). Simply being part of a group like `wheel` does not grant the UI access to the daemon from Flatpak.
## Uninstall
To uninstall the flatpak-created service run the following commands:
```bash
sudo systemctl disable --now lactd
sudo rm /etc/systemd/system/lactd.service
```
## Implementation details
The service uses a binary distributed with the flatpak, but runs it outside of the sandbox.
This is achieved by first getting the location where the LACT flatpak and its flatpak runtime are located on the host.
These paths are used to run the daemon binary, while letting it use libraries provided by the flatpak runtime. This avoids any reliance on libraries being present or missing the host¹.
Additionally, a `flatpak run` wrapper command is provided to the service so that it can call `vulkaninfo` inside of the flatpak sandbox.
1. Nvidia's management library will still be loaded from the host, as it is not directly a part of the Flatpak runtime. The library is shipped with Nvidia drivers, so it is extremely unlikely that it is available in Flatpak while being missing on the host.
File diff suppressed because it is too large Load Diff
+124
View File
@@ -0,0 +1,124 @@
app-id: io.github.ilya_zlobintsev.LACT
runtime: org.gnome.Platform
runtime-version: "48"
sdk: org.gnome.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.rust-stable
- org.freedesktop.Sdk.Extension.llvm20
command: startup.sh
finish-args:
- --share=ipc
- --socket=fallback-x11
- --socket=wayland
- --device=dri
- --talk-name=org.freedesktop.Flatpak
- --filesystem=/run/lactd.sock
cleanup:
- /include
- /share/vulkan/registry
- /lib/*.a
- /lib/pkgconfig
modules:
- name: lact
buildsystem: simple
sources:
- generated-sources.json
- type: dir
path: "../"
skip:
- "target"
- "target_ra"
build-options:
append-path: "/usr/lib/sdk/rust-stable/bin:/usr/lib/sdk/llvm20/bin"
prepend-ld-library-path: "/usr/lib/sdk/llvm20/lib"
env:
CARGO_HOME: "/run/build/lact/cargo"
PREFIX: "/app"
build-commands:
- cargo --offline fetch --manifest-path Cargo.toml
- cargo --offline build -p lact --features flatpak --release
- make install
- install -Dm755 flatpak/startup.sh /app/bin/startup.sh
- sed -i -E 's/lact gui/startup.sh/' /app/share/applications/io.github.ilya_zlobintsev.LACT.desktop
modules:
- name: yad
config-opts:
- --enable-standalone
- --disable-icon-browser
- --disable-tools
sources:
- type: archive
url: https://github.com/v1cont/yad/releases/download/v14.1/yad-14.1.tar.xz
sha256: dde047a915cd8d3892c32b6ba031876f5cda673e01882c99613f043867c88133
x-checker-data:
type: anitya
project-id: 5280
url-template: https://github.com/v1cont/yad/releases/download/v$version/yad-$version.tar.xz
cleanup:
- /share/icons
modules:
- name: intltool
cleanup:
- '*'
sources:
- type: archive
url: https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz
sha256: 67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd
x-checker-data:
type: anitya
project-id: 1385
url-template: https://launchpad.net/intltool/trunk/$version/+download/intltool-$version.tar.gz
- name: libdrm
buildsystem: meson
builddir: true
config-opts:
- -Dtests=false
sources:
- type: archive
url: https://gitlab.freedesktop.org/mesa/drm/-/archive/libdrm-2.4.124/drm-libdrm-2.4.124.tar.gz
sha256: 49c077f3938147e7c321fe89255eb189c1be68f6ed0aa36e29d38e3db0e84e08
x-checker-data:
type: anitya
project-id: 1596
url-template: https://gitlab.freedesktop.org/mesa/drm/-/archive/libdrm-$version/drm-libdrm-$version.tar.gz
- name: vulkan-tools
buildsystem: cmake-ninja
config-opts:
- -DVULKAN_HEADERS_INSTALL_DIR=/app
- -DCMAKE_BUILD_TYPE=Release
- -DBUILD_CUBE=OFF
- -DBUILD_ICD=OFF
- -DBUILD_VULKANINFO=ON
sources:
- type: archive
url: https://github.com/KhronosGroup/Vulkan-Tools/archive/v1.4.311/Vulkan-Tools-1.4.311.tar.gz
sha256: 7113bc0c746b45072e269fada0d684b4ae9de609c38d9e764b59793b14120a7b
x-checker-data:
type: anitya
project-id: 242111
url-template: https://github.com/KhronosGroup/Vulkan-Tools/archive/v$version/Vulkan-Tools-$version.tar.gz
modules:
- name: volk
buildsystem: cmake-ninja
config-opts:
- -DVOLK_INSTALL=ON
sources:
- type: archive
url: https://github.com/zeux/volk/archive/vulkan-sdk-1.4.309.0.tar.gz
sha256: 1724924d8e3dccf0c508887edb79d56d9dd11b0738eab5a44e2fa95b8a9ebe1c
x-checker-data:
type: anitya
project-id: 370476
url-template: https://github.com/zeux/volk/archive/vulkan-sdk-$version.tar.gz
modules:
- name: vulkan-headers
buildsystem: cmake-ninja
sources:
- type: archive
url: https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.311/Vulkan-Headers-v1.4.311.tar.gz
sha256: 7989c360b870bcc2de52b9fd626fd2ba7a212fe177ade3aa3a10b2bcb61f8689
x-checker-data:
type: anitya
project-id: 88835
url-template: https://github.com/KhronosGroup/Vulkan-Headers/archive/v$version/Vulkan-Headers-v$version.tar.gz
+67
View File
@@ -0,0 +1,67 @@
#!/bin/env bash
set -e
DAEMON_SOCKET=/run/lactd.sock
UNIT_PATH=/etc/systemd/system/lactd.service
if [ ! -e "${DAEMON_SOCKET}" ]; then
echo "${DAEMON_SOCKET} does not exist, showing setup prompt"
set +e
YAD_OUTPUT=$(yad --title="LACT Flatpak Setup" \
--text="The LACT system service could not be found.
In order to edit GPU settings, LACT requires a service to be running as root.
This setup will install <u><tt>lactd.service</tt></u> outside of the Flatpak sandbox.
It is possible to skip this step if you wish to use LACT only for information and monitoring.
Do you wish to install the service?" \
--form \
--field "Autostart service at boot":CHK "TRUE")
EXIT_CODE=$?
set -e
if [ ${EXIT_CODE} -eq 0 ]; then
IFS="|" read -ra OPTIONS <<< "$YAD_OUTPUT"
AUTOSTART="${OPTIONS[0]}"
echo "Setting up the service with autostart ${AUTOSTART}"
UNIT="\
[Unit]
Description=AMDGPU Control Daemon (via Flatpak)
After=multi-user.target
[Service]
Environment=FLATPAK_INSTALL_USER=$USER
Environment=VULKANINFO_COMMAND=\"sudo -u $USER -s flatpak run --filesystem=/tmp --command=vulkaninfo io.github.ilya_zlobintsev.LACT\"
ExecStart=sh -c \"eval \$(sudo -u \$FLATPAK_INSTALL_USER -s flatpak run --command=lact io.github.ilya_zlobintsev.LACT flatpak generate-daemon-cmd)\"
Nice=-10
Restart=on-failure
[Install]
WantedBy=multi-user.target\
"
echo "${UNIT}" | flatpak-spawn --host pkexec tee "${UNIT_PATH}"
echo "Unit file created at ${UNIT_PATH}"
if [ "${AUTOSTART}" == "TRUE" ]; then
echo "Enabling the service with autostart"
flatpak-spawn --host pkexec sh -c "systemctl daemon-reload && systemctl enable --now lactd.service"
else
echo "Starting the service without autostart"
flatpak-spawn --host pkexec sh -c "systemctl daemon-reload && systemctl start lactd.service"
fi
yad --text 'The service has been started. Please run LACT again.' --button=OK:0
exit 0
else
echo "Service setup rejected, skipping"
fi
else
echo "${DAEMON_SOCKET} exists, skipping setup prompt"
fi
lact $@
+2 -2
View File
@@ -245,14 +245,14 @@ impl DaemonClient {
}
fn get_socket_path() -> Option<PathBuf> {
let root_path = PathBuf::from("/var/run/lactd.sock");
let root_path = PathBuf::from("/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));
let user_path = PathBuf::from(format!("/run/user/{}/lactd.sock", uid));
if user_path.exists() {
Some(user_path)
+5 -1
View File
@@ -76,10 +76,14 @@ pub struct Daemon {
impl Default for Daemon {
fn default() -> Self {
let admin_user = env::var("FLATPAK_INSTALL_USER")
.ok()
.filter(|user| !user.is_empty());
#[allow(deprecated)]
Self {
log_level: "info".to_owned(),
admin_user: None,
admin_user,
admin_group: find_existing_group(&DEFAULT_ADMIN_GROUPS),
admin_groups: vec![],
disable_clocks_cleanup: false,
+28 -9
View File
@@ -2,10 +2,9 @@ use anyhow::{anyhow, bail, Context};
use indexmap::{map::Entry, IndexMap};
use lact_schema::{GpuPciInfo, VulkanDriverInfo, VulkanInfo};
use serde::Deserialize;
use std::fs;
use tempfile::tempdir;
use std::{env, fs, path::Path};
use tokio::process::Command;
use tracing::trace;
use tracing::{error, trace};
include!(concat!(env!("OUT_DIR"), "/vulkan_constants.rs"));
@@ -14,14 +13,12 @@ pub async fn get_vulkan_info(pci_info: &GpuPciInfo) -> anyhow::Result<VulkanInfo
#[cfg(test)]
return Ok(VulkanInfo::default());
let workdir = tempdir().context("Could not create temp folder")?;
trace!("Reading vulkan info");
let vendor_id = u32::from_str_radix(&pci_info.device_pci_info.vendor_id, 16)?;
let device_id = u32::from_str_radix(&pci_info.device_pci_info.model_id, 16)?;
trace!("Reading vulkan info");
let summary_output = Command::new("vulkaninfo")
let summary_output = vulkaninfo_command()
.arg("--summary")
.output()
.await
@@ -44,9 +41,9 @@ pub async fn get_vulkan_info(pci_info: &GpuPciInfo) -> anyhow::Result<VulkanInfo
if u32::from_str_radix(entry.vendor_id, 16) == Ok(vendor_id)
&& u32::from_str_radix(entry.device_id, 16) == Ok(device_id)
{
let output = Command::new("vulkaninfo")
let output = vulkaninfo_command()
.arg(format!("--json={i}"))
.current_dir(workdir.path())
.current_dir("/tmp")
.output()
.await
.context("Could not read vulkan info for device")?;
@@ -64,11 +61,18 @@ pub async fn get_vulkan_info(pci_info: &GpuPciInfo) -> anyhow::Result<VulkanInfo
{
parse_legacy_devsim(devsim, &entry)
} else {
let file_path = workdir.path().join(entry.file_name());
let file_path = Path::new("/tmp").join(entry.file_name());
let manifest = fs::read_to_string(&file_path).with_context(|| {
format!("Could not read info file from '{}'", file_path.display())
})?;
if let Err(err) = fs::remove_file(&file_path) {
error!(
"could not clean up file at '{}' created by vulkaninfo: {err}",
file_path.display()
);
}
parse_manifest(&manifest, &entry)?
};
return Ok(manifest);
@@ -271,6 +275,21 @@ fn parse_summary(summary: &str) -> Vec<SummaryDeviceEntry> {
devices
}
fn vulkaninfo_command() -> Command {
if let Ok(custom_command) = env::var("VULKANINFO_COMMAND") {
let mut split = custom_command.split_ascii_whitespace();
let program = split
.next()
.expect("Could not parse provided vulkaninfo command");
let mut cmd = Command::new(program);
cmd.args(split);
cmd
} else {
Command::new("vulkaninfo")
}
}
#[cfg(test)]
mod tests {
use super::{parse_legacy_devsim, parse_summary, VulkanInfoDevSimManifest};
+2 -2
View File
@@ -10,9 +10,9 @@ use tracing::{debug, info};
pub fn get_socket_path() -> PathBuf {
let uid = getuid();
if uid.is_root() {
PathBuf::from_str("/var/run/lactd.sock").unwrap()
PathBuf::from_str("/run/lactd.sock").unwrap()
} else {
PathBuf::from_str(&format!("/var/run/user/{uid}/lactd.sock")).unwrap()
PathBuf::from_str(&format!("/run/user/{uid}/lactd.sock")).unwrap()
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ use tracing_subscriber::EnvFilter;
static CONFIG: SharedState<UiConfig> = SharedState::new();
const GUI_VERSION: &str = env!("CARGO_PKG_VERSION");
const APP_ID: &str = "io.github.lact-linux";
pub const APP_ID: &str = "io.github.ilya_zlobintsev.LACT";
pub fn run(args: GuiArgs) -> anyhow::Result<()> {
let env_filter = EnvFilter::builder()
+11
View File
@@ -16,6 +16,17 @@ pub enum Command {
Gui(GuiArgs),
/// Run the CLI
Cli(CliArgs),
/// Flatpak helper commands
Flatpak {
#[command(subcommand)]
cmd: FlatpakCommand,
},
}
#[derive(Subcommand)]
pub enum FlatpakCommand {
/// Generate a command that runs the daemon from flatpak
GenerateDaemonCmd,
}
#[derive(Default, Parser)]
+2
View File
@@ -6,6 +6,7 @@ edition = "2021"
[features]
default = ["lact-gui"]
adw = ["lact-gui/adw"]
flatpak = ["dep:configparser"]
[dependencies]
lact-daemon = { path = "../lact-daemon" }
@@ -13,6 +14,7 @@ lact-schema = { path = "../lact-schema", features = ["args"] }
lact-cli = { path = "../lact-cli" }
lact-gui = { path = "../lact-gui", optional = true }
anyhow = { workspace = true }
configparser = { version = "3.1.0", optional = true }
[dev-dependencies]
divan = { workspace = true }
+74
View File
@@ -0,0 +1,74 @@
// Inspired by https://github.com/ryanabx/flatpak-unsandbox/
use anyhow::{anyhow, bail, Context};
use configparser::ini::Ini;
use lact_schema::args::FlatpakCommand;
use std::{
path::{Component, Path, PathBuf},
process::Command,
};
pub fn cmd(cmd: FlatpakCommand) -> anyhow::Result<()> {
let info = get_flatpak_info()?;
match cmd {
FlatpakCommand::GenerateDaemonCmd => generate_daemon_cmd(&info),
}
}
fn generate_daemon_cmd(info: &Ini) -> anyhow::Result<()> {
let app_path = info
.get("Instance", "app-path")
.context("Could not get app path")?;
let runtime_path = info
.get("Instance", "runtime-path")
.context("Could not get runtime path")?;
let relative_ld_path = get_relative_ld_path()?;
let relative_ld_path_parts = relative_ld_path.components().collect::<Vec<Component>>();
let ld_path = format!("{runtime_path}/{}", relative_ld_path.display());
let runtime_lib_path = format!(
"{runtime_path}/{}",
relative_ld_path_parts[0..relative_ld_path_parts.len() - 1]
.iter()
.collect::<PathBuf>()
.display()
);
let app_bin_path = format!("{app_path}/bin");
let library_paths = format!("{app_path}/lib:{runtime_lib_path}");
println!("{ld_path} --library-path {library_paths} {app_bin_path}/lact daemon");
Ok(())
}
fn get_relative_ld_path() -> anyhow::Result<PathBuf> {
let out = Command::new("ldconfig").arg("-p").output()?;
for l in String::from_utf8(out.stdout)?.lines() {
if l.trim().starts_with("ld-linux") {
let path = l
.split(" => ")
.nth(1)
.context("Invalid ld-linux line")?
.trim();
let relative_path = Path::new(path).components().skip(2).collect();
return Ok(relative_path);
}
}
bail!("Could not find ld-linux inside of flatpak");
}
fn get_flatpak_info() -> anyhow::Result<Ini> {
let info_path = Path::new("/.flatpak-info");
if !info_path.exists() {
bail!("Not running inside of Flatpak");
}
let mut info = Ini::new();
info.load(info_path)
.map_err(|err| anyhow!("Could not read flatpak info: {err}"))?;
Ok(info)
}
+10
View File
@@ -1,3 +1,6 @@
#[cfg(feature = "flatpak")]
mod flatpak;
use lact_schema::args::{clap::Parser, Args, Command, GuiArgs};
fn main() -> anyhow::Result<()> {
@@ -10,6 +13,13 @@ fn main() -> anyhow::Result<()> {
Command::Daemon => lact_daemon::run(),
Command::Gui(gui_args) => run_gui(gui_args),
Command::Cli(cli_args) => lact_cli::run(cli_args),
#[allow(unused_variables)]
Command::Flatpak { cmd } => {
#[cfg(not(feature = "flatpak"))]
return Err(anyhow::anyhow!("Compiled without flatpak support"));
#[cfg(feature = "flatpak")]
flatpak::cmd(cmd)
}
}
}
+2 -22
View File
@@ -10,26 +10,6 @@ pkger -c .pkger.yml build lact
Generated packages will be placed in `pkg/output`.
# Why is there no AppImage/Flatpak/Docker?
# Flatpak
Unfortunately, due to the nature of the app that has 2 parts (daemon running as root and a GUI running as a user), none of the popular universal formats fit it very well.
---
Flatpak is mainly designed for graphical desktop applications, with support for user CLI apps as well.
It does not support services, and running a Flatpak as root is also problematic. This means that the LACT daemon can't run as Flatpak.
---
AppImage on the other hand can run as root. However it is also mainly designed for graphical apps where you download a run a single file.
This means that you would need to manually install a service file alongside the AppImage, though this could be automated with a script.
The bigger problem is that AppImages are built by taking the dependencies of the host system. Some things (primarly `glibc`) are usually not bundled with the image, which means that the recommended way to package things is by building the AppImage on the oldest possible system that you want your app to run on. This is not really possible with LACT, as it uses gtk4, which means that the "universal" AppImage would only run on modern distros anyway.
It is possible to bundle glibc with the AppImage by using [appimage-builder](https://appimage-builder.readthedocs.io/), which would enable the image to run on older systems. The problem is that the resulting file ends up being very large, and since AppImage extract itself on startup it means that it takes about 10 seconds to start every time even on a relatively powerful system. There are flags that allow AppImages to reuse files between restarts, but it ends up storing hundreds of megabytes of data on /tmp (which is stored in RAM on most systems). Overall it is not a very good user experience.
---
The daemon could run in a Docker container with little issue. However running graphical applications in Docker, while possible, is extremely inconvenient and doesn't integrate with the rest of the system.
---
All of this means that native packaging is currently the only feasible way to distribute LACT.
See [here](../flatpak/README.md) for Flatpak information.
+3 -3
View File
@@ -93,9 +93,9 @@ VERGEN_GIT_SHA=$LACT_COMMIT_HASH make install PREFIX=/usr DESTDIR=%{buildroot}
%doc README.md
/usr/bin/lact
/usr/lib/systemd/system/lactd.service
/usr/share/applications/io.github.lact-linux.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
/usr/share/pixmaps/io.github.lact-linux.png
/usr/share/applications/io.github.ilya_zlobintsev.LACT.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
/usr/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
%changelog
* $(date +"%a %b %d %Y") - $MAINTAINER - $GH_RELEASE_NAME - $GH_RELEASE_TAG
+3 -3
View File
@@ -29,9 +29,9 @@ VERGEN_GIT_SHA=942526e make install PREFIX=/usr DESTDIR=%{buildroot}
%doc README.md
/usr/bin/lact
/usr/lib/systemd/system/lactd.service
/usr/share/applications/io.github.lact-linux.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
/usr/share/pixmaps/io.github.lact-linux.png
/usr/share/applications/io.github.ilya_zlobintsev.LACT.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
/usr/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
%changelog
* Sun Mar 16 2025 - ilya-zlobintsev - v0.7.2 - v0.7.2
+3 -3
View File
@@ -29,9 +29,9 @@ VERGEN_GIT_SHA=942526e make install PREFIX=/usr DESTDIR=%{buildroot}
%doc README.md
/usr/bin/lact
/usr/lib/systemd/system/lactd.service
/usr/share/applications/io.github.lact-linux.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
/usr/share/pixmaps/io.github.lact-linux.png
/usr/share/applications/io.github.ilya_zlobintsev.LACT.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
/usr/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
%changelog
* Sun Mar 16 2025 - ilya-zlobintsev - v0.7.2 - v0.7.2
+3 -3
View File
@@ -29,9 +29,9 @@ VERGEN_GIT_SHA=942526e make install PREFIX=/usr DESTDIR=%{buildroot}
%doc README.md
/usr/bin/lact
/usr/lib/systemd/system/lactd.service
/usr/share/applications/io.github.lact-linux.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.lact-linux.svg
/usr/share/pixmaps/io.github.lact-linux.png
/usr/share/applications/io.github.ilya_zlobintsev.LACT.desktop
/usr/share/icons/hicolor/scalable/apps/io.github.ilya_zlobintsev.LACT.svg
/usr/share/pixmaps/io.github.ilya_zlobintsev.LACT.png
%changelog
* Sun Mar 16 2025 - ilya-zlobintsev - v0.7.2 - v0.7.2
@@ -10,7 +10,7 @@
id="svg11300"
sodipodi:version="0.32"
inkscape:version="1.3.1 (91b66b0783, 2023-11-16, custom)"
sodipodi:docname="io.github.lact-linux.Source.svg"
sodipodi:docname="io.github.ilya_zlobintsev.LACT.Source.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
version="1.0"
style="display:inline;enable-background:new"
@@ -3,6 +3,6 @@ Type=Application
Name=LACT
GenericName=GPU Control Application
Exec=lact gui
Icon=io.github.lact-linux
Icon=io.github.ilya_zlobintsev.LACT
Categories=System;
Keywords=AMD;GPU;Radeon;
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.ilya_zlobintsev.LACT</id>
<metadata_license>CC0</metadata_license>
<project_license>MIT</project_license>
<name>LACT</name>
<summary>GPU Control Application</summary>
<description>
<p>LACT lets you configure and monitor your AMD, Nvidia or Intel GPU on Linux.</p>
<p>Supported functionality:</p>
<ul>
<li>Detailed GPU information</li>
<li>Overclocking</li>
<li>Power limits</li>
<li>Fan control</li>
<li>Monitoring with historical charts</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<image>https://i.imgur.com/zG5jkTH.png</image>
<caption>Information</caption>
</screenshot>
<screenshot>
<image>https://i.imgur.com/72y3Rca.png</image>
<caption>Overclocking</caption>
</screenshot>
<screenshot>
<image>https://i.imgur.com/aMEDZ43.png</image>
<caption>Fan Control</caption>
</screenshot>
</screenshots>
<url type="homepage">https://github.com/ilya-zlobintsev/LACT</url>
<url type="vcs-browser">https://github.com/ilya-zlobintsev/LACT</url>
<url type="bugtracker">https://github.com/ilya-zlobintsev/LACT/issues</url>
<content_rating type="oars-1.0" />
<releases>
<release version="0.7.2" date="2025-03-16">
<url>https://github.com/ilya-zlobintsev/LACT/releases/tag/v0.7.2</url>
</release>
<release version="0.7.1" date="2025-02-27">
<url>https://github.com/ilya-zlobintsev/LACT/releases/tag/v0.7.1</url>
</release>
<release version="0.7.0" date="2025-01-14">
<url>https://github.com/ilya-zlobintsev/LACT/releases/tag/v0.7.0</url>
</release>
</releases>
<developer id="io.github.ilya_zlobintsev">
<name>Ilya Zlobintsev</name>
</developer>
<update_contact>ilya.zl@protonmail.com</update_contact>
<launchable type="desktop-id">io.github.ilya_zlobintsev.LACT.desktop</launchable>
</component>
+1 -1
View File
@@ -1,5 +1,5 @@
[Unit]
Description=AMDGPU Control Daemon
Description=GPU Control Daemon
After=multi-user.target
[Service]