1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.programs.gamemode;
10 settingsFormat = pkgs.formats.ini { listsAsDuplicateKeys = true; };
11 configFile = settingsFormat.generate "gamemode.ini" cfg.settings;
12in
13{
14 options = {
15 programs.gamemode = {
16 enable = lib.mkEnableOption "GameMode to optimise system performance on demand";
17
18 enableRenice =
19 lib.mkEnableOption "CAP_SYS_NICE on gamemoded to support lowering process niceness"
20 // {
21 default = true;
22 };
23
24 settings = lib.mkOption {
25 type = settingsFormat.type;
26 default = { };
27 description = ''
28 System-wide configuration for GameMode (/etc/gamemode.ini).
29 See {manpage}`gamemoded(8)` man page for available settings.
30 '';
31 example = lib.literalExpression ''
32 {
33 general = {
34 renice = 10;
35 };
36
37 # Warning: GPU optimisations have the potential to damage hardware
38 gpu = {
39 apply_gpu_optimisations = "accept-responsibility";
40 gpu_device = 0;
41 amd_performance_level = "high";
42 };
43
44 custom = {
45 start = "''${pkgs.libnotify}/bin/notify-send 'GameMode started'";
46 end = "''${pkgs.libnotify}/bin/notify-send 'GameMode ended'";
47 };
48 }
49 '';
50 };
51 };
52 };
53
54 config = lib.mkIf cfg.enable {
55 environment = {
56 systemPackages = [ pkgs.gamemode ];
57 etc."gamemode.ini".source = configFile;
58 };
59
60 security = {
61 polkit.enable = true;
62 wrappers = lib.mkIf cfg.enableRenice {
63 gamemoded = {
64 owner = "root";
65 group = "root";
66 source = "${pkgs.gamemode}/bin/gamemoded";
67 capabilities = "cap_sys_nice+ep";
68 };
69 };
70 };
71
72 systemd = {
73 packages = [ pkgs.gamemode ];
74 user.services.gamemoded = {
75 # The upstream service already defines this, but doesn't get applied.
76 # See https://github.com/NixOS/nixpkgs/issues/81138
77 wantedBy = [ "default.target" ];
78
79 # Use pkexec from the security wrappers to allow users to
80 # run libexec/cpugovctl & libexec/gpuclockctl as root with
81 # the the actions defined in share/polkit-1/actions.
82 #
83 # This uses a link farm to make sure other wrapped executables
84 # aren't included in PATH.
85 environment.PATH = lib.mkForce (
86 pkgs.linkFarm "pkexec" [
87 {
88 name = "pkexec";
89 path = "${config.security.wrapperDir}/pkexec";
90 }
91 ]
92 );
93
94 serviceConfig.ExecStart = lib.mkIf cfg.enableRenice [
95 "" # Tell systemd to clear the existing ExecStart list, to prevent appending to it.
96 "${config.security.wrapperDir}/gamemoded"
97 ];
98 };
99 };
100
101 users.groups.gamemode = { };
102 };
103
104 meta = {
105 maintainers = with lib.maintainers; [ kira-bruneau ];
106 };
107}