diff --git a/hosts/yarn/default.nix b/hosts/yarn/default.nix index abc5fa6..3b3d01b 100644 --- a/hosts/yarn/default.nix +++ b/hosts/yarn/default.nix @@ -83,21 +83,114 @@ # PS5 DualSense adaptive triggers in Forza Horizon 4 / 5. services.forzaTrigger.enable = true; - # Skip the 40 MB T10/Microsoft Studios intro video on startup. - # The module discovers FH5's install path from Steam's library metadata - # and replaces the BK2 file with a 0-byte stub. Re-applies daily via - # systemd timer so Steam verify/updates don't silently undo it. + # Declarative game-file mods on top of Steam. # - # Two copies live in the install: media/UI/Videos/T10_MS_Combined.bk2 - # (SD) and .../hires/T10_MS_Combined.bk2 (hires). The engine picks one - # based on the installed asset profile, so we stub both for guaranteed - # coverage. PCGamingWiki documents both paths under "Skip intro video". - services.gameMods = { - enable = true; - mods."fh5-no-intro" = { - steamAppId = 1551360; - files."media/UI/Videos/T10_MS_Combined.bk2".empty = true; - files."media/UI/Videos/hires/T10_MS_Combined.bk2".empty = true; + # fh5-no-intro: stub the 40 MB T10/Microsoft Studios cold-start splash. + # Two copies live in the install (SD + hires); engine picks one based on + # the installed asset profile, so stub both. PCGamingWiki documents both + # paths under "Skip intro video". + # + # fh5-optiscaler: drop OptiScaler v0.9.1 + a FH5-tuned OptiScaler.ini into + # the install dir to enable FSR 4 INT8 on this RDNA 3 Navi 32 box. + # OptiScaler intercepts FH5's DLSS/XeSS calls and reroutes them through + # the bundled FFX SDK. Settings flipped from upstream defaults: + # Fsr4Update auto -> true # FSR 4 path required for INT8 RDNA 3 + # Dxgi auto -> false # FH5 wiki: required for 0.9 + # DlssReactiveMaskBias auto -> 0.65 # FH5 wiki: fixes flickering lights, reduces car ghosting + # + # Required one-time per-game setup in Steam (Proton picker is not + # declarable from NixOS; launch options are written declaratively below): + # 1. Properties -> Compatibility: force "GE-Proton" (proton-ge-bin is + # already in extraCompatPackages; pick the latest installed). + # Steam must be closed when the launch options write happens, or + # Steam will overwrite our localconfig.vdf edit on shutdown. + # 2. In-game: switch the Upscaling option from FSR 2.2 to DLSS or XeSS + # (FSR 2 inputs aren't intercepted). Press Insert to open the Opti + # overlay and set the FFX upscaler to FSR 4. + # + # Caveats: + # - OptiScaler.ini is dropped with mode = "init" so in-game overlay edits + # persist. The awk-patched template below is only written on first apply + # (or after manual deletion). To push a new default into an existing + # install: rm OptiScaler.ini in the FH5 dir, then `systemctl start + # game-mods`. The DLLs and other static assets stay mode = "create" so + # they're updated on every OptiScaler version bump. + # - OptiScaler's installation page warns against use with online games. + # FH5 has no kernel-mode anti-cheat but Playground does server-side + # telemetry. Use at your own risk. + # + # fh5-vkd3d-no-hvv: append `VKD3D_CONFIG=no_upload_hvv` to FH5's launch + # options. Disables vkd3d-proton's host-visible VRAM upload heap, which + # works around a Proton stutter/crash on this box. Kept as its own mod + # (no files, just env) so the workaround can be removed independently of + # OptiScaler when a future Proton release fixes the underlying issue. + services.gameMods = + let + optiPkg = pkgs.optiscaler; + # OptiScaler.ini ships with CRLF line endings, so we use awk with explicit + # RS/ORS to keep the rewrites line-ending agnostic. The regex is matched + # against the CR-stripped record, the original CRLF is restored on output. + optiIni = pkgs.runCommand "OptiScaler-fh5.ini" { } '' + awk -v RS='\r\n' -v ORS='\r\n' ' + /^Fsr4Update=auto$/ { print "Fsr4Update=true"; next } + /^Dxgi=auto$/ { print "Dxgi=false"; next } + /^DlssReactiveMaskBias=auto$/ { print "DlssReactiveMaskBias=0.65"; next } + { print } + ' ${optiPkg}/OptiScaler.ini > $out + ''; + fromOpti = relpath: { + source = "${optiPkg}/${relpath}"; + mode = "create"; + }; + in + { + enable = true; + mods."fh5-no-intro" = { + steamAppId = 1551360; + files."media/UI/Videos/T10_MS_Combined.bk2".empty = true; + files."media/UI/Videos/hires/T10_MS_Combined.bk2".empty = true; + }; + mods."fh5-optiscaler" = { + steamAppId = 1551360; + # RDNA 3 (Navi 32) FSR 4 path on Linux: + # PROTON_FSR4_UPGRADE=1 opts FH5 into Proton's FSR 4 upgrade. + # DXIL_SPIRV_CONFIG=wmma_rdna3_... fixes broken visuals on RDNA 3 per + # the OptiScaler FSR4 wiki. + # Other FH5-targeting mods (e.g. fh5-vkd3d-no-hvv) append their own + # entries to this list; the module joins them and adds %command%. + launchOptions = [ + "PROTON_FSR4_UPGRADE=1" + "DXIL_SPIRV_CONFIG=wmma_rdna3_workaround" + ]; + files = { + # OptiScaler.dll is renamed to dxgi.dll so FH5's DLL search order + # picks it up as the dxgi shim per the OptiScaler FH5 wiki page. + "dxgi.dll" = fromOpti "OptiScaler.dll"; + "OptiScaler.ini" = { + source = optiIni; + # init: drop the patched template once, then leave it alone so + # the in-game overlay can persist user tweaks. + mode = "init"; + }; + } + // lib.genAttrs [ + "D3D12_Optiscaler/D3D12Core.dll" + "amd_fidelityfx_dx12.dll" + "amd_fidelityfx_framegeneration_dx12.dll" + "amd_fidelityfx_upscaler_dx12.dll" + "amd_fidelityfx_vk.dll" + "dlssg_to_fsr3_amd_is_better.dll" + "fakenvapi.dll" + "fakenvapi.ini" + "libxell.dll" + "libxess.dll" + "libxess_dx11.dll" + "libxess_fg.dll" + ] fromOpti; + }; + mods."fh5-vkd3d-no-hvv" = { + steamAppId = 1551360; + launchOptions = [ "VKD3D_CONFIG=no_upload_hvv" ]; + }; }; - }; }