rr: add FSR Ray Regeneration, exact RDNA3 inference and motion experiments

Add an experimental FSR Ray Regeneration backend for D3D12 RR requests:
- Convert depth, motion, normals and albedos into AMD denoiser inputs.
- Split and recompose diffuse/specular signals, then run Super Sampling.
- Add stability/detail controls, demodulation guards and halo limiting.
- Handle AMD provider discovery under NVIDIA GPU spoofing.
- Add runtime probes, synthetic reference scenes and per-dispatch profiling.

Add exact gfx11 DLSS-RR inference using f16 cooperative matrices:
- Reproduce FP8 conversions, accumulation and camera reprojection arithmetic.
- Widen model weights and avoid requiring VK_EXT_shader_float8.
- Extend model building, replay tools and descriptor metadata.

Expand motion preprocessing and experimental AW2 native-motion support:
- Add tiled LDS dilation, padded allocation handling and thin-only sky fill.
- Order dilation with input waits and NGX on the selected stream.
- Add jitter-aligned native composition, hybrid routing and wire history repair.
- Add prepared masks, sparse repair and independent motion/repair controls.

Add optional fused R11G11B10 input/output conversion, sampled stage timings
and profile summarization. Extend configuration, packaging, documentation,
FidelityFX headers and CPU/GPU regression coverage.
This commit is contained in:
ayo committed 2026-10-16 04:55:25 -04:00
1 parent 17c1828f97
commit 34e6b0fe71
83 files changed
+11300 -195

No files matched your search

+1 -1
View File
@@ -25,7 +25,7 @@ PARAM_OBJECT="$ROOT/build/d4r_ngx_param_msvc.obj"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -Wno-missing-field-initializers -DD4R_ENGINE_VK_TABLE -I"$ROOT/build/vulkan-include" -I"$ROOT/build/vulkan-staging" -shared -static -static-libgcc -static-libstdc++ \
"$ROOT/tools/d4r_nvngx_shim.cpp" "$ROOT/tools/d4r_ngx_param_host.cpp" "$PARAM_OBJECT" \
"$ROOT/engine/runtime.cpp" "$ROOT/engine/game.cpp" "$ROOT/engine/game_m.cpp" "$ROOT/engine/game_rr.cpp" "$ROOT/engine/vk_dispatch.cpp" \
-Wl,--entry,d4r_dll_entry -o "$ROOT/build/d4r_nvngx.dll"
-ldxgi -lbcrypt -Wl,--entry,d4r_dll_entry -o "$ROOT/build/d4r_nvngx.dll"
printf 'Built %s\n' "$ROOT/build/d4r_nvngx.dll"
cp "$ROOT/build/d4r_nvngx.dll" "$ROOT/build/d4r.asi"
printf 'Built %s\n' "$ROOT/build/d4r.asi"
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
# Builds build/fsr_rr_probe.exe, the standalone AMD FSR Ray Regeneration provider/execution check
# (tools/fsr_rr_probe.cpp). It needs no NVIDIA or d4r runtime files.
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
VULKAN_INCLUDE="${VULKAN_INCLUDE:-/usr/include}"
mkdir -p "$ROOT/build/vulkan-include"
ln -sfn "$VULKAN_INCLUDE/vulkan" "$ROOT/build/vulkan-include/vulkan"
ln -sfn "$VULKAN_INCLUDE/vk_video" "$ROOT/build/vulkan-include/vk_video"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -Wno-missing-field-initializers -municode -static -static-libgcc \
-static-libstdc++ -I"$ROOT/build/vulkan-include" "$ROOT/tools/fsr_rr_probe.cpp" -ld3d12 -ldxgi -o "$ROOT/build/fsr_rr_probe.exe"
printf 'Built %s\n' "$ROOT/build/fsr_rr_probe.exe"
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
# Builds build/rr_backend_check.exe (tools/rr_backend_check.cpp): a DLSS Ray Reconstruction request
# through d4r_nvngx.dll, measured against the synthetic scene's ground truth. Builds the shim first,
# for the NGX parameter object it links against.
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
"$ROOT/scripts/build_d4r_nvngx_shim.sh" >/dev/null
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -Wno-missing-field-initializers -static -static-libgcc -static-libstdc++ \
"$ROOT/tools/rr_backend_check.cpp" "$ROOT/tools/d4r_ngx_param_host.cpp" "$ROOT/build/d4r_ngx_param_msvc.obj" \
-ld3d12 -ldxgi -o "$ROOT/build/rr_backend_check.exe"
printf 'Built %s\n' "$ROOT/build/rr_backend_check.exe"
+17 -2
View File
@@ -6,7 +6,11 @@ set -euo pipefail
# the game launcher takes as D4R_VKD3D_DIR.
# usage: build_vkd3d_proton_d4r.sh OUT_DIR
# Env: VKD3D_PROTON_SRC (clone, default ~/.cache/d4r-vkd3d-proton),
# VKD3D_PROTON_COMMIT (default 3dfc6f07, the base GE-Proton11-3 ships).
# VKD3D_PROTON_COMMIT (default 3dfc6f07, the base GE-Proton11-3 ships),
# D4R_VKD3D_FSR_RR=1: also what AMD's FSR Ray Regeneration needs on RDNA 3
# ([RayReconstruction] Backend = fsr): dxil-spirv's accepted scalar FP8 fallback (upstream PR 307,
# merge f9f6294f, cherry-picked onto the linked translator) and -Denable_extended_emulation=true,
# in a build directory of its own. Run games with DXIL_SPIRV_CONFIG=wmma_rdna3_workaround.
if [[ $# -ne 1 ]]; then
printf 'usage: %s OUT_DIR\n' "$0" >&2
exit 2
@@ -22,7 +26,18 @@ BUILD="$SRC-build"
git -C "$SRC" checkout -q -f -B d4r-split "$COMMIT"
git -C "$SRC" submodule update --init --recursive -q
git -C "$SRC" apply "$ROOT"/patches/vkd3d-proton/*.patch
[[ -d "$BUILD" ]] || meson setup --cross-file "$SRC/build-win64.txt" --buildtype release -Denable_tests=false "$BUILD" "$SRC"
EXTRA=()
if [[ "${D4R_VKD3D_FSR_RR:-0}" == 1 ]]; then
DXIL="$SRC/subprojects/dxil-spirv"
git -C "$DXIL" fetch -q origin f9f6294f3a6795e071bef3a64d2bee99e7c1b7bc
if ! git -C "$DXIL" merge-base --is-ancestor f9f6294f3a6795e071bef3a64d2bee99e7c1b7bc^2 HEAD; then
git -C "$DXIL" -c user.name=d4r -c user.email=d4r@localhost cherry-pick -x \
$(git -C "$DXIL" rev-list --reverse f9f6294f3a6795e071bef3a64d2bee99e7c1b7bc^1..f9f6294f3a6795e071bef3a64d2bee99e7c1b7bc^2)
fi
BUILD="$SRC-build-fsrrr"
EXTRA=(-Denable_extended_emulation=true)
fi
[[ -d "$BUILD" ]] || meson setup --cross-file "$SRC/build-win64.txt" --buildtype release -Denable_tests=false "${EXTRA[@]}" "$BUILD" "$SRC"
ninja -C "$BUILD"
mkdir -p "$OUT"
x86_64-w64-mingw32-strip -o "$OUT/d3d12.dll" "$BUILD/libs/d3d12/d3d12.dll"
+3
View File
@@ -5,6 +5,9 @@ OUT="${1:-$ROOT/build/vulkan-staging}"
mkdir -p "$OUT"
glslangValidator -V --target-env vulkan1.0 -o "$OUT/read.spv" "$ROOT/kernels/support/vulkan_read.comp" >/dev/null
glslangValidator -V --target-env vulkan1.0 -o "$OUT/wait.spv" "$ROOT/kernels/support/vulkan_wait.comp" >/dev/null
# FSR Ray Regeneration backend (tools/d4r_fsr_rr_passes.h)
glslangValidator -V --target-env vulkan1.0 -o "$OUT/fsr_rr_prepare.spv" "$ROOT/kernels/support/fsr_rr_prepare.comp" >/dev/null
glslangValidator -V --target-env vulkan1.0 -o "$OUT/fsr_rr_compose.spv" "$ROOT/kernels/support/fsr_rr_compose.comp" >/dev/null
for format in rgba16f rgba32f r11f_g11f_b10f rgb10_a2 rgba8; do
glslangValidator -V --target-env vulkan1.0 -DOUTPUT_FORMAT="$format" \
-o "$OUT/write_$format.spv" "$ROOT/kernels/support/vulkan_write.comp" >/dev/null
+34
View File
@@ -100,6 +100,34 @@ def main(argv):
env["D4R_RR_PRESET"] = rr_model
else:
fail(f"[RayReconstruction] Model {rr_model!r}: use auto, default, D, E or F")
# Backend: which denoiser serves a game's Ray Reconstruction request. dlss (the default) is
# NVIDIA's model (Model above); fsr is AMD's FSR Ray Regeneration, followed by Super Sampling.
rr_backend = get("RayReconstruction", "Backend")
if rr_backend is not None:
if rr_backend.lower() not in ("dlss", "fsr"):
fail(f"[RayReconstruction] Backend {rr_backend!r}: use dlss or fsr")
env["D4R_RR_BACKEND"] = rr_backend.lower()
# FSR denoiser tuning: FsrStabilityBias (auto = AMD's default, or a number >= 0) and FsrDetail (the share,
# 0-1, of the colour that goes around the denoiser; 0 = off).
fsr_stability = get("RayReconstruction", "FsrStabilityBias")
if fsr_stability is not None and fsr_stability.lower() != "auto":
try:
if float(fsr_stability) < 0:
raise ValueError
except ValueError:
fail(f"[RayReconstruction] FsrStabilityBias {fsr_stability!r}: use auto or a number >= 0")
env["D4R_FSR_RR_STABILITY_BIAS"] = fsr_stability
fsr_detail = get("RayReconstruction", "FsrDetail")
if fsr_detail is not None:
try:
if not 0 <= float(fsr_detail) <= 1:
raise ValueError
except ValueError:
fail(f"[RayReconstruction] FsrDetail {fsr_detail!r}: use a number from 0 to 1")
env["D4R_FSR_RR_DETAIL"] = fsr_detail
fsr_denoiser = path_value("RayReconstruction", "FsrDenoiser")
if fsr_denoiser:
env["D4R_FSR_RR_DLL"] = fsr_denoiser
age = get("Latency", "FrameAge")
if age is not None:
@@ -162,6 +190,7 @@ def main(argv):
if value is not None:
env[var] = "1" if value else "0"
value = get("Interop", "MarkerPollUs")
env["D4R_MOTION_THIN_SKY"] = "1" if flag("Interop", "MotionDilationThinSky") else "0"
dilation = get("Interop", "MotionVectorDilation")
if dilation is not None and dilation not in ("0", "1", "2"):
fail("[Interop] MotionVectorDilation must be 0, 1 or 2")
@@ -213,6 +242,11 @@ def main(argv):
if flag("Debug", "Profile"):
env["D4R_PROFILE"] = "1"
every = get("Debug", "ProfileLogEvery")
if every is not None:
if not every.isascii() or not every.isdecimal() or not 1 <= int(every) <= 4294967295:
fail(f"[Debug] ProfileLogEvery must be 1-4294967295, not {every!r}")
env["D4R_PROFILE_LOG_EVERY"] = str(int(every))
if path_value("Debug", "LogDir"):
env["D4R_GAME_LOG_DIR"] = path_value("Debug", "LogDir")
+5
View File
@@ -128,6 +128,11 @@ cp -r "$ROCM_RUNTIME/lib" "$STAGE/d4r/rocm/lib"
"$STAGE/d4r/nvcuda.dll" "$STAGE/d4r/zluda/libcuda.so" "$STAGE/d4r/rocm/lib/"*
cp "$ROOT/packaging/d4r.ini" "$STAGE/d4r/d4r.ini"
cp "$ROOT/packaging/d4r-check.sh" "$STAGE/d4r/d4r-check.sh"
# AMD FSR Ray Regeneration 1.2 for [RayReconstruction] Backend = fsr: AMD's unmodified denoiser DLL (MIT)
if [[ -n "${D4R_BUNDLE_FSR_RR_DLL:-}" ]]; then
cp "$D4R_BUNDLE_FSR_RR_DLL" "$STAGE/d4r/amd_fidelityfx_denoiser_dx12.dll"
cp "$ROOT/third_party/fidelityfx/LICENSE.txt" "$STAGE/d4r/licenses/FidelityFX-LICENSE.txt"
fi
if [[ "$VARIANT" != clean ]]; then
: "${D4R_BUNDLE_DLSS:?set D4R_BUNDLE_DLSS}" "${D4R_BUNDLE_TEX:?set D4R_BUNDLE_TEX}"
if [[ "$VARIANT" == full ]]; then
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
set -euo pipefail
# Runs build/fsr_rr_probe.exe through a Proton build in its own prefix, with a given vkd3d-proton
# (d3d12.dll + d3d12core.dll) and AMD denoiser DLL copied next to the exe, as a game install would
# have them. Nothing outside APP_DIR and the prefix is touched.
# usage: run_fsr_rr_probe_proton.sh PROTON_DIR VKD3D_DIR DENOISER_DLL OUT_DIR [probe args...]
# Env: D4R_FSR_PROBE_COMPAT prefix (default ${TMPDIR:-/tmp}/d4r-fsr-rr-probe-compat)
# D4R_FSR_PROBE_APP app directory (default OUT_DIR/app)
# DXIL_SPIRV_CONFIG passed through; defaults to wmma_rdna3_workaround (gfx11 WMMA path)
# D4R_FSR_PROBE_SPOOF=1 report an NVIDIA GPU the way d4r's DLSS games run
# (PROTON_FORCE_NVAPI=1 DXVK_NVAPI_GPU_ARCH=AD100)
if [[ $# -lt 4 ]]; then
printf 'usage: %s PROTON_DIR VKD3D_DIR DENOISER_DLL OUT_DIR [probe args...]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
VKD3D_DIR="$(realpath "$2")"
DENOISER="$(realpath "$3")"
OUT="$(realpath -m "$4")"
shift 4
winpath() { printf 'Z:%s' "$(printf '%s' "$1" | tr '/' '\\')"; }
[[ -f "$ROOT/build/fsr_rr_probe.exe" ]] || "$ROOT/scripts/build_fsr_rr_probe.sh" >/dev/null
APP="${D4R_FSR_PROBE_APP:-$OUT/app}"
mkdir -p "$APP" "$OUT"
cp -f "$ROOT/build/fsr_rr_probe.exe" "$APP/"
cp -f "$VKD3D_DIR/d3d12.dll" "$VKD3D_DIR/d3d12core.dll" "$APP/"
cp -f "$DENOISER" "$APP/amd_fidelityfx_denoiser_dx12.dll"
{
printf 'proton=%s\n' "$PROTON_DIR"
sha256sum "$APP/d3d12.dll" "$APP/d3d12core.dll" "$APP/amd_fidelityfx_denoiser_dx12.dll" "$APP/fsr_rr_probe.exe"
} > "$OUT/run-manifest.txt"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="$(realpath -m "${D4R_FSR_PROBE_COMPAT:-${TMPDIR:-/tmp}/d4r-fsr-rr-probe-compat}")"
mkdir -p "$STEAM_COMPAT_DATA_PATH"
export WINEDLLOVERRIDES="d3d12,d3d12core=n,b${WINEDLLOVERRIDES:+;$WINEDLLOVERRIDES}"
export DXIL_SPIRV_CONFIG="${DXIL_SPIRV_CONFIG-wmma_rdna3_workaround}"
export VKD3D_SHADER_CACHE_PATH="${VKD3D_SHADER_CACHE_PATH:-$(winpath "$OUT")}"
export VKD3D_DEBUG="${VKD3D_DEBUG:-warn}"
if [[ "${D4R_FSR_PROBE_SPOOF:-0}" == 1 ]]; then
export PROTON_FORCE_NVAPI=1 DXVK_NVAPI_GPU_ARCH=AD100
fi
printf 'DXIL_SPIRV_CONFIG=%s spoof=%s\n' "$DXIL_SPIRV_CONFIG" "${D4R_FSR_PROBE_SPOOF:-0}" >> "$OUT/run-manifest.txt"
set +e
"$PROTON_DIR/proton" run "$APP/fsr_rr_probe.exe" "$(winpath "$APP/amd_fidelityfx_denoiser_dx12.dll")" \
"$(winpath "$OUT")" "$@" 2> "$OUT/stderr.log" | tee "$OUT/stdout.log"
status=${PIPESTATUS[0]}
set -e
printf 'exit=%s\n' "$status" >> "$OUT/run-manifest.txt"
exit "$status"
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
# Runs build/rr_backend_check.exe through a Proton build in its own prefix, against a portable d4r
# folder (d4r.ini, d4r_nvngx.dll, nvcuda.dll, ngx/, zluda/, and amd_fidelityfx_denoiser_dx12.dll or
# nvngx_dlssd.dll for the backend under test), with the d4r vkd3d-proton next to the exe.
# The GPU is reported as NVIDIA (PROTON_FORCE_NVAPI=1 DXVK_NVAPI_GPU_ARCH=AD100), as d4r's games run.
# usage: run_rr_backend_check_proton.sh PROTON_DIR VKD3D_DIR D4R_DIR OUT_DIR [check args...]
# Env: D4R_RR_BACKEND (dlss|fsr) and any other shim variable are passed through.
# D4R_RR_CHECK_COMPAT prefix (default ${TMPDIR:-/tmp}/d4r-rr-check-compat)
if [[ $# -lt 4 ]]; then
printf 'usage: %s PROTON_DIR VKD3D_DIR D4R_DIR OUT_DIR [check args...]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
VKD3D_DIR="$(realpath "$2")"
D4R_DIR="$(realpath "$3")"
OUT="$(realpath -m "$4")"
shift 4
winpath() { printf 'Z:%s' "$(printf '%s' "$1" | tr '/' '\\')"; }
[[ -f "$ROOT/build/rr_backend_check.exe" ]] || "$ROOT/scripts/build_rr_backend_check.sh" >/dev/null
APP="$OUT/app"
mkdir -p "$APP"
cp -f "$ROOT/build/rr_backend_check.exe" "$APP/"
cp -f "$VKD3D_DIR/d3d12.dll" "$VKD3D_DIR/d3d12core.dll" "$APP/"
{
printf 'proton=%s\nd4r=%s\nbackend=%s\n' "$PROTON_DIR" "$D4R_DIR" "${D4R_RR_BACKEND:-ini}"
sha256sum "$APP/d3d12.dll" "$APP/d3d12core.dll" "$D4R_DIR"/*.dll
} > "$OUT/run-manifest.txt"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="$(realpath -m "${D4R_RR_CHECK_COMPAT:-${TMPDIR:-/tmp}/d4r-rr-check-compat}")"
mkdir -p "$STEAM_COMPAT_DATA_PATH"
export WINEDLLOVERRIDES="d3d12,d3d12core=n,b${WINEDLLOVERRIDES:+;$WINEDLLOVERRIDES}"
export DXIL_SPIRV_CONFIG="${DXIL_SPIRV_CONFIG-wmma_rdna3_workaround}"
export VKD3D_SHADER_CACHE_PATH="${VKD3D_SHADER_CACHE_PATH:-$(winpath "$OUT")}"
export PROTON_FORCE_NVAPI=1 DXVK_NVAPI_GPU_ARCH=AD100
export D4R_SHIM_LOG="$(winpath "$OUT/d4r_nvngx.log")"
set +e
"$PROTON_DIR/proton" run "$APP/rr_backend_check.exe" "$(winpath "$D4R_DIR/d4r_nvngx.dll")" "$(winpath "$OUT")" "$@" \
> "$OUT/stdout.log" 2> "$OUT/stderr.log"
status=$?
set -e
printf 'exit=%s\n' "$status" >> "$OUT/run-manifest.txt"
grep -E '^(check=|overall=|tonemapped)' "$OUT/stdout.log" || true
exit "$status"
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Summarize warm D4R_PROFILE samples without merging feature instances or sizes.
GPU pass fields and delayed vk_* fields are summarized independently. Their
per-line difference is deliberately not calculated; they describe different frames.
"""
import argparse
from collections import defaultdict
import json
import math
from pathlib import Path
import re
import statistics
GROUP_FIELDS = ('render', 'output', 'preset', 'quality', 'flags', 'input_wait',
'feature', 'native_field', 'native_substitute', 'wire_requested', 'gpu_completion', 'vk_output_mode', 'vk_input_mode')
FIELDS = ('vk_total', 'dlss_gpu', 'vk_input', 'vk_dlss_wait', 'vk_output',
'native_motion_gpu', 'wire_repair_gpu', 'marker_wait', 'pipeline',
'throughput_interval')
def summarize(text, min_frame=300, since_clock=None, until_clock=None):
groups = defaultdict(list)
instance = 0
for line in text.splitlines():
if 'NVSDK_NGX_D3D12_CreateFeature(feature=' in line:
instance += 1
if 'D4R_PROFILE frame=' not in line:
continue
if since_clock is not None or until_clock is not None:
clock = re.search(r'^\[\s*([0-9.]+)\]', line)
if clock is None:
continue
seconds = float(clock[1])
if since_clock is not None and seconds < since_clock:
continue
if until_clock is not None and seconds > until_clock:
continue
values = dict(re.findall(r'(\w+)=([^\s]+)', line))
if int(values['frame']) < min_frame or values.get('reset') != '0':
continue
key = (instance, *(values.get(k, 'unknown') for k in
GROUP_FIELDS))
groups[key].append(values)
result = []
for key, samples in groups.items():
row = dict(zip(('feature_instance', *GROUP_FIELDS), key))
row.update(samples=len(samples), first_frame=int(samples[0]['frame']), last_frame=int(samples[-1]['frame']))
row['timings_ms'] = {}
for field in FIELDS:
values = [float(s.get(field, '-1')) for s in samples]
valid = [v for v in values if math.isfinite(v) and v >= 0]
row['timings_ms'][field] = (dict(n=len(valid), median=statistics.median(valid),
min=min(valid), max=max(valid)) if valid else None)
result.append(row)
return result
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('log', type=Path)
parser.add_argument('--min-frame', type=int, default=300)
parser.add_argument('--since-clock', type=float, help='minimum bracketed log-clock seconds')
parser.add_argument('--until-clock', type=float, help='maximum bracketed log-clock seconds')
args = parser.parse_args()
print(json.dumps(summarize(args.log.read_text(errors='replace'), args.min_frame,
args.since_clock, args.until_clock), indent=2))
if __name__ == '__main__':
main()