diff --git a/home-config/applications/graphical/default.nix b/home-config/applications/graphical/default.nix index 515a4182..522a881b 100644 --- a/home-config/applications/graphical/default.nix +++ b/home-config/applications/graphical/default.nix @@ -6,6 +6,7 @@ apvlv feh yubioath-flutter + obsidian ]; programs.alacritty = { diff --git a/home-config/dotfiles/sway.conf b/home-config/dotfiles/sway.conf index 32c9b545..bbb4b130 100644 --- a/home-config/dotfiles/sway.conf +++ b/home-config/dotfiles/sway.conf @@ -15,6 +15,8 @@ output "Dell Inc. DELL G2723HN 5B0C3H3" { max_render_time 3 } +output "GSS edid.build 0x00000001" disable + # Window decorations client.focused $lavender $base $text $lavender $lavender diff --git a/nixos-config/desktop/greeter/default.nix b/nixos-config/desktop/greeter/default.nix index e0897d41..e55afbe2 100644 --- a/nixos-config/desktop/greeter/default.nix +++ b/nixos-config/desktop/greeter/default.nix @@ -11,6 +11,7 @@ let sway-gtkgreet = pkgs.writeText "sway-gtkgreet" '' output '*' background #fafafa solid_color + output 'GSS edid.build 0x00000001' disable seat seat0 xcursor_theme Bibata-Original-Ice 24 exec dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK diff --git a/nixos-config/hosts/yui/default.nix b/nixos-config/hosts/yui/default.nix index e593a341..cd60bb8a 100644 --- a/nixos-config/hosts/yui/default.nix +++ b/nixos-config/hosts/yui/default.nix @@ -1,4 +1,4 @@ -{ pkgs, flake-inputs, ... }: +{ lib, flake-inputs, ... }: { imports = [ flake-inputs.disko.nixosModules.disko @@ -19,14 +19,21 @@ nixpkgs.config.allowUnfreePredicate = pkg: - builtins.elem (pkgs.lib.getName pkg) [ + (builtins.elem (lib.getName pkg) [ "steam" "steam-run" # Required to get the steam controller to work (i.e., for hardware.steam-hardware) "steam-original" "steam-unwrapped" "nvidia-x11" - ]; + "obsidian" + # For sunshine streams with nvenc + "cuda-merged" + "libnpp" + ]) + || (lib.strings.hasPrefix "cuda_" (lib.getName pkg)) + || (lib.strings.hasPrefix "libcu" (lib.getName pkg)) + || (lib.strings.hasPrefix "libnv" (lib.getName pkg)); home-manager.users.tlater = import "${flake-inputs.self}/home-config/hosts/yui.nix"; diff --git a/nixos-config/hosts/yui/games.nix b/nixos-config/hosts/yui/games.nix index d077ec8a..79e0c96e 100644 --- a/nixos-config/hosts/yui/games.nix +++ b/nixos-config/hosts/yui/games.nix @@ -9,6 +9,8 @@ in nix-gaming.nixosModules.pipewireLowLatency nix-gaming.nixosModules.platformOptimizations nix-gaming.nixosModules.wine + + ./sunshine.nix ]; environment.systemPackages = diff --git a/nixos-config/hosts/yui/sunshine.nix b/nixos-config/hosts/yui/sunshine.nix new file mode 100644 index 00000000..f7b98e10 --- /dev/null +++ b/nixos-config/hosts/yui/sunshine.nix @@ -0,0 +1,140 @@ +{ + flake-inputs, + config, + pkgs, + ... +}: +let + inherit (flake-inputs.self.pkgs-lib.${pkgs.stdenv.hostPlatform.system}) writeNuWith; + inherit (flake-inputs.self.packages.${pkgs.stdenv.hostPlatform.system}) edid-generator; +in +{ + nix.settings = { + substituters = [ "https://cache.nixos-cuda.org" ]; + trusted-public-keys = [ "cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M=" ]; + }; + + # Create a virtual display to render games for sunshine on + hardware.display = { + edid.packages = [ + (pkgs.runCommand "VTCL65C825.bin" + { + nativeBuildInputs = [ edid-generator ]; + settings = pkgs.writers.writeJSON "edid.json" { + defaultMode = { + width = 1920; + height = 1080; + refresh = 120; + }; + modes = [ + { + width = 1920; + height = 1080; + refresh = 120; + } + { + width = 1920; + height = 1080; + refresh = 60; + } + { + width = 3840; + height = 2160; + refresh = 120; + } + { + width = 3840; + height = 2160; + refresh = 60; + } + ]; + audio = false; + hdr = true; + deepColor = true; + dsc = false; + vrr = false; + listedModesOnly = false; + }; + } + '' + mkdir -p "$out/lib/firmware/edid" + edid-generator $settings > "$out/lib/firmware/edid/VTCL65C825.bin" + '' + ) + ]; + + # The port (DP-2) to be used must be free on the GPU, use + # `ls /sys/class/drm/*/status` to find free ports. + # + # Using DP-2 because HDMI doesn't support 3840x2160@120. + outputs."DP-2" = { + edid = "VTCL65C825.bin"; + mode = "e"; + }; + }; + + services.sunshine = { + enable = true; + package = pkgs.sunshine.override { cudaSupport = true; }; + + openFirewall = true; + settings = { + sunshine_name = config.networking.hostName; + system_tray = false; + encoder = "nvenc"; + + # TODO(tlater): Switch to portalgrab once released: + # https://github.com/LizardByte/Sunshine/pull/4417 + capture = "wlr"; + output_name = 1; + }; + + applications.apps = [ + ( + let + runScript = writeNuWith { + packages = [ + pkgs.util-linux + config.programs.sway.package + config.programs.steam.package + ]; + }; + in + { + name = "Steam Big Picture"; + cmd = + (runScript "run-steam" /* nu */ '' + swaymsg output DP-2 enable + swaymsg workspace sunshine gaps outer 0 + swaymsg workspace sunshine gaps inner 0 + swaymsg workspace sunshine output DP-2 + swaymsg focus output DP-2 + swaymsg assign '[title="Steam Big Picture Mode"]' → workspace steam + + try { + setsid steam steam://open/bigpicture + } + '').outPath; + + auto-detach = false; + prep-cmd = [ + { + undo = + (runScript "close-steam" /* nu */ '' + swaymsg output DP-2 disable + + sleep 20sec + if (ps | where pid == (cat ~/.steampid)) != [ ] { + try { + steam -shutdown + } + } + '').outPath; + } + ]; + } + ) + ]; + }; + +} diff --git a/pkgs/packages/custom-edid.nix b/pkgs/packages/custom-edid.nix new file mode 100644 index 00000000..b093036d --- /dev/null +++ b/pkgs/packages/custom-edid.nix @@ -0,0 +1,18 @@ +{ + runCommand, + xorg, + edid-generator, +}: +edid-generator.overrideAttrs (old: { + # passAsFile = [ ]; + clean = true; + + # modelines = ''Modeline "3840x2160" 712.34 3840 4152 4576 5312 2160 2161 2164 2235 -HSync +Vsync''; + + modelinesPath = + (runCommand "modelines" { nativeBuildInputs = [ xorg.xorgserver ]; } '' + gtf 3840 2160 120 > modeline + sed -i 's/"3840x2160_120.00"/"VTCL65C825"/' modeline + grep -v '# ' modeline > $out + '').outPath; +}) diff --git a/pkgs/packages/edid-generator.nix b/pkgs/packages/edid-generator.nix new file mode 100644 index 00000000..7c235477 --- /dev/null +++ b/pkgs/packages/edid-generator.nix @@ -0,0 +1,45 @@ +{ + fetchFromGitHub, + runCommand, + writers, +}: +let + edid-core = + runCommand "edid-core" + { + src = fetchFromGitHub { + owner = "goncalossilva"; + repo = "edid-generator"; + rev = "bc311cb7d5d4900a1bdad8fa967125c8e50c0174"; + hash = "sha256-90yzP0wxVms/6+sLa8zOkZbuBkqnBMQS0WyEn2poWUM="; + }; + } + /* sh */ '' + mkdir -p "$out/lib/node_modules/edid-core/" + cp "$src/assets/js/edid-core.js" "$out/lib/node_modules/edid-core/index.js" + ''; +in +writers.writeJSBin "edid-generator" { libraries = [ edid-core ]; } /* js */ '' + const { readFile } = require("node:fs/promises"); + const { resolve } = require("node:path"); + const { stdout, stderr } = require("node:process"); + + const { generateEdid } = require("edid-core"); + + async function main() { + const settings = JSON.parse(await readFile(resolve(process.argv[2]))); + const edid = generateEdid(settings); + + if (edid.warnings) { + console.warn("EDID wasn't generated cleanly:"); + + for (warning of edid.warnings) { + console.warn("- " + warning); + } + } + + stdout.write(edid.bytes); + } + + main(); +''