diff --git a/install.sh b/install.sh index 177dff1..1ce30a3 100755 --- a/install.sh +++ b/install.sh @@ -1,43 +1,91 @@ #!/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. set -euo pipefail DLSS_URL=https://raw.githubusercontent.com/NVIDIA/DLSS/a291cc7d2cc642a51566f3dfd5376f635cd1b284/lib/Windows_x86_64/rel/nvngx_dlss.dll DLSS_SHA256=be6e434a94ca32499515eb62ca0e6c274526055d568d0426e4c652dcdfb6ee6e +DLSSD_URL=https://raw.githubusercontent.com/NVIDIA/DLSS/374959484e79a640feaba44c93ac8cfb0a03f5b5/lib/Windows_x86_64/rel/nvngx_dlssd.dll +DLSSD_SHA256=4bc7ea5fcb2f32cf86bc2cb072e8d2860914a0be511cbdcb2fc206c1d9d83b80 DRIVER_URL=https://us.download.nvidia.com/Windows/596.36/596.36-desktop-win10-win11-64bit-international-dch-whql.exe DRIVER_SHA256=4a1793d2bc7792f43270fe8286ec381ae24409fe29049dbe1eb8530ed89e19cf NGX_SHA256=0e3423b3b7afa1019c7ecac053a8408df8e5d9d9d904434705c6aaeacec02fef fail() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } -if [[ ${1:-} == --help || ${1:-} == -h ]]; then - printf '%s\n' 'Usage: bash install.sh [extracted-release-directory]' \ +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.' \ - 'Downloads official NVIDIA DLSS 310.7.0 and NGX from driver 596.36 (~915 MiB).' \ - 'Requires Bash, curl, sha256sum, and 7zz, 7z or 7za. No sudo needed.' \ - 'Existing matching DLLs are kept; differing DLLs are backed up. NVIDIA license terms apply.' - exit 0 -fi -[[ $# -le 1 ]] || fail 'Usage: bash install.sh [extracted-release-directory]' + '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.' \ + '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.' +} +DO_DLLS=1 DO_ENGINE=1 REBUILD=0 +while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) usage; exit 0 ;; + --no-engine) DO_ENGINE=0; shift ;; + --engine-only) DO_DLLS=0; shift ;; + --rebuild-engine) REBUILD=1; shift ;; + -*) usage >&2; exit 2 ;; + *) break ;; + esac +done +[[ $# -le 1 ]] || { usage >&2; exit 2; } ROOT=$(cd -- "${1:-$(dirname -- "${BASH_SOURCE[0]}")}" && pwd) RUNTIME="$ROOT/d4r" [[ ! -f "$ROOT/d4r.ini" ]] || RUNTIME="$ROOT" [[ -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" ]]; } -need_dlss=1; need_ngx=1 -valid "$RUNTIME/nvngx_dlss.dll" "$DLSS_SHA256" && need_dlss=0 -valid "$RUNTIME/ngx/_nvngx.dll" "$NGX_SHA256" && need_ngx=0 -if (( need_dlss == 0 && need_ngx == 0 )); then - echo 'NVIDIA DLLs are already installed and verified.' - exit 0 -fi -command -v curl >/dev/null || fail 'Missing curl. Install it and run this script again.' -if (( need_ngx )); then + +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='' - 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 + 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.' +} + TMP=$(mktemp -d) STAGED='' trap '[[ -z "$STAGED" ]] || rm -f -- "$STAGED"; rm -rf -- "$TMP"' EXIT @@ -48,23 +96,7 @@ download() { --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."; } -echo 'Downloading NVIDIA files under NVIDIA license terms:' -echo 'DLSS: https://github.com/NVIDIA/DLSS/blob/v310.7.0/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_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 either destination. Stage on the destination -# filesystem for atomic replacement and retain a unique backup of a differing file. +# Stage on the destination filesystem for atomic replacement and retain a unique backup of a differing file. place() { local src=$1 dst=$2 backup mkdir -p -- "$(dirname -- "$dst")" @@ -81,6 +113,37 @@ place() { STAGED='' printf 'Installed: %s\n' "$dst" } -(( need_dlss == 0 )) || place "$TMP/nvngx_dlss.dll" "$RUNTIME/nvngx_dlss.dll" -(( need_ngx == 0 )) || place "$TMP/ngx/_nvngx.dll" "$RUNTIME/ngx/_nvngx.dll" -echo 'NVIDIA DLLs installed and verified. Follow the included README for Steam launch options.' + +(( 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. +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 +} +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 +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 +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.' diff --git a/packaging/D4R_README.txt b/packaging/D4R_README.txt index 2b73cd5..9d8002a 100644 --- a/packaging/D4R_README.txt +++ b/packaging/D4R_README.txt @@ -24,8 +24,9 @@ What you need - Linux with the amdgpu kernel driver (/dev/kfd). ROCm itself is not needed: the zip includes the ROCm 7.2.4 runtime in d4r/rocm. RocmDir in d4r/d4r.ini selects another ROCm installation instead. - GE-Proton 11 (tested: GE-Proton11-3), selected for the game in Steam. -@installer - Internet access, Bash, curl, sha256sum and 7-Zip to run the included install.sh. -@installer NVIDIA DLLs are downloaded during installation, under NVIDIA's terms. +@installer - Internet access, Bash, curl, sha256sum and 7-Zip to run the included install.sh, and python3 +@installer with numpy for the engine models it builds. NVIDIA DLLs are downloaded during installation, +@installer under NVIDIA's terms. @clean - Two NVIDIA files, which this zip does not include: @clean - nvngx_dlss.dll, the DLSS library, version 310.7 or 310.9 (tested: 310.7.0 and 310.9.1). @clean Many games ship one, but often an older version. The d4r kernels check the DLSS code they @@ -34,7 +35,7 @@ What you need @clean driver 596.36, file version 32.0.15.9636). Extract the driver installer, for example with @clean 7-Zip, and look for _nvngx.dll. @full - Nothing from NVIDIA: this zip already contains NVIDIA's DLSS library (nvngx_dlss.dll 310.7.0), -@full NVIDIA's NGX runtime (_nvngx.dll 32.0.15.9636) and output kernels built from NVIDIA's DLSS code. +@full NVIDIA's NGX runtime (_nvngx.dll 32.0.15.9636) and output kernels built from NVIDIA's DLSS code. Install @@ -50,11 +51,18 @@ that archive's d4r/README.txt: setup runs automatically when the ASI loads. If the folder already has a dxgi.dll or OptiScaler.ini (another OptiScaler install), move those out of the way first. Also remove PROTON_USE_OPTISCALER from the game's launch options if you used GE-Proton's built-in OptiScaler: d4r brings its own. -@installer 2. Run bash install.sh from a terminal (Bash, curl, sha256sum and 7zz/7z/7za required). -@installer It downloads DLSS 310.7.0 and the NGX core from official NVIDIA sources, checks SHA-256, -@installer and installs d4r/nvngx_dlss.dll and d4r/ngx/_nvngx.dll. No sudo is needed. The driver -@installer archive is about 915 MiB; it is extracted, never executed. Downloads are temporary. -@installer Run it again to check the files; differing existing DLLs are backed up before replacement. +@installer 2. Run bash install.sh from a terminal (Bash, curl, sha256sum, 7zz/7z/7za and python3 with numpy +@installer required). It downloads DLSS 310.7.0, DLSS Ray Reconstruction 310.9.1 and the NGX core from +@installer official NVIDIA sources, checks SHA-256, and installs d4r/nvngx_dlss.dll, d4r/nvngx_dlssd.dll and +@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 3. In Steam, open the game's Properties: @clean 3. In Steam, open the game's Properties: @@ -90,25 +98,28 @@ Settings gfx12-fp8 kernel folder; set it to false to use f16 widening. The FP8 path has not been tested on a real RDNA4 GPU. @full - Ray Reconstruction: this zip includes NVIDIA's CUDA-capable denoiser (d4r/nvngx_dlssd.dll -@full 310.7.0). [RayReconstruction] Enable defaults to auto: when the game turns Ray -@full Reconstruction on, d4r runs it through the denoiser. Model = D or E selects a denoiser -@full preset explicitly; auto follows the game. RR presets D/E are validated on RX 9070 XT -@full (gfx1201) with [Kernels] NativeFp8 = on, the packaged default on RDNA4. Keep NativeFp8 on: -@full the scalar FP8 RR path is not validated. +@full 310.7.0). [RayReconstruction] Enable defaults to auto: when the game turns Ray +@full Reconstruction on, d4r runs it through the denoiser. Model = D or E selects a denoiser +@full preset explicitly; auto follows the game. RR presets D/E are validated on RX 9070 XT +@full (gfx1201) with [Kernels] NativeFp8 = on, the packaged default on RDNA4. Keep NativeFp8 on: +@full the scalar FP8 RR path is not validated. - If L/M shows extra trails in motion, try [Kernels] NativeSwinEncoders = false with 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) and 4.5 (M and L) on d4r's own - Vulkan inference engine: the upscale is recorded into the game's own frame instead of going through CUDA - emulation. It needs Mesa RADV with VK_KHR_cooperative_matrix and the models in d4r/engine/k (K), - d4r/engine/k-ldr (K in games without HDR), d4r/engine/m and d4r/engine/m-ldr (M), d4r/engine/l and - d4r/engine/l-ldr (L). Games and settings it does not cover (other models, display-resolution motion - vectors with L or M) keep using the normal path, - and d4r/d4r_nvngx.log says which one ran and why. Tested in one game so far. - This zip has only the engine's shaders in d4r/engine/k. The weights (weights.bin, offsets.bin, - lut.bin) are read from your own nvngx_dlss.dll with the tools in d4r's source repository - (engine/README.md); until they are there, d4r uses the normal path. +- [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 + 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, + and d4r/d4r_nvngx.log says which one ran and why. Tested in a few games so far. +@installer install.sh builds the models from your NVIDIA DLLs (d4r/tools/build-engine-models.sh). They hold +@installer values read from NVIDIA's DLSS: they stay on your machine and must not be shared. +@full Build the models with the tools in d4r's source repository (engine/README.md); until they are +@full there, d4r uses the normal path. +@clean Build the models with the tools in d4r's source repository (engine/README.md); until they are +@clean there, d4r uses the normal path. - OptiScaler.ini: OptiScaler's settings, such as its fps overlay and the render resolution of each quality mode. Press Insert in game for OptiScaler's menu. [Libraries] NvngxPath=d4r\nvngx.dll explicitly selects d4r's shim; OptiDllPath=d4r is also @@ -201,6 +212,8 @@ sections 15 and 16). @full NVIDIA's code (listed in d4r/source/SOURCES.txt) are NVIDIA's property, are not covered by @full d4r's license, and are included by whoever distributes this zip, not by NVIDIA. -@installer NVIDIA DLLs are downloaded by install.sh from NVIDIA/DLSS SDK 310.7.0 and driver 596.36. +@installer NVIDIA DLLs are downloaded by install.sh from NVIDIA/DLSS SDK 310.7.0 and 310.9.1 and driver +@installer 596.36. The engine models install.sh builds from them in d4r/engine are NVIDIA's data, for your +@installer own use. d4r/tools/models/bin/glslangValidator is Khronos' glslang 16.6.0 (d4r/licenses). @installer The included kernels compiled from NVIDIA PTX remain NVIDIA's property and are not @installer covered by d4r's license. See d4r/source/SOURCES.txt for their provenance. diff --git a/packaging/SOURCES.txt b/packaging/SOURCES.txt index f052638..46babff 100644 --- a/packaging/SOURCES.txt +++ b/packaging/SOURCES.txt @@ -9,7 +9,13 @@ Built from source by d4r (GPL-3.0-only, d4r/licenses/d4r-LICENSE.txt): d4r/kernels/ native RDNA3/RDNA4 kernels for the DLSS 4 and 4.5 network layers, kernels/k and kernels/m (d4r-kernels.txt lists hashes of the DLSS code each kernel replaces; it holds no NVIDIA code) d4r/d4r.ini, d4r/d4r-check.sh, D4R_README.txt -@installer install.sh downloads and verifies NVIDIA DLLs; no driver installation +@installer install.sh downloads and verifies NVIDIA DLLs; no driver installation. Then builds the engine's +@installer models from them with d4r/tools/build-engine-models.sh +@installer d4r/tools/models/ d4r's engine-model compilers and shader sources (engine/, kernels/tools, kernels/rr, +@installer vulkan/ptx2glsl.py) and the D3D12 test app (tools/d3d12_dlss_harness.cpp) +@installer d4r/tools/models/bin/glslangValidator +@installer Khronos glslang 16.6.0 (unmodified release build), https://github.com/KhronosGroup/glslang +@installer License: d4r/licenses/glslang-LICENSE.txt Third-party software, unmodified or patched by d4r: d4r/zluda/libcuda.so ZLUDA (Apache License 2.0 or MIT), https://github.com/vosen/ZLUDA @@ -44,8 +50,10 @@ Third-party software, unmodified or patched by d4r: @full d4r/nvngx_dlss.dll NVIDIA DLSS Super Resolution library @DLSS_VERSION@ @full d4r/ngx/_nvngx.dll NVIDIA NGX runtime from NVIDIA's Windows display driver, @NGX_VERSION@ @installer NVIDIA DLLs are not bundled. install.sh downloads DLSS 310.7.0 from NVIDIA/DLSS -@installer commit a291cc7d2cc642a51566f3dfd5376f635cd1b284 and _nvngx.dll from NVIDIA driver 596.36. -@installer URLs and SHA-256 hashes are pinned in install.sh. NVIDIA license terms apply. +@installer commit a291cc7d2cc642a51566f3dfd5376f635cd1b284, DLSS Ray Reconstruction 310.9.1 from commit +@installer 374959484e79a640feaba44c93ac8cfb0a03f5b5 and _nvngx.dll from NVIDIA driver 596.36. +@installer URLs and SHA-256 hashes are pinned in install.sh. NVIDIA license terms apply. The engine models +@installer install.sh builds in d4r/engine hold values read from those DLLs: they are not part of this zip. @installer Included NVIDIA PTX-derived kernels (not covered by d4r licenses): @installer d4r/kernels/*/hiluma_engine_*, rrlite_enc0_*, rrlite_dec0_*, rrlite_post_*, rrlite_downsample_* @installer NVIDIA's PTX with parts replaced by d4r code (kernels/tex) or translated to diff --git a/packaging/build_engine_models.sh b/packaging/build_engine_models.sh new file mode 100755 index 0000000..525651f --- /dev/null +++ b/packaging/build_engine_models.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +# 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] +# +# 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 +# NVIDIA's DLSS keeps these weights packed in nvngx_dlss.dll; they are read where NGX unpacks +# them: the bundled D3D12 test app renders one frame per model through this d4r folder under +# 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). +# 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 +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 ;; + *) break ;; + esac +done +TOOLS="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +KIT="$TOOLS/models" +RUNTIME="$(cd -- "${1:-$TOOLS/..}" && pwd)" +[[ -f "$RUNTIME/d4r.ini" && -d "$KIT/engine" ]] || fail "no d4r folder with the model tools at $RUNTIME" +GAME="$(dirname -- "$RUNTIME")" +DLSSD_SHA256=4bc7ea5fcb2f32cf86bc2cb072e8d2860914a0be511cbdcb2fc206c1d9d83b80 # nvngx_dlssd.dll 310.9.1 +DLSS_SHA256=be6e434a94ca32499515eb62ca0e6c274526055d568d0426e4c652dcdfb6ee6e # nvngx_dlss.dll 310.7.0 + +command -v python3 > /dev/null || fail 'python3 is missing (install Python 3)' +python3 -c 'import numpy' 2> /dev/null || fail 'numpy is missing (install python-numpy / python3-numpy)' +export PATH="$KIT/bin:$PATH" # the bundled glslangValidator +glslangValidator --version > /dev/null 2>&1 || fail "glslangValidator ($KIT/bin) does not run on this system" +sha() { sha256sum -- "$1" | cut -d' ' -f1; } + +WORK="$(mktemp -d "${TMPDIR:-/tmp}/d4r-models.XXXXXX")" +trap 'rm -rf -- "$WORK"' EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + +# replace RUNTIME/engine/NAME with the files of a built model that the runtime reads (a rename: safe while a game runs) +place() { # place NAME DIR FILE... + local name=$1 src=$2 dst="$RUNTIME/engine/$1" f + shift 2 + mkdir -p "$RUNTIME/engine" "$WORK/place/$name" + for f in "$@"; do cp -- "$src/$f" "$WORK/place/$name/"; done + rm -rf -- "$dst.new"; mv -- "$WORK/place/$name" "$dst.new" + rm -rf -- "$dst.old"; [[ ! -e "$dst" ]] || mv -- "$dst" "$dst.old" + mv -- "$dst.new" "$dst"; rm -rf -- "$dst.old" + printf ' engine/%s (%s files)\n' "$name" "$(ls "$dst" | wc -l)" +} +model_files() { # rr.txt and the files it names, for model directory $1 + echo rr.txt + awk '$1 == "stage" { print $3; if ($5 != "-") print $5; if ($6 ~ /\.args$/) print $6 } $1 == "template" { print $3 }' "$1/rr.txt" | sort -u +} +run() { # run LOG COMMAND...: the command's output in WORK/LOG, shown when it fails + local log="$WORK/$1"; shift + "$@" > "$log" 2>&1 || { tail -n 20 "$log" >&2; fail "failed: $(basename -- "$2") (log above)"; } +} + +if (( DO_RR )); then + DLL="$RUNTIME/nvngx_dlssd.dll" + [[ -f "$DLL" && "$(sha "$DLL")" == "$DLSSD_SHA256" ]] || fail "Ray Reconstruction models need nvngx_dlssd.dll 310.9.1 in $RUNTIME (run install.sh)" + echo 'Building the Ray Reconstruction models (presets D, E and F) from nvngx_dlssd.dll...' + for p in D E; do + l=$(tr DE de <<< "$p") + bash "$KIT/engine/rr/build_native_model.sh" --dll "$DLL" "$p" "$WORK/rr-$l" > "$WORK/rr-$l.log" 2>&1 || + { tail -n 20 "$WORK/rr-$l.log" >&2; fail "preset $p model failed"; } + place "rr-$l" "$WORK/rr-$l" $(model_files "$WORK/rr-$l") exposure_rr0.spv exposure_rr1.spv + done + run ptx-f.log python3 "$KIT/kernels/tools/extract_dlss_ptx.py" "$DLL" "$WORK/ptx-f" + run rr-f.log python3 "$KIT/engine/compile_rr2.py" --dll "$DLL" "$WORK/rr-f" --ptx-dir "$WORK/ptx-f" + place rr-f "$WORK/rr-f" $(model_files "$WORK/rr-f") enc0-aux.bin exposure_f0.spv exposure_f1.spv +fi + +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 + [[ -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")")" + [[ -d "$STEAM_ROOT/steamapps" || ! -d "$HOME/.local/share/Steam" ]] || STEAM_ROOT="$HOME/.local/share/Steam" + # the test app beside the D3D12 pair the game uses (proxy release: the game folder; ASI release: the d4r folder) + APP="$WORK/app"; mkdir -p "$APP" + cp -- "$KIT/bin/d3d12_dlss_harness.exe" "$APP/" + if [[ -f "$RUNTIME/d4r12core.dll" ]]; then + cp -- "$RUNTIME/d3d12.dll" "$RUNTIME/d4r12core.dll" "$APP/" + elif [[ -f "$GAME/d3d12core.dll" ]]; then + cp -- "$GAME/d3d12.dll" "$GAME/d3d12core.dll" "$APP/" + else + fail "d4r's d3d12.dll / d3d12core.dll not found next to $RUNTIME" + fi + winpath() { printf 'Z:%s' "$(printf '%s' "$1" | tr '/' '\\')"; } + dump() { # dump NAME PRESET: the uploads of one frame of preset PRESET in WORK/NAME/replay + local w="$WORK/$1" + mkdir -p "$w/replay" + printf ' rendering one frame with model %s through d4r (GE-Proton %s)...\n' "$1" "$(basename "$PROTON")" + (cd "$APP" && env STEAM_COMPAT_CLIENT_INSTALL_PATH="$STEAM_ROOT" STEAM_COMPAT_DATA_PATH="$WORK/prefix" \ + PROTON_FORCE_NVAPI=1 DXVK_NVAPI_GPU_ARCH=AD100 WINEDLLOVERRIDES='d3d12=n,b;d3d12core=n,b;d4r12core=n,b' \ + D4R_ENGINE=0 D4R_DLSS_PRESET="$2" D4R_HARNESS_CREATE_FLAGS=0x4B D4R_SHIM_LOG="$(winpath "$w/shim.log")" \ + D4R_CUDA_REPLAY_DUMP_DIR="$w/replay" D4R_CUDA_REPLAY_DUMP_LIMIT=60 \ + "$PROTON/proton" run "$APP/d3d12_dlss_harness.exe" "$(winpath "$RUNTIME/nvngx.dll")" "$(winpath "$w/out.raw")" \ + 1 640 360 1280 720) > "$w/run.log" 2>&1 || true + if ! ls "$w/replay" | grep -q "$3"; then + tail -n 15 "$w/run.log" >&2 + [[ ! -f "$w/shim.log" ]] || tail -n 15 "$w/shim.log" >&2 + fail "model $1: the test frame did not run through DLSS (logs above)" + fi + } + echo 'Building the Super Resolution models (K, M and L) from what NGX uploads...' + mkdir -p "$WORK/prefix" + dump k 11 dltss_pwin_dec0_layer + run k-extract.log python3 "$KIT/engine/extract_k.py" "$WORK/k/replay" "$WORK/k/model" + run k-lut.log python3 "$KIT/engine/prepare_k.py" "$WORK/k" "$WORK/k/case" --lut-only + for v in k k-ldr; do + run "$v.log" python3 "$KIT/engine/compile_k.py" "$WORK/k/model" "$WORK/k/case/lut.bin" "$WORK/$v-out" \ + $([[ $v == k-ldr ]] && echo --ldr) + place "$v" "$WORK/$v-out" $(ls "$WORK/$v-out") + done + rm -rf -- "$WORK/k" + for c in "m 13 rrlite_enc0_4x4_mvlo_hdr_folded" "l 12 rrlite_enc0_4x4_mvlo_hdr$"; do + set -- $c + dump "$1" "$2" "$3" + for v in "$1" "$1-ldr"; do + run "$v.log" python3 "$KIT/engine/compile_m.py" "$WORK/$1" "$WORK/$v-out" $([[ $v == *-ldr ]] && echo --ldr) + place "$v" "$WORK/$v-out" $(ls "$WORK/$v-out") + done + rm -rf -- "${WORK:?}/$1" + done +fi +printf 'Engine models are in %s/engine.\n' "$RUNTIME" diff --git a/scripts/check_redistributable.py b/scripts/check_redistributable.py index 5bede64..858253c 100755 --- a/scripts/check_redistributable.py +++ b/scripts/check_redistributable.py @@ -23,6 +23,8 @@ from pathlib import Path, PurePosixPath # Files the native engine's tools write from NVIDIA's DLSS (engine/README.md); NOTICE names them. MODEL_DATA = {'weights.bin', 'offsets.bin', 'lut.bin', 'hipnet.bin', 'model.json'} +# ... and the M / L and Ray Reconstruction models' (engine/compile_m.py, compile_rr.py, compile_rr2.py) +MODEL_DATA_PATTERNS = ('weights8.bin', 'weights16.bin', 'weights-*.bin', '*.args', 'enc0-aux.bin', '*.generated.*') # Compiled or extracted NVIDIA GPU code. NVIDIA_CODE_SUFFIXES = {'.ptx', '.cubin', '.fatbin', '.nvngx'} # Kernels kernels/build.sh builds from NVIDIA's PTX (tex/l families and the PTX-translated hiluma kernels). @@ -62,7 +64,7 @@ def findings_for(path, read, release=None): suffix = PurePosixPath(lower).suffix full = release == 'full' problems = [] - if lower in MODEL_DATA: + if lower in MODEL_DATA or any(fnmatch.fnmatch(lower, pattern) for pattern in MODEL_DATA_PATTERNS): problems.append('engine model data read from NVIDIA\'s DLSS') if suffix in NVIDIA_CODE_SUFFIXES: problems.append('NVIDIA GPU code') diff --git a/scripts/package_release.sh b/scripts/package_release.sh index 730849e..6d289ed 100755 --- a/scripts/package_release.sh +++ b/scripts/package_release.sh @@ -140,6 +140,8 @@ if [[ "$VARIANT" != clean ]]; then [[ "$INSTALL_MODE" != asi ]] || installer_dir="$STAGE/d4r" cp "$ROOT/install.sh" "$installer_dir/install.sh" chmod +x "$installer_dir/install.sh" + # install.sh builds the engine's models from the downloaded DLLs (D4R_GLSLANG, D4R_GLSLANG_LICENSE) + "$ROOT/scripts/stage_engine_kit.sh" "$STAGE/d4r" # The downloader is pinned to DLSS 310.7.0: refuse mismatched release inputs. expected=$(sed -n "s/^DLSS_SHA256=//p" "$ROOT/install.sh") [[ "$(sha256sum "$D4R_BUNDLE_DLSS" | cut -d' ' -f1)" == "$expected" ]] || { diff --git a/scripts/stage_engine_kit.sh b/scripts/stage_engine_kit.sh new file mode 100755 index 0000000..45a384d --- /dev/null +++ b/scripts/stage_engine_kit.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Puts the engine-model builder into a release's d4r folder: d4r/tools/build-engine-models.sh (install.sh runs it) +# and d4r/tools/models/ with d4r's model compilers and shader sources, the D3D12 test app and glslangValidator. +# Only d4r's own code and Khronos' glslang go in; the models are built on the user's machine from their DLLs. +# +# usage: scripts/stage_engine_kit.sh D4R_FOLDER +# D4R_GLSLANG glslang release archive or extracted folder (bin/glslangValidator; Khronos 16.6.0 tested) +# D4R_GLSLANG_LICENSE its LICENSE.txt (the release archives have none; the tag's LICENSE.txt in KhronosGroup/glslang) +# D4R_HARNESS_EXE the D3D12 test app (default build/d3d12_dlss_harness.exe, scripts/build_d3d12_dlss_harness.sh) +set -euo pipefail +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +D4R="$(realpath "${1:?usage: stage_engine_kit.sh D4R_FOLDER}")" +: "${D4R_GLSLANG:?set D4R_GLSLANG to a glslang release (glslang-16.6.0-linux-x86_64-release.tar.gz)}" +: "${D4R_GLSLANG_LICENSE:?set D4R_GLSLANG_LICENSE to the LICENSE.txt of glslang}" +HARNESS="${D4R_HARNESS_EXE:-$ROOT/build/d3d12_dlss_harness.exe}" +[[ -f "$HARNESS" ]] || { echo "missing $HARNESS (scripts/build_d3d12_dlss_harness.sh)" >&2; exit 2; } +KIT="$D4R/tools/models" +rm -rf "$KIT" +mkdir -p "$KIT/bin" "$KIT/engine/rr" "$KIT/kernels/tools" "$KIT/kernels/rr" "$KIT/vulkan" "$D4R/licenses" +copy() { # copy SRC_DIR DST_DIR PATTERN...: never tests + local src=$1 dst=$2 pat f + shift 2 + for pat in "$@"; do + for f in "$ROOT/$src"/$pat; do + [[ -f "$f" ]] || continue + case "$(basename "$f")" in test_*) continue ;; esac + cp "$f" "$dst/" + done + done +} +copy engine "$KIT/engine" '*.py' '*.comp' '*.glsl' +copy engine/rr "$KIT/engine/rr" '*.py' '*.comp' '*.glsl' '*.txt' '*.npy' '*.sh' +copy kernels/tools "$KIT/kernels/tools" '*.py' +copy kernels/rr "$KIT/kernels/rr" '*.py' +copy vulkan "$KIT/vulkan" '*.py' # ptx2glsl.py: engine/rr/ptx2rr.py builds on it +# the model compilers import these test modules' packing helpers +cp "$ROOT/engine/test_k.py" "$ROOT/engine/test_m.py" "$KIT/engine/" +cp "$ROOT/engine/rr/test_layer.py" "$KIT/engine/rr/" +cp "$HARNESS" "$KIT/bin/d3d12_dlss_harness.exe" +TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT +GL="$D4R_GLSLANG" +if [[ -f "$GL" ]]; then + case "$GL" in *.zip) unzip -q "$GL" -d "$TMP" ;; *) tar xf "$GL" -C "$TMP" ;; esac + GL="$TMP" +fi +cp "$GL/bin/glslangValidator" "$KIT/bin/glslangValidator" +chmod +x "$KIT/bin/glslangValidator" +cp "$D4R_GLSLANG_LICENSE" "$D4R/licenses/glslang-LICENSE.txt" +cp "$ROOT/packaging/build_engine_models.sh" "$D4R/tools/build-engine-models.sh" +chmod +x "$D4R/tools/build-engine-models.sh" +printf 'Staged the engine-model builder in %s (%s)\n' "$D4R/tools" "$(du -sh "$D4R/tools" | cut -f1)"