From de389523d76b7e04208a98430a44d5c772ea2e91 Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Tue, 24 Aug 2021 12:21:49 +0200 Subject: [PATCH] modules: Add a gaming virtualisation module --- hosts/miku.nix | 111 ++--------------------- modules/programs/gamemode/#gamemode.ini# | 36 ++++++++ modules/virtualisation/gaming.nix | 109 ++++++++++++++++++++++ overlays/steam.nix | 51 ++++++----- 4 files changed, 177 insertions(+), 130 deletions(-) create mode 100644 modules/programs/gamemode/#gamemode.ini# create mode 100644 modules/virtualisation/gaming.nix diff --git a/hosts/miku.nix b/hosts/miku.nix index c9e4b6f..348c4a8 100644 --- a/hosts/miku.nix +++ b/hosts/miku.nix @@ -7,6 +7,7 @@ ../modules/fonts.nix ../modules/users/alexander.nix ../modules/programs/zsh ../modules/programs/git ../modules/programs/mpv ../modules/programs/tmux ../modules/programs/emacs ../modules/programs/firefox ../modules/programs/gnome-terminal ../modules/programs/gnome ../modules/programs/i18n.nix ../modules/programs/gamemode ../modules/programs/nonvm + ../modules/virtualisation/gaming.nix ../modules/programs/distributed-build/builder.nix ../modules/programs/music ]; @@ -19,7 +20,10 @@ })) # Steam overlay - (import ../overlays/steam.nix pkgs) + (import ../overlays/steam.nix { + pkgs = pkgs; + lib = lib; + }) # Simple overrides (final: prev: { @@ -64,7 +68,7 @@ emacsPgtkGcc unstable.firmwareLinuxNonfree gajim - libvirt virt-manager qemu scream + virt-manager unstable.qemu scream gamemode # Custom package key-mapper # Custom package replaysorcery # Custom package @@ -77,72 +81,6 @@ # Prevent us from having to always type it out NIXOS_CONFIG = "/home/${config.system.singleUser}/Development/Personal/nixos-config/hosts/miku.nix"; }; - - etc = { - "evdev-proxy/config.toml".source = pkgs.writeText "config.toml" '' - log_level = "INFO" - - [[device]] - [device.Simple] - name = "EvdevProxyMouse" - vendor = 0x1337 - model = 0x1337 - class = "Mouse" - [[device.Simple.selector]] - USBIDClass = {vendor=0x046d, model=0xc531, class="Mouse"} - [[device.Simple.selector]] - USBIDClass = {vendor=0x046d, model=0xc07c, class="Mouse"} - [[device]] - [device.Simple] - name = "EvdevProxyTartarus" - vendor = 0x1337 - model = 0x1338 - class = "Keyboard" - # This is to give a deterministic /dev/input/by-id/ path to - # the mapped version of the Tartarus evdev node. - # (Useful for qemu) - [[device.Simple.selector]] - EVDEVClass = {phys="\"key-mapper\""} - ''; - "libvirt/hooks/qemu".source = let - vfio-isolate-state = "/tmp/vfio-isolate-state"; - in pkgs.writeScript "qemu" '' - #!${pkgs.stdenv.shell} - guest=$1 - action=$2 - phase=$3 - extra=$4 - - if [[ "$guest" = "win10" ]]; then - case "$action" in - prepare) - # Only do this while in preparation - [[ ! "$phase" = "prepare" ]] && exit 0 - - sudo -u alexander systemctl --user start evdev-proxy.service - sudo -u alexander systemctl --user start scream.service - sleep 2 - - ${pkgs.vfio-isolate}/bin/vfio-isolate \ - -u ${vfio-isolate-state} \ - cpu-governor performance "$GUEST_CORES" \ - cpuset-create --cpus "$GUEST_CORES" /guest.slice \ - cpuset-create --cpus C0,4 /host.slice \ - move-tasks / /host.slice \ - irq-affinity mask "$GUEST_CORES" - ;; - stopped) - # Only run when the VM is fully stopped - [[ ! "$phase" = "end" ]] && exit 0 - sudo -u alexander systemctl --user stop evdev-proxy.service - sudo -u alexander systemctl --user stop scream.service - - ${pkgs.vfio-isolate}/bin/vfio-isolate \ - restore ${vfio-isolate-state} - esac - fi - ''; - }; }; networking = { @@ -209,36 +147,9 @@ sshd.enable = true; }; - virtualisation.libvirtd = { - enable = true; - qemuOvmf = true; - #qemuRunAsRoot = false; - qemuPackage = pkgs.unstable.qemu; - qemuVerbatimConfig = '' - seccomp_sandbox = 0 - cgroup_device_acl = [ - "/dev/null", "/dev/full", "/dev/zero", - "/dev/random", "/dev/urandom", - "/dev/ptmx", "/dev/kvm", "/dev/kqemu", - "/dev/rtc","/dev/hpet", - "/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse", - "/dev/input/by-id/usb-Razer_Razer_Tartarus_V2-event-kbd", - "/dev/input/by-id/virtual-event-EvdevProxyMouse", - "/dev/input/by-id/virtual-event-EvdevProxyTartarus", - "/dev/input/by-id/usb-Razer_Razer_BlackWidow_Ultimate-event-kbd" - ] - ''; - }; - # NOTE: Workaround for libvirt's SYSCONFDIR being set to /var/lib - # (See https://github.com/NixOS/nixpkgs/issues/51152#issuecomment-899374407) - system.activationScripts.libvirt-hooks.text = '' - ln -Tfs /etc/libvirt/hooks /var/lib/libvirt/hooks - ''; - systemd = { services = { NetworkManager-wait-online.enable = false; - libvirtd.path = with pkgs; [ vfio-isolate systemd ]; }; user.services = { @@ -281,15 +192,6 @@ Restart = "always"; }; }; - evdev-proxy = { - description = "Creates virtual device to proxy evdev devices events"; - #wantedBy = [ "default.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.evdev-proxy}/bin/evdev-proxy"; - Restart = "always"; - }; - }; # TODO: Remove once in stable or I decide to use unstable gamemode = { description = "A daemon/lib combo for Linux that allows games to request a set of optimisations be temporarily applied to the host OS."; @@ -302,7 +204,6 @@ ]); serviceConfig = { Type = "simple"; - #ExecStart = "${pkgs.gamemode}/bin/gamemoded"; ExecStart = "${config.security.wrapperDir}/gamemoded"; Restart = "always"; }; diff --git a/modules/programs/gamemode/#gamemode.ini# b/modules/programs/gamemode/#gamemode.ini# new file mode 100644 index 0000000..c1123bc --- /dev/null +++ b/modules/programs/gamemode/#gamemode.ini# @@ -0,0 +1,36 @@ +[general] +reaper_freq=5 +desiredgov=performance +; TODO: Maybe set this +;defaultgov=powersave + +; The iGPU desired governor is used when the integrated GPU is under heavy load +igpu_desiredgov=powersave +igpu_power_threshold=0.3 + +softrealtime=on; +renice=0 +ioprio=0 +inhibit_screensaver=1 + +[filter] +; If "whitelist" entry has a value(s) +; gamemode will reject anything not in the whitelist +;whitelist=RiseOfTheTombRaide + +; Gamemode will always reject anything in the blacklist +;blacklist=HalfLife3 +; glxgears + +[gpu] + +[supervisor] + +[custom] +start=systemctl --user start replaysorcery-kms + systemctl --user start replaysorcery + +end=systemctl --user stop replaysorcery-kms + systemctl --user stop replaysorcery + +script_timeout=10 \ No newline at end of file diff --git a/modules/virtualisation/gaming.nix b/modules/virtualisation/gaming.nix new file mode 100644 index 0000000..676c7a8 --- /dev/null +++ b/modules/virtualisation/gaming.nix @@ -0,0 +1,109 @@ +{ pkgs, ... }: + +{ + environment.etc = { + "evdev-proxy/config.toml".source = pkgs.writeText "config.toml" '' + log_level = "INFO" + + [[device]] + [device.Simple] + name = "EvdevProxyMouse" + vendor = 0x1337 + model = 0x1337 + class = "Mouse" + [[device.Simple.selector]] + USBIDClass = {vendor=0x046d, model=0xc531, class="Mouse"} + [[device.Simple.selector]] + USBIDClass = {vendor=0x046d, model=0xc07c, class="Mouse"} + [[device]] + [device.Simple] + name = "EvdevProxyTartarus" + vendor = 0x1337 + model = 0x1338 + class = "Keyboard" + # This is to give a deterministic /dev/input/by-id/ path to + # the mapped version of the Tartarus evdev node. + # (Useful for qemu) + [[device.Simple.selector]] + EVDEVClass = {phys="\"key-mapper\""} + ''; + "libvirt/hooks/qemu".source = let + vfio-isolate-state = "/tmp/vfio-isolate-state"; + in pkgs.writeScript "qemu" '' + #!${pkgs.stdenv.shell} + guest=$1 + action=$2 + phase=$3 + extra=$4 + + if [[ "$guest" = "win10" ]]; then + case "$action" in + prepare) + # Only do this while in preparation + [[ ! "$phase" = "prepare" ]] && exit 0 + + sudo -u alexander systemctl --user start evdev-proxy.service + sudo -u alexander systemctl --user start scream.service + sleep 2 + + ${pkgs.vfio-isolate}/bin/vfio-isolate \ + -u ${vfio-isolate-state} \ + cpu-governor performance "$GUEST_CORES" \ + cpuset-create --cpus "$GUEST_CORES" /guest.slice \ + cpuset-create --cpus C0,4 /host.slice \ + move-tasks / /host.slice \ + irq-affinity mask "$GUEST_CORES" + ;; + stopped) + # Only run when the VM is fully stopped + [[ ! "$phase" = "end" ]] && exit 0 + sudo -u alexander systemctl --user stop evdev-proxy.service + sudo -u alexander systemctl --user stop scream.service + + ${pkgs.vfio-isolate}/bin/vfio-isolate \ + restore ${vfio-isolate-state} + esac + fi + ''; + }; + + virtualisation.libvirtd = { + enable = true; + #qemuRunAsRoot = false; + qemuOvmf = true; + qemuPackage = pkgs.unstable.qemu; + qemuVerbatimConfig = '' + seccomp_sandbox = 0 + cgroup_device_acl = [ + "/dev/null", "/dev/full", "/dev/zero", + "/dev/random", "/dev/urandom", + "/dev/ptmx", "/dev/kvm", "/dev/kqemu", + "/dev/rtc","/dev/hpet", + "/dev/input/by-id/usb-Logitech_USB_Receiver-if02-event-mouse", + "/dev/input/by-id/usb-Razer_Razer_Tartarus_V2-event-kbd", + "/dev/input/by-id/virtual-event-EvdevProxyMouse", + "/dev/input/by-id/virtual-event-EvdevProxyTartarus", + "/dev/input/by-id/usb-Razer_Razer_BlackWidow_Ultimate-event-kbd" + ] + ''; + }; + + # NOTE: Workaround for libvirt's SYSCONFDIR being set to /var/lib + # (See https://github.com/NixOS/nixpkgs/issues/51152#issuecomment-899374407) + system.activationScripts.libvirt-hooks.text = '' + ln -Tfs /etc/libvirt/hooks /var/lib/libvirt/hooks + ''; + + systemd = { + services.libvirtd.path = with pkgs; [ vfio-isolate systemd bash ]; + user.services.evdev-proxy = { + description = "Creates virtual device to proxy evdev devices events"; + #wantedBy = [ "default.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.evdev-proxy}/bin/evdev-proxy"; + Restart = "always"; + }; + }; + }; +} diff --git a/overlays/steam.nix b/overlays/steam.nix index ab846cd..a11f4b5 100644 --- a/overlays/steam.nix +++ b/overlays/steam.nix @@ -1,4 +1,5 @@ -pkgs: final: prev: +{ pkgs, lib }: +final: prev: # TODO: Replace with the commented out version below let @@ -12,28 +13,28 @@ in { steam = steamPackages.steam-fhsenv.override { extraPkgs = pkgsx: with pkgsx; [ gamemode ]; }; +} - #(final: prev: - # let - # # NOTE: This is a really messy solution - # buildFHSUserEnvBubblewrap = prev.callPackage ../packages/build-support/build-fhs-userenv-bubblewrap {}; - # in { - # steamPackages = prev.steamPackages.override { - # buildFHSUserEnv = buildFHSUserEnvBubblewrap; - # # Include gamemode in the FHS - # #extraPkgs = (pkgs: with pkgs; [ gamemode ]); - # }; - - # steam = prev.steamPackages.steam-fhsenv.overrideAttrs (old: { - # specifyHomeDirs = true; - # chdirTo = "/home/$USER"; - # }); - # #steam = final.steamPackages.steam-fhsenv.override { - # # extraPkgs = pkgs: with pkgs; [ gamemode ]; - # #}; - # steam-run = final.steam.run; - # steam-run-native = (final.steam.override { - # nativeOnly = true; - # }); - # steamcmd = final.steamPackages.steamcmd; - # }) +#let +# # NOTE: This is a really messy solution +# buildFHSUserEnvBubblewrap = prev.callPackage ../packages/build-support/build-fhs-userenv-bubblewrap {}; +#in { +# steamPackages = prev.steamPackages.override { +# buildFHSUserEnv = buildFHSUserEnvBubblewrap; +# # Include gamemode in the FHS +# #extraPkgs = (pkgs: with pkgs; [ gamemode ]); +# }; +# +# steam = prev.steamPackages.steam-fhsenv.overrideAttrs (old: { +# specifyHomeDirs = true; +# chdirTo = "/home/$USER"; +# }); +# #steam = final.steamPackages.steam-fhsenv.override { +# # extraPkgs = pkgs: with pkgs; [ gamemode ]; +# #}; +# steam-run = final.steam.run; +# steam-run-native = (final.steam.override { +# nativeOnly = true; +# }); +# steamcmd = final.steamPackages.steamcmd; +#}