diff --git a/install.sh b/install.sh index 1ce30a3..e6bc86e 100755 --- a/install.sh +++ b/install.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # NVIDIA installer: beside the proxy release's d4r/ or inside the ASI's d4r/. -# Installs NVIDIA's DLLs and then builds the native engine's models from them on this machine. +# Installs NVIDIA's DLLs and then builds the native engine's models from them on this machine. Both are kept in +# ~/.cache/d4r, so the next game's install copies them instead of downloading or building again. set -euo pipefail DLSS_URL=https://raw.githubusercontent.com/NVIDIA/DLSS/a291cc7d2cc642a51566f3dfd5376f635cd1b284/lib/Windows_x86_64/rel/nvngx_dlss.dll DLSS_SHA256=be6e434a94ca32499515eb62ca0e6c274526055d568d0426e4c652dcdfb6ee6e @@ -12,23 +13,29 @@ NGX_SHA256=0e3423b3b7afa1019c7ecac053a8408df8e5d9d9d904434705c6aaeacec02fef fail() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } usage() { - printf '%s\n' 'Usage: bash install.sh [--no-engine | --engine-only] [--rebuild-engine] [extracted-release-directory]' \ - 'Default: the directory containing this script, regardless of your working directory.' \ + printf '%s\n' 'Usage: bash install.sh [options] [extracted-release-directory]' \ + 'Default directory: the one containing this script, regardless of your working directory.' \ + 'Run it from a terminal and it asks what to do. The options answer those questions in advance:' \ + ' --yes accept every default (also the behaviour without a terminal)' \ + ' --no-engine only the NVIDIA DLLs, no engine models' \ + ' --engine-only only the engine models (the DLLs are already installed)' \ + ' --exact engine models with NVIDIA'"'"'s exact roundings (slower) instead of the fastest builds' \ + ' --rebuild-engine build the models again even when a cached build fits' \ '1. Downloads official NVIDIA DLSS 310.7.0 (Super Resolution), DLSS Ray Reconstruction 310.9.1 and NGX from' \ - ' driver 596.36 (~1 GiB in all). Existing matching DLLs are kept; differing DLLs are backed up.' \ - '2. Builds the native engine'"'"'s models ([Engine] in d4r/d4r.ini) from those DLLs into d4r/engine:' \ - ' Ray Reconstruction D, E and F from nvngx_dlssd.dll; Super Resolution K, M and L (and their LDR variants)' \ - ' by rendering one test frame per model through d4r under GE-Proton (about a minute each).' \ - ' --no-engine skips this, --engine-only does only this, --rebuild-engine rebuilds models already built.' \ + ' driver 596.36 (~1 GiB, once: verified copies are kept in ~/.cache/d4r/nvidia).' \ + '2. Builds the native engine'"'"'s models from those DLLs into d4r/engine (once per DLL set and builder version:' \ + ' ~/.cache/d4r/engine-models). The engine is the faster path; d4r.ini [Engine] Enabled = auto uses it.' \ 'Requires Bash, curl, sha256sum, 7zz/7z/7za, python3 with numpy, and GE-Proton 11 in Steam (or' \ - 'D4R_PROTON=/path/to/GE-Proton11-3). No sudo needed. NVIDIA license terms apply.' + 'D4R_PROTON=/path/to/GE-Proton11-3). No sudo needed. NVIDIA license terms apply. D4R_CACHE_DIR moves the cache.' } -DO_DLLS=1 DO_ENGINE=1 REBUILD=0 +DO_DLLS=1 DO_ENGINE=ask EXACT=ask REBUILD=0 YES=0 while [[ $# -gt 0 ]]; do case "$1" in -h|--help) usage; exit 0 ;; + -y|--yes) YES=1; shift ;; --no-engine) DO_ENGINE=0; shift ;; - --engine-only) DO_DLLS=0; shift ;; + --engine-only) DO_DLLS=0; DO_ENGINE=1; shift ;; + --exact) EXACT=1; shift ;; --rebuild-engine) REBUILD=1; shift ;; -*) usage >&2; exit 2 ;; *) break ;; @@ -41,49 +48,21 @@ RUNTIME="$ROOT/d4r" [[ -f "$RUNTIME/nvngx.dll" && -f "$RUNTIME/d4r.ini" ]] || fail "Extract the release ZIP first; no d4r runtime found in $ROOT" command -v sha256sum >/dev/null || fail 'Missing sha256sum (install coreutils).' valid() { [[ -f "$1" ]] && [[ $(sha256sum -- "$1" | cut -d' ' -f1) == "$2" ]]; } +CACHE="${D4R_CACHE_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/d4r}" -install_dlls() { - local need_dlss=1 need_dlssd=1 need_ngx=1 tool - valid "$RUNTIME/nvngx_dlss.dll" "$DLSS_SHA256" && need_dlss=0 - valid "$RUNTIME/nvngx_dlssd.dll" "$DLSSD_SHA256" && need_dlssd=0 - valid "$RUNTIME/ngx/_nvngx.dll" "$NGX_SHA256" && need_ngx=0 - if (( need_dlss == 0 && need_dlssd == 0 && need_ngx == 0 )); then - echo 'NVIDIA DLLs are already installed and verified.' - return - fi - command -v curl >/dev/null || fail 'Missing curl. Install it and run this script again.' - SEVENZIP='' - if (( need_ngx )); then - for tool in 7zz 7z 7za; do - if command -v "$tool" >/dev/null; then SEVENZIP=$tool; break; fi - done - [[ -n "$SEVENZIP" ]] || fail 'Missing 7-Zip. Install 7zip (or p7zip) and run this script again.' - fi - echo 'Downloading NVIDIA files under NVIDIA license terms:' - echo 'DLSS: https://github.com/NVIDIA/DLSS/blob/v310.9.1/LICENSE.txt' - echo 'Driver: https://www.nvidia.com/en-us/drivers/nvidia-license/' - if (( need_dlss )); then - echo 'Downloading DLSS 310.7.0...' - download "$DLSS_URL" "$TMP/nvngx_dlss.dll" - verify "$TMP/nvngx_dlss.dll" "$DLSS_SHA256" - fi - if (( need_dlssd )); then - echo 'Downloading DLSS Ray Reconstruction 310.9.1...' - download "$DLSSD_URL" "$TMP/nvngx_dlssd.dll" - verify "$TMP/nvngx_dlssd.dll" "$DLSSD_SHA256" - fi - if (( need_ngx )); then - echo 'Downloading NVIDIA driver 596.36 (~915 MiB); extracting NGX without running the installer...' - download "$DRIVER_URL" "$TMP/driver.exe" - verify "$TMP/driver.exe" "$DRIVER_SHA256" - "$SEVENZIP" e -y -bso0 -bsp0 "-o$TMP/ngx" "$TMP/driver.exe" 'Display.Driver/_nvngx.dll' || fail 'Could not extract NGX; no DLLs installed.' - verify "$TMP/ngx/_nvngx.dll" "$NGX_SHA256" - fi - # Verify all downloads before modifying any destination. - (( need_dlss == 0 )) || place "$TMP/nvngx_dlss.dll" "$RUNTIME/nvngx_dlss.dll" - (( need_dlssd == 0 )) || place "$TMP/nvngx_dlssd.dll" "$RUNTIME/nvngx_dlssd.dll" - (( need_ngx == 0 )) || place "$TMP/ngx/_nvngx.dll" "$RUNTIME/ngx/_nvngx.dll" - echo 'NVIDIA DLLs installed and verified.' +# Questions only on a terminal; otherwise (or with --yes) every default applies. +interactive() { (( YES == 0 )) && [[ -t 0 && -t 1 ]]; } +ask() { # ask "QUESTION" DEFAULT(y|n): 0 for yes + local answer + if ! interactive; then [[ $2 == y ]]; return; fi + while true; do + read -r -p "$1 [$([[ $2 == y ]] && echo Y/n || echo y/N)] " answer || answer='' + case "${answer,,}" in + '') [[ $2 == y ]]; return ;; + y|yes) return 0 ;; + n|no) return 1 ;; + esac + done } TMP=$(mktemp -d) @@ -92,7 +71,7 @@ trap '[[ -z "$STAGED" ]] || rm -f -- "$STAGED"; rm -rf -- "$TMP"' EXIT trap 'exit 130' INT trap 'exit 143' TERM download() { - curl --fail --location --show-error --retry 3 --connect-timeout 30 \ + curl --fail --location --show-error --retry 3 --connect-timeout 30 --progress-bar \ --proto '=https' --proto-redir '=https' --output "$2" "$1" || fail "Download failed: $1. Run the installer again to retry." } verify() { valid "$1" "$2" || fail "SHA-256 mismatch for $1; no DLLs installed."; } @@ -113,37 +92,154 @@ place() { STAGED='' printf 'Installed: %s\n' "$dst" } +# A verified copy in the cache, or none. Cached files are checked again before use. +cached() { local f="$CACHE/nvidia/$1"; valid "$f" "$2" && printf '%s\n' "$f"; } +keep() { mkdir -p -- "$CACHE/nvidia" && cp -- "$1" "$CACHE/nvidia/$2.tmp" && mv -f -- "$CACHE/nvidia/$2.tmp" "$CACHE/nvidia/$2"; } + +install_dlls() { + local need_dlss=1 need_dlssd=1 need_ngx=1 tool src + valid "$RUNTIME/nvngx_dlss.dll" "$DLSS_SHA256" && need_dlss=0 + valid "$RUNTIME/nvngx_dlssd.dll" "$DLSSD_SHA256" && need_dlssd=0 + valid "$RUNTIME/ngx/_nvngx.dll" "$NGX_SHA256" && need_ngx=0 + if (( need_dlss == 0 && need_dlssd == 0 && need_ngx == 0 )); then + echo 'NVIDIA DLLs are already installed and verified.' + return + fi + # earlier installs' verified copies first + if (( need_dlss )) && src=$(cached nvngx_dlss.dll "$DLSS_SHA256"); then cp -- "$src" "$TMP/nvngx_dlss.dll"; need_dlss=2; fi + if (( need_dlssd )) && src=$(cached nvngx_dlssd.dll "$DLSSD_SHA256"); then cp -- "$src" "$TMP/nvngx_dlssd.dll"; need_dlssd=2; fi + if (( need_ngx )) && src=$(cached _nvngx.dll "$NGX_SHA256"); then mkdir -p "$TMP/ngx"; cp -- "$src" "$TMP/ngx/_nvngx.dll"; need_ngx=2; fi + if (( need_dlss == 1 || need_dlssd == 1 || need_ngx == 1 )); then + local size=0 + (( need_dlss != 1 )) || size=$((size + 57)) + (( need_dlssd != 1 )) || size=$((size + 47)) + (( need_ngx != 1 )) || size=$((size + 915)) + echo "d4r needs NVIDIA's DLSS files, downloaded from NVIDIA under NVIDIA's license terms:" + echo ' DLSS: https://github.com/NVIDIA/DLSS/blob/v310.9.1/LICENSE.txt' + echo ' Driver: https://www.nvidia.com/en-us/drivers/nvidia-license/' + ask "Download them now (~$size MiB, once: later installs use $CACHE/nvidia)?" y || + fail 'Not downloaded. d4r needs these files; run install.sh again when you want to install them.' + command -v curl >/dev/null || fail 'Missing curl. Install it and run this script again.' + SEVENZIP='' + if (( need_ngx == 1 )); then + for tool in 7zz 7z 7za; do + if command -v "$tool" >/dev/null; then SEVENZIP=$tool; break; fi + done + [[ -n "$SEVENZIP" ]] || fail 'Missing 7-Zip. Install 7zip (or p7zip) and run this script again.' + fi + fi + if (( need_dlss == 1 )); then + echo 'Downloading DLSS 310.7.0...' + download "$DLSS_URL" "$TMP/nvngx_dlss.dll" + verify "$TMP/nvngx_dlss.dll" "$DLSS_SHA256" + keep "$TMP/nvngx_dlss.dll" nvngx_dlss.dll + fi + if (( need_dlssd == 1 )); then + echo 'Downloading DLSS Ray Reconstruction 310.9.1...' + download "$DLSSD_URL" "$TMP/nvngx_dlssd.dll" + verify "$TMP/nvngx_dlssd.dll" "$DLSSD_SHA256" + keep "$TMP/nvngx_dlssd.dll" nvngx_dlssd.dll + fi + if (( need_ngx == 1 )); then + echo 'Downloading NVIDIA driver 596.36 (~915 MiB); extracting NGX without running the installer...' + download "$DRIVER_URL" "$TMP/driver.exe" + verify "$TMP/driver.exe" "$DRIVER_SHA256" + "$SEVENZIP" e -y -bso0 -bsp0 "-o$TMP/ngx" "$TMP/driver.exe" 'Display.Driver/_nvngx.dll' || fail 'Could not extract NGX; no DLLs installed.' + rm -f -- "$TMP/driver.exe" + verify "$TMP/ngx/_nvngx.dll" "$NGX_SHA256" + keep "$TMP/ngx/_nvngx.dll" _nvngx.dll + fi + # Everything is verified before any destination changes. + (( need_dlss == 0 )) || place "$TMP/nvngx_dlss.dll" "$RUNTIME/nvngx_dlss.dll" + (( need_dlssd == 0 )) || place "$TMP/nvngx_dlssd.dll" "$RUNTIME/nvngx_dlssd.dll" + (( need_ngx == 0 )) || place "$TMP/ngx/_nvngx.dll" "$RUNTIME/ngx/_nvngx.dll" + echo 'NVIDIA DLLs installed and verified.' +} (( DO_DLLS == 0 )) || install_dlls -if (( DO_ENGINE == 0 )); then - echo 'Follow the included README for Steam launch options.' - exit 0 -fi -# The engine's models, built from the DLLs above. A stamp of the DLLs and the builder skips an unchanged rebuild. +# --- the engine's models --------------------------------------------------------------------------------------- BUILDER="$RUNTIME/tools/build-engine-models.sh" -[[ -f "$BUILDER" ]] || fail "missing $BUILDER (this release has no engine-model builder; use --no-engine)" -STAMP="$RUNTIME/engine/.d4r-models" -stamp() { - { sha256sum -- "$RUNTIME/nvngx_dlss.dll" "$RUNTIME/nvngx_dlssd.dll" 2>/dev/null | cut -d' ' -f1 - (cd "$RUNTIME/tools" && find . -type f ! -name '*.pyc' -print0 | LC_ALL=C sort -z | xargs -0 sha256sum); } | sha256sum | cut -d' ' -f1 -} +done_msg() { echo 'Done. Follow the included README for Steam launch options.'; } +if [[ ! -f "$BUILDER" ]]; then + [[ "$DO_ENGINE" != 1 ]] || fail "missing $BUILDER (this release has no engine-model builder)" + done_msg; exit 0 +fi models=(rr-d rr-e rr-f k k-ldr m m-ldr l l-ldr) -complete=1 -for m in "${models[@]}"; do [[ -d "$RUNTIME/engine/$m" ]] || complete=0; done -if (( REBUILD == 0 && complete )) && [[ -f "$STAMP" && "$(cat "$STAMP")" == "$(stamp)" ]]; then - echo 'Engine models are already built for these DLLs (--rebuild-engine builds them again).' - exit 0 +# One build serves every game with the same DLLs and builder: the key covers both and the accuracy choice. +key() { # key EXACT(0|1) + { echo "exact=$1" + sha256sum -- "$RUNTIME/nvngx_dlss.dll" "$RUNTIME/nvngx_dlssd.dll" 2>/dev/null | cut -d' ' -f1 + (cd "$RUNTIME/tools" && find . -type f ! -name '*.pyc' -print0 | LC_ALL=C sort -z | xargs -0 sha256sum); } | sha256sum | cut -c1-16 +} +have() { local m; for m in "${models[@]}"; do [[ -f "$1/$m/model.json" || -f "$1/$m/rr.txt" ]] || return 1; done; } +STAMP="$RUNTIME/engine/.d4r-models" +if [[ "$EXACT" == ask ]]; then + EXACT=0 + for e in 0 1; do [[ -f "$STAMP" && "$(cat "$STAMP")" == "$(key $e)" ]] && EXACT=$e; done fi -rm -f -- "$STAMP" -failed=() -bash "$BUILDER" --rr-only "$RUNTIME" || failed+=('Ray Reconstruction') -bash "$BUILDER" --sr-only "$RUNTIME" || failed+=('Super Resolution') -if (( ${#failed[@]} )); then - printf 'install.sh: the engine models for %s were not built (reason above). d4r works without them on its\n' \ - "$(IFS=/; echo "${failed[*]}")" >&2 - printf 'normal path; fix the cause and run: bash install.sh --engine-only\n' >&2 - exit 1 +if (( REBUILD == 0 )) && [[ "$DO_ENGINE" != 0 && -f "$STAMP" && "$(cat "$STAMP")" == "$(key "$EXACT")" ]] && have "$RUNTIME/engine"; then + echo 'The engine models in this folder are up to date.' + done_msg; exit 0 fi -stamp > "$STAMP" -echo 'Done. Follow the included README for Steam launch options; set [Engine] Enabled = true in d4r/d4r.ini to use the engine.' +if [[ "$DO_ENGINE" == ask ]]; then + echo + echo "Set up d4r's own DLSS engine (recommended)?" + echo ' + Faster: DLSS 4 / 4.5 and Ray Reconstruction run on d4r'"'"'s Vulkan engine instead of NVIDIA'"'"'s kernels' + echo ' through CUDA emulation (for example Ray Reconstruction at 720p -> 4K in about 3.6 ms per frame).' + echo ' + Lower latency: the game shows the upscaled result of the frame it just rendered, not an older one.' + echo ' + No minute-long freeze while DLSS'"'"'s CUDA kernels compile the first time a model is used.' + echo ' - Longer setup, once: building its models takes a minute or two (it renders a test frame per model' + echo ' through GE-Proton) and needs ~300 MB of temporary space. Later installs reuse the models.' + echo ' Without it, d4r uses its normal path; anything the engine does not cover uses that path anyway.' + if ask 'Set up the engine now?' y; then DO_ENGINE=1; else DO_ENGINE=0; fi +fi +if [[ "$DO_ENGINE" == 0 ]]; then + echo 'No engine models: d4r uses its normal path. Run install.sh again to build them later.' + done_msg; exit 0 +fi +KEY="$(key "$EXACT")" +SHARED="$CACHE/engine-models/$KEY" +copy_models() { # copy_models FROM TO: whole model folders, each replaced by a rename + local m + mkdir -p -- "$2" + for m in "${models[@]}"; do + rm -rf -- "$2/$m.new"; cp -r -- "$1/$m" "$2/$m.new" + rm -rf -- "$2/$m.old"; [[ ! -e "$2/$m" ]] || mv -- "$2/$m" "$2/$m.old" + mv -- "$2/$m.new" "$2/$m"; rm -rf -- "$2/$m.old" + done +} +if (( REBUILD == 0 )) && have "$SHARED"; then + echo "Using the engine models built earlier ($SHARED)." + copy_models "$SHARED" "$RUNTIME/engine" +else + failed=() + flags=(); (( EXACT == 0 )) || flags=(--exact) + bash "$BUILDER" --rr-only "${flags[@]}" "$RUNTIME" || failed+=('Ray Reconstruction') + if [[ -z "${D4R_PROTON:-}" && -z "$(bash "$BUILDER" --find-proton)" ]] && interactive; then + echo 'The Super Resolution models render one test frame through GE-Proton 11, which was not found in Steam.' + read -r -p 'Path to a GE-Proton folder (Enter to skip): ' D4R_PROTON || D4R_PROTON='' + export D4R_PROTON + fi + if [[ -n "${D4R_PROTON:-}" || -n "$(bash "$BUILDER" --find-proton)" ]]; then + bash "$BUILDER" --sr-only "${flags[@]}" "$RUNTIME" || failed+=('Super Resolution') + else + failed+=('Super Resolution') + echo 'install.sh: no GE-Proton 11 found for the Super Resolution models.' >&2 + fi + if (( ${#failed[@]} )); then + printf 'install.sh: the engine models for %s were not built (reason above). d4r runs those on its normal path;\n' \ + "$(IFS=/; echo "${failed[*]}")" >&2 + printf 'fix the cause and run install.sh again.\n' >&2 + exit 1 + fi + # keep a copy for the next game + rm -rf -- "$SHARED.tmp"; mkdir -p -- "$SHARED.tmp" + for m in "${models[@]}"; do cp -r -- "$RUNTIME/engine/$m" "$SHARED.tmp/"; done + rm -rf -- "$SHARED"; mv -- "$SHARED.tmp" "$SHARED" +fi +printf '%s\n' "$KEY" > "$STAMP" +if grep -qiE '^[[:space:]]*Enabled[[:space:]]*=[[:space:]]*(false|0|no|off)[[:space:]]*$' <(sed -n '/^\[Engine\]/,/^\[/p' "$RUNTIME/d4r.ini"); then + echo 'Note: d4r/d4r.ini turns the engine off ([Engine] Enabled = false); set it to auto to use these models.' +fi +done_msg diff --git a/packaging/D4R_README.txt b/packaging/D4R_README.txt index 9d8002a..075110b 100644 --- a/packaging/D4R_README.txt +++ b/packaging/D4R_README.txt @@ -57,13 +57,14 @@ that archive's d4r/README.txt: setup runs automatically when the ASI loads. @installer d4r/ngx/_nvngx.dll. No sudo is needed. The driver archive is about 915 MiB; it is extracted, @installer never executed. Downloads are temporary. Run it again to check the files; differing existing @installer DLLs are backed up before replacement. -@installer It then builds the native engine's models in d4r/engine from those DLLs ([Engine] under -@installer Settings): Ray Reconstruction D, E and F straight from nvngx_dlssd.dll, and Super Resolution -@installer K, M and L (with their LDR variants) by rendering one test frame per model through d4r under -@installer GE-Proton 11, found in Steam's compatibility tools (or set D4R_PROTON=/path/to/GE-Proton11-3). -@installer The first time this takes a few minutes while DLSS's kernels compile. --no-engine skips it; -@installer bash install.sh --engine-only builds the models later, --rebuild-engine builds them again. -@clean 2. Copy nvngx_dlss.dll into the d4r folder, and _nvngx.dll into d4r/ngx. +@installer Verified copies are kept in ~/.cache/d4r/nvidia, so installing d4r in the next game needs no +@installer download. install.sh then asks whether to set up d4r's own DLSS engine (recommended: faster, +@installer lower latency). That builds the engine's models in d4r/engine from the DLLs: Ray Reconstruction +@installer D, E and F straight from nvngx_dlssd.dll, and Super Resolution K, M and L (with their LDR +@installer variants) by rendering one test frame per model through d4r under GE-Proton 11, found in Steam's +@installer compatibility tools (or set D4R_PROTON=/path/to/GE-Proton11-3). It takes a minute or two once; +@installer the models are kept in ~/.cache/d4r/engine-models for the next game. bash install.sh --help lists +@installer options for scripted installs. @installer 3. In Steam, open the game's Properties: @clean 3. In Steam, open the game's Properties: @full 2. In Steam, open the game's Properties: @@ -107,9 +108,10 @@ Settings PreferAccuracy = true. This uses original translated enc1/enc2 layers while retaining other native acceleration. It reduced trails in a captured Townfall sequence on RX 7700 XT and costs some GPU time. Restart after changing it; other scenes and RDNA4 hardware still need testing. -- [Engine] Enabled = true (experimental, off by default) runs DLSS 4 (K), 4.5 (M and L) and Ray - Reconstruction (D, E and F) on d4r's own Vulkan inference engine: the work is recorded into the game's - own frame instead of going through CUDA emulation. It needs Mesa RADV with VK_KHR_cooperative_matrix +- [Engine] runs DLSS 4 (K), 4.5 (M and L) and Ray Reconstruction (D, E and F) on d4r's own Vulkan + inference engine: the work is recorded into the game's own frame instead of going through CUDA + emulation, which is faster. Enabled = auto (the default) uses it whenever its models are in d4r/engine; + true / false force it on / off. It needs Mesa RADV with VK_KHR_cooperative_matrix and the models in d4r/engine: k (K), k-ldr (K in games without HDR), m and m-ldr (M), l and l-ldr (L), rr-d, rr-e and rr-f (Ray Reconstruction). Games and settings it does not cover (other models, display-resolution motion vectors with L or M) keep using the normal path, @@ -197,7 +199,7 @@ Uninstall --------- Delete dxgi.dll, OptiScaler.ini, OptiScaler.log (if present), d3d12.dll, d3d12core.dll, D4R_README.txt, install.sh (if present) and the d4r folder from the game folder, and clear the launch options. The kernel -cache in ~/.cache/d4r can be deleted too. +cache in ~/.cache/d4r can be deleted too; it also holds install.sh's copies of the NVIDIA DLLs and the engine models. Licenses diff --git a/packaging/build_engine_models.sh b/packaging/build_engine_models.sh index 525651f..f5baa7b 100755 --- a/packaging/build_engine_models.sh +++ b/packaging/build_engine_models.sh @@ -2,7 +2,8 @@ # Builds the native engine's models ([Engine] in d4r.ini) on this machine, from the NVIDIA DLLs install.sh put in # the d4r folder. Shipped as d4r/tools/build-engine-models.sh; install.sh runs it. # -# usage: bash d4r/tools/build-engine-models.sh [--rr-only | --sr-only] [D4R_FOLDER] +# usage: bash d4r/tools/build-engine-models.sh [--rr-only | --sr-only] [--exact] [D4R_FOLDER] +# bash d4r/tools/build-engine-models.sh --find-proton prints the GE-Proton it would use (or nothing) # # Ray Reconstruction engine/rr-d, rr-e, rr-f from d4r/nvngx_dlssd.dll 310.9.1 alone (about half a minute) # Super Resolution engine/k, k-ldr, m, m-ldr, l, l-ldr @@ -11,19 +12,41 @@ # GE-Proton, and the uploads are saved (a minute or two each; the first run also compiles # DLSS's kernels and creates a temporary Proton prefix) # Needs python3 with numpy, and for Super Resolution a GE-Proton (D4R_PROTON=/path/to/GE-Proton11-3 to choose one). +# The models are the fastest builds (this GPU's own arithmetic; engine/README.md). --exact builds NVIDIA's roundings +# instead: bit-identical to the CUDA path, about 20% slower (K is the same either way). # Everything written is derived from NVIDIA's DLLs: it stays in this folder and must not be redistributed. set -euo pipefail fail() { printf 'build-engine-models: %s\n' "$*" >&2; exit 1; } -DO_RR=1 DO_SR=1 +DO_RR=1 DO_SR=1 FIND_PROTON=0 while [[ $# -gt 0 ]]; do case "$1" in --rr-only) DO_SR=0; shift ;; --sr-only) DO_RR=0; shift ;; - -h|--help) sed -n '2,15p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;; + --exact) export D4R_RR_RELAXED=0 M_EXACT=1; shift ;; + --find-proton) FIND_PROTON=1; shift ;; + -h|--help) sed -n '2,19p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;; *) break ;; esac done +find_proton() { + # a GE-Proton: D4R_PROTON, else GE-Proton11-3 (the tested one), else the newest stock GE-Proton11-N in Steam's + # compatibility tools. Renamed or rebuilt variants (2026-10-14: one with a suffix after the version number) can + # fail NGX's CUDA initialisation, so they are only used when named. + PROTON="${D4R_PROTON:-}" + if [[ -z "$PROTON" ]]; then + best=-1 + for d in "$HOME/.local/share/Steam" "$HOME/.steam/root" "$HOME/.steam/steam" \ + "$HOME/.var/app/com.valvesoftware.Steam/data/Steam"; do + for p in "$d"/compatibilitytools.d/GE-Proton11-*; do + n="${p##*/GE-Proton11-}" + [[ -x "$p/proton" && "$n" =~ ^[0-9]+$ ]] || continue + if [[ "$n" == 3 ]]; then best=1000; PROTON="$p"; elif (( n > best )); then best=$n; PROTON="$p"; fi + done + done + fi +} +if (( FIND_PROTON )); then find_proton; [[ -z "$PROTON" ]] || printf '%s\n' "$PROTON"; exit 0; fi TOOLS="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" KIT="$TOOLS/models" RUNTIME="$(cd -- "${1:-$TOOLS/..}" && pwd)" @@ -82,21 +105,7 @@ if (( DO_SR )); then DLL="$RUNTIME/nvngx_dlss.dll" [[ -f "$DLL" && "$(sha "$DLL")" == "$DLSS_SHA256" ]] || fail "Super Resolution models need nvngx_dlss.dll 310.7.0 in $RUNTIME (run install.sh)" [[ -f "$RUNTIME/ngx/_nvngx.dll" ]] || fail "missing $RUNTIME/ngx/_nvngx.dll (run install.sh)" - # a GE-Proton: D4R_PROTON, else GE-Proton11-3 (the tested one), else the newest stock GE-Proton11-N in Steam's - # compatibility tools. Renamed or rebuilt variants (2026-10-14: one with a suffix after the version number) can - # fail NGX's CUDA initialisation, so they are only used when named. - PROTON="${D4R_PROTON:-}" - if [[ -z "$PROTON" ]]; then - best=-1 - for d in "$HOME/.local/share/Steam" "$HOME/.steam/root" "$HOME/.steam/steam" \ - "$HOME/.var/app/com.valvesoftware.Steam/data/Steam"; do - for p in "$d"/compatibilitytools.d/GE-Proton11-*; do - n="${p##*/GE-Proton11-}" - [[ -x "$p/proton" && "$n" =~ ^[0-9]+$ ]] || continue - if [[ "$n" == 3 ]]; then best=1000; PROTON="$p"; elif (( n > best )); then best=$n; PROTON="$p"; fi - done - done - fi + find_proton [[ -n "$PROTON" && -x "$PROTON/proton" ]] || fail 'no GE-Proton found: set D4R_PROTON=/path/to/GE-Proton11-3 (the folder holding the proton script)' STEAM_ROOT="$(dirname -- "$(dirname -- "$PROTON")")" diff --git a/packaging/d4r.ini b/packaging/d4r.ini index 0acb400..16cd1f5 100644 --- a/packaging/d4r.ini +++ b/packaging/d4r.ini @@ -29,7 +29,7 @@ ShowWatermark = false Enable = auto ; Independent denoiser presets: auto (game choice), default, D, E (transformer) or F (DLSS 4.5). ; E and F through NVIDIA's library need a denoiser DLL containing that model (F: 310.9 or later). On the engine -; ([Engine] Enabled = true) F runs from the model in d4r\engine\rr-f; frames the library serves instead show +; ([Engine]) F runs from the model in d4r\engine\rr-f; frames the library serves instead show ; preset D when the DLL is older (d4r_nvngx.log says so). Model = auto @@ -73,11 +73,13 @@ ElideNgxSync = true DirectOutput = auto [Engine] -; Experimental. Runs DLSS 4 and 4.5 (models K, L and M) on d4r's own Vulkan inference engine instead of NVIDIA's -; kernels: the game shows the result of the frame it just rendered and [Latency] / [Interop] do not apply. -; Needs Mesa RADV with VK_KHR_cooperative_matrix and the models in d4r\engine\k, k-ldr, m, m-ldr, l and l-ldr -; (see D4R_README.txt). Games or settings it does not cover use the normal path; d4r_nvngx.log says why. -Enabled = false +; Runs DLSS 4 and 4.5 (models K, L and M) and Ray Reconstruction (D, E and F) on d4r's own Vulkan inference +; engine instead of NVIDIA's kernels: the faster path, and the game shows the result of the frame it just rendered +; ([Latency] / [Interop] do not apply). Needs Mesa RADV with VK_KHR_cooperative_matrix and the models install.sh +; builds in d4r\engine (k, k-ldr, m, m-ldr, l, l-ldr, rr-d, rr-e, rr-f). Games or settings it does not cover, +; and a device that cannot run it, use the normal path; d4r_nvngx.log says why. +; auto = on when d4r\engine holds a model, true / false = always / never. +Enabled = auto ; Another model K folder for games with the HDR flag (a path relative to the d4r folder, or a Windows path ; such as Z:\home\me\k) ModelDir = auto diff --git a/tools/d4r_nvngx_shim.cpp b/tools/d4r_nvngx_shim.cpp index 3f2368d..3497e0b 100644 --- a/tools/d4r_nvngx_shim.cpp +++ b/tools/d4r_nvngx_shim.cpp @@ -695,8 +695,25 @@ static void load_portable_config() // release cannot ship that kernel, which is built from NVIDIA's PTX. portable_set("D4R_SHIM_OUTPUT_DIRECT", ini_flag(ini, "interop", "DirectOutput", nativeOn) ? "1" : "0"); - // [Engine]: d4r's own Vulkan inference for DLSS 4 (K); the model is looked up in d4r\engine\k - portable_set("D4R_ENGINE", ini_flag(ini, "engine", "Enabled", 0) ? "1" : "0"); + // [Engine]: d4r's own Vulkan inference (K, L, M and Ray Reconstruction); the models are looked up in d4r\engine. + // Enabled = auto (the default) runs it when install.sh built a model there: it is the faster path, and a model + // the device cannot run, or a feature no model covers, still goes to the CUDA backend (d4r_nvngx.log says why). + { + const std::string enabled = ascii_lower(ini_value(ini, "engine", "Enabled")); + bool on = false; + if (enabled.empty() || enabled == "auto") + { + for (const wchar_t* model : {L"k", L"k-ldr", L"m", L"m-ldr", L"l", L"l-ldr", L"rr-d", L"rr-e", L"rr-f"}) + { + const DWORD attributes = GetFileAttributesW((dir + L"\\engine\\" + model).c_str()); + if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)) + on = true; + } + } + else + on = ini_flag(ini, "engine", "Enabled", 0) != 0; + portable_set("D4R_ENGINE", on ? "1" : "0"); + } if (const std::string engineModel = ini_value(ini, "engine", "ModelDir"); !engineModel.empty()) portable_set(L"D4R_ENGINE_MODEL_DIR", portable_path(engineModel)); // Network: the network on the engine's Vulkan shader ("vulkan", and the default: "auto") or on the native HIP