mirror of
https://github.com/nix-community/home-manager.git
synced 2025-12-02 23:21:02 +01:00
202 lines
8 KiB
Markdown
202 lines
8 KiB
Markdown
# GPU on non-NixOS systems {#sec-usage-gpu-non-nixos}
|
|
|
|
To access the GPU, programs need access to OpenGL and Vulkan libraries. While
|
|
this works transparently on NixOS, it does not on other Linux systems. There are
|
|
two options:
|
|
|
|
1. Recommended: modify the host system slightly so that the graphics libraries
|
|
can be found where programs from Nixpkgs can find them.
|
|
2. Wrap programs from Nixpkgs in an environment which tells them where to find
|
|
graphics libraries.
|
|
|
|
The first option is very clean because the needed modifications to the host OS
|
|
are small. However, it does require root/sudo access to the system, which may
|
|
not be available. The second approach avoids that. However, it injects libraries
|
|
from Nixpkgs into the environment of wrapped programs, which can make it
|
|
impossible to launch programs of the host OS from wrapped programs.
|
|
|
|
|
|
## When sudo is available: fixing the host OS {#sec-usage-gpu-sudo}
|
|
|
|
The {option}`targets.genericLinux.gpu` module is automatically enabled whenever
|
|
the option {option}`targets.genericLinux.enable` is set (unless
|
|
[NixGL](#sec-usage-gpu-nosudo) is used instead), which is recommended for
|
|
non-NixOS Linux distributions in any case. The module can also be explicitly
|
|
enabled by setting {option}`targets.genericLinux.gpu.enable`.
|
|
|
|
This module builds a directory containing GPU libraries. When activating the
|
|
home configuration by `home-manager switch`, the host system is examined: for
|
|
compatibility with NixOS, these libraries need to be placed in
|
|
`/run/opengl-driver`. If this directory does not exist, or contains a different
|
|
set of libraries, the activation script will print a warning such as
|
|
|
|
```text
|
|
Activating checkExistingGpuDrivers
|
|
GPU drivers require an update, run
|
|
sudo /nix/store/HASH-non-nixos-gpu/bin/non-nixos-gpu-setup
|
|
```
|
|
|
|
Because the `/run` directory is volatile and disappears on reboot, libraries
|
|
cannot be simply copied or linked there. The `non-nixos-gpu-setup` script
|
|
installs a Systemd service which ensures that the drivers are linked to
|
|
`/run/opengl-driver` on boot. Home Manager will always check and warn you when
|
|
this setup needs to be refreshed.
|
|
|
|
If you ever wish to uninstall these drivers, all you need to do is
|
|
|
|
```sh
|
|
sudo rm /run/opengl-driver
|
|
sudo systemctl disable --now non-nixos-gpu.service
|
|
sudo rm /etc/systemd/system/non-nixos-gpu.service
|
|
```
|
|
|
|
|
|
### GPU offloading {#sec-usage-gpu-offloading}
|
|
|
|
You can use the {option}`targets.genericLinux.nixGL.prime.installScript` option.
|
|
It installs the `prime-offload` script which is configured through options under
|
|
{option}`targets.genericLinux.nixGL.prime`. This functionality is independent
|
|
from the rest of NixGL and can be used when
|
|
{option}`targets.genericLinux.nixGL.packages` is left `null`, which it should be
|
|
when using drivers from `/run/opengl-driver`.
|
|
|
|
|
|
### Nvidia drivers {#sec-usage-gpu-nvidia}
|
|
|
|
If you need to include the proprietary Nvidia drivers, the process is a bit more
|
|
involved. You need to:
|
|
|
|
1. Determine the exact version used by the host system. Example: `550.163.01`
|
|
|
|
1. Fetch that version of the drivers from Nvidia and calculate their hash.
|
|
Example:
|
|
|
|
```sh
|
|
nix store prefetch-file \
|
|
https://download.nvidia.com/XFree86/Linux-x86_64/550.163.01/NVIDIA-Linux-x86_64-550.163.01.run
|
|
```
|
|
|
|
Attention: the version and architecture are present twice. If you are on an
|
|
ARM system, replace `x86_64` with `aarch64`.
|
|
|
|
1. Put this information into your home configuration. Example:
|
|
|
|
```nix
|
|
targets.genericLinux.gpu.nvidia = {
|
|
enable = true;
|
|
version = "550.163.01";
|
|
sha256 = "sha256-74FJ9bNFlUYBRen7+C08ku5Gc1uFYGeqlIh7l1yrmi4=";
|
|
};
|
|
```
|
|
|
|
::: {.warning}
|
|
The Nvidia driver version **must** match the host system. This means that you
|
|
must pay attention when upgrading the system and update the home configuration
|
|
as well.
|
|
:::
|
|
|
|
|
|
## No root access: wrapping programs {#sec-usage-gpu-nosudo}
|
|
|
|
The wrapping approach is facilitated by
|
|
[NixGL](https://github.com/nix-community/nixGL), which can be integrated into
|
|
Home Manager.
|
|
|
|
::: {.warning}
|
|
|
|
This approach can cause issues when a wrapped program from Nixpkgs executes a
|
|
program from the host. For example, Firefox from Nixpkgs must be wrapped by
|
|
NixGL in order for graphical acceleration to work. If you then download a PDF
|
|
file and open it in a PDF viewer that is not installed from Nixpkgs but is
|
|
provided by the host distribution, there may be issues. Because Firefox's
|
|
environment injects libraries from NixGL, they are inherited by the PDF viewer,
|
|
and unless they are the same or compatible version as the libraries on the host,
|
|
the viewer will not work. This problem manifests more often with Vulkan because
|
|
it needs a larger set of injected libraries than OpenGL.
|
|
|
|
The problem typically manifests with errors similar to
|
|
|
|
```text
|
|
/nix/store/HASH-gcc-12.3.0-lib/lib/libstdc++.so.6: version `GLIBCXX_3.4.31' not found
|
|
```
|
|
|
|
:::
|
|
|
|
To enable the integration, import NixGL into your home configuration, either as
|
|
a channel, or as a flake input passed via `extraSpecialArgs`. Then, set the
|
|
`targets.genericLinux.nixGL.packages` option to the package set provided by
|
|
NixGL.
|
|
|
|
Once integration is enabled, it can be used in two ways: as Nix functions for
|
|
wrapping programs installed via Home Manager, and as shell commands for running
|
|
programs installed by other means (such as `nix shell`). In either case, there
|
|
are several wrappers available. They can be broadly categorized
|
|
|
|
- by vendor: as Mesa (for Free drivers of all vendors) and Nvidia (for
|
|
Nvidia-specific proprietary drivers).
|
|
- by GPU selection: as primary and secondary (offloading).
|
|
|
|
For example, the `mesa` wrapper provides support for running programs on the
|
|
primary GPU for Intel, AMD and Nouveau drivers, while the `mesaPrime` wrapper
|
|
does the same for the secondary GPU.
|
|
|
|
**Note:** when using Nvidia wrappers together with flakes, your home
|
|
configuration will not be pure and needs to be built using `home-manager switch
|
|
--impure`. Otherwise, the build will fail, complaining about missing attribute
|
|
`currentTime`.
|
|
|
|
Wrapper functions are available under `config.lib.nixGL.wrappers`. However, it
|
|
can be more convenient to use the `config.lib.nixGL.wrap` alias, which can be
|
|
configured to use any of the wrappers. It is intended to provide a customization
|
|
point when the same home configuration is used across several machines with
|
|
different hardware. There is also the `config.lib.nixGL.wrapOffload` alias for
|
|
two-GPU systems.
|
|
|
|
Another convenience is that all wrapper functions are always available. However,
|
|
when `targets.genericLinux.nixGL.packages` option is unset, they are no-ops.
|
|
This allows them to be used even when the home configuration is used on NixOS
|
|
machines. The exception is the `prime-offload` script which ignores
|
|
`targets.genericLinux.nixGL.packages` and is installed into the environment
|
|
whenever `targets.genericLinux.nixGL.prime.installScript` is set. This script,
|
|
which can be used to start a program on a secondary GPU, does not depend on
|
|
NixGL and is useful on NixOS systems as well.
|
|
|
|
Below is an abbreviated example for an Optimus laptop that makes use of both
|
|
Mesa and Nvidia wrappers, where the latter is used in dGPU offloading mode. It
|
|
demonstrates how to wrap `mpv` to run on the integrated Intel GPU, wrap FreeCAD
|
|
to run on the Nvidia dGPU, and how to install the wrapper scripts. It also wraps
|
|
Xonotic to run on the dGPU, but uses the wrapper function directly for
|
|
demonstration purposes.
|
|
|
|
```nix
|
|
{ config, lib, pkgs, nixgl, ... }:
|
|
{
|
|
targets.genericLinux.nixGL = {
|
|
packages = nixgl.packages;
|
|
defaultWrapper = "mesa";
|
|
offloadWrapper = "nvidiaPrime";
|
|
installScripts = [ "mesa" "nvidiaPrime" ];
|
|
};
|
|
|
|
programs.mpv = {
|
|
enable = true;
|
|
package = config.lib.nixGL.wrap pkgs.mpv;
|
|
};
|
|
|
|
home.packages = [
|
|
(config.lib.nixGL.wrapOffload pkgs.freecad)
|
|
(config.lib.nixGL.wrappers.nvidiaPrime pkgs.xonotic)
|
|
];
|
|
}
|
|
```
|
|
|
|
The above example assumes a flake-based setup where `nixgl` was passed from the
|
|
flake. When using channels, the example would instead begin with
|
|
|
|
```nix
|
|
{ config, lib, pkgs, ... }:
|
|
{
|
|
targets.genericLinux.nixGL.packages = import <nixgl> { inherit pkgs; };
|
|
# The rest is the same as above
|
|
...
|
|
```
|