feat: add d4r inference engines and Windows parity tooling

Add native K/M/RR inference engines, HIP kernels, replay and validation
harnesses, and Windows DLSS setup and runtime support. Include GPU
profiling tools, build and packaging scripts, platform integration
patches, and implementation documentation.
This commit is contained in:
ayo committed 2026-10-16 08:54:47 -04:00
1 parent 25493b3198
commit 7c5d3c9157
430 files changed
+76191

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/bench_dlss_kernel.cpp" -ldl \
-o "$ROOT/build/bench_dlss_kernel"
printf 'Built %s\n' "$ROOT/build/bench_dlss_kernel"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
"$ROOT/scripts/build_d4r_nvngx_shim.sh"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -I"$ROOT/build/vulkan-include" -static -static-libgcc -static-libstdc++ \
"$ROOT/tools/d3d12_dlss_harness.cpp" "$ROOT/tools/d4r_ngx_param_host.cpp" "$ROOT/build/d4r_ngx_param_msvc.obj" \
-o "$ROOT/build/d3d12_dlss_harness.exe"
printf 'Built %s\n' "$ROOT/build/d3d12_dlss_harness.exe"
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
VULKAN_INCLUDE="${VULKAN_INCLUDE:-/usr/include}"
# Only the Vulkan headers from the host include tree, not its libc headers.
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" -I"$ROOT/build/vulkan-include" -std=c++20 -O2 -Wall -Wextra -Wno-missing-field-initializers -static -static-libgcc -static-libstdc++ \
"$ROOT/tools/d3d12_hip_interop_probe.cpp" -ld3d12 -o "$ROOT/build/d3d12_hip_interop_probe.exe"
printf 'Built %s\n' "$ROOT/build/d3d12_hip_interop_probe.exe"
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Build d4r-owned motion processing kernels and embed them in the Wine bridge.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="${1:-$ROOT/build/wine-nvcuda/generated}"
ROCM="${D4R_ROCM_DIR:-/opt/rocm}"
CLANG="$ROCM/lib/llvm/bin/clang++"
[[ -x "$CLANG" ]] || { echo "motion kernels need ROCm clang (D4R_ROCM_DIR)" >&2; exit 2; }
mkdir -p "$OUT"
for arch in gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201; do
"$CLANG" -x hip -nogpuinc -nogpulib --offload-device-only --offload-arch="$arch" \
--no-gpu-bundle-output -O3 -mno-wavefrontsize64 -o "$OUT/$arch.hsaco" \
"$ROOT/kernels/support/motion_dilate.hip"
done
python3 - "$OUT" <<'PY'
from pathlib import Path
import sys
root = Path(sys.argv[1])
lines = ['/* Generated from d4r-owned HIP source; do not edit. */', '#include <string.h>']
for p in sorted(root.glob('gfx*.hsaco')):
data = p.read_bytes()
lines.append(f'static const unsigned char motion_{p.stem}[] __attribute__((aligned(64))) = {{')
lines.extend(','.join(f'0x{x:02x}' for x in data[i:i+24]) + ',' for i in range(0,len(data),24))
lines.append('};')
lines.append('static const void* d4r_motion_image(const char* arch) {')
for p in sorted(root.glob('gfx*.hsaco')):
lines.append(f' if (strcmp(arch, "{p.stem}") == 0) return motion_{p.stem};')
lines.append(' return NULL;\n}')
(root/'d4r_motion_kernels.h').write_text('\n'.join(lines)+'\n')
PY
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CC="${MINGW_CC:-x86_64-w64-mingw32-gcc}"
mkdir -p "$ROOT/build"
"$CC" -std=c11 -O2 -Wall -Wextra -shared -static-libgcc \
"$ROOT/tools/d4r_nvapi_identity.c" -o "$ROOT/build/nvapi64.dll"
printf 'Built %s\n' "$ROOT/build/nvapi64.dll"
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
ROCM_ROOT="${ROCM_ROOT:-/opt/rocm}"
if [[ ! -f "$ROCM_ROOT/include/hip/hip_runtime_api.h" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ROCM_ROOT to a ROCm installation containing HIP headers and libamdhip64.so\n' >&2
exit 2
fi
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra -D__HIP_PLATFORM_AMD__=1 \
-I"$ROCM_ROOT/include" \
"$ROOT/tools/hip_vk_interop_probe.cpp" \
-L"$ROCM_ROOT/lib" -lamdhip64 -lvulkan \
-Wl,-rpath,"$ROCM_ROOT/lib" \
-o "$ROOT/build/hip_vk_interop_probe"
printf 'Built %s\n' "$ROOT/build/hip_vk_interop_probe"
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
CLANG_CL="${CLANG_CL:-clang-cl}"
if [[ -z "${NVSDK_NGX_INCLUDE:-}" || ! -f "$NVSDK_NGX_INCLUDE/nvsdk_ngx.h" ]]; then
printf '%s\n' "Set NVSDK_NGX_INCLUDE to a directory containing NVIDIA's nvsdk_ngx.h and nvsdk_ngx_defs.h" >&2
exit 2
fi
mkdir -p "$ROOT/build"
ABI_OBJECT="$ROOT/build/ngx_param_abi_probe_msvc.obj"
"$CLANG_CL" --target=x86_64-pc-windows-msvc /nologo /std:c++20 /O2 /c /GS- /GR- /EHs-c- /Zl \
"/Fo$ABI_OBJECT" "$ROOT/tools/ngx_param_abi_probe_msvc.cpp"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -static -static-libgcc -static-libstdc++ \
-I"$NVSDK_NGX_INCLUDE" \
"$ROOT/tools/ngx_cuda_probe.cpp" "$ABI_OBJECT" \
-o "$ROOT/build/ngx_cuda_probe.exe"
printf 'Built %s\n' "$ROOT/build/ngx_cuda_probe.exe"
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
if [[ -z "${NVSDK_NGX_INCLUDE:-}" || ! -f "$NVSDK_NGX_INCLUDE/nvsdk_ngx.h" ]]; then
printf '%s\n' "Set NVSDK_NGX_INCLUDE to a directory containing NVIDIA's nvsdk_ngx.h and nvsdk_ngx_defs.h" >&2
exit 2
fi
mkdir -p "$ROOT/build"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -static -static-libgcc -static-libstdc++ \
-I"$NVSDK_NGX_INCLUDE" \
"$ROOT/tools/ngx_d3d12_probe.cpp" \
-o "$ROOT/build/ngx_d3d12_probe.exe"
printf 'Built %s\n' "$ROOT/build/ngx_d3d12_probe.exe"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
mkdir -p "$ROOT/build"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -Werror \
"$ROOT/tools/ngx_load_probe.cpp" \
-o "$ROOT/build/ngx_load_probe.exe"
printf 'Built %s\n' "$ROOT/build/ngx_load_probe.exe"
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MINGW_CXX="${MINGW_CXX:-x86_64-w64-mingw32-g++}"
if [[ -z "${NVSDK_NGX_INCLUDE:-}" || ! -f "$NVSDK_NGX_INCLUDE/nvsdk_ngx_vk.h" ]]; then
printf '%s\n' "Set NVSDK_NGX_INCLUDE to a directory containing NVIDIA's nvsdk_ngx_vk.h and nvsdk_ngx_defs.h" >&2
exit 2
fi
VULKAN_INCLUDE="${VULKAN_INCLUDE:-$(dirname "$NVSDK_NGX_INCLUDE")/vulkan/include}"
if [[ ! -f "$VULKAN_INCLUDE/vulkan/vulkan.h" ]]; then
printf '%s\n' "Set VULKAN_INCLUDE to a Windows-target Vulkan-Headers include root" >&2
exit 2
fi
mkdir -p "$ROOT/build"
"$MINGW_CXX" -std=c++20 -O2 -Wall -Wextra -static -static-libgcc -static-libstdc++ \
-I"$NVSDK_NGX_INCLUDE" -I"$VULKAN_INCLUDE" \
"$ROOT/tools/ngx_vulkan_probe.cpp" \
-o "$ROOT/build/ngx_vulkan_probe.exe"
printf 'Built %s\n' "$ROOT/build/ngx_vulkan_probe.exe"
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Run inside packaging/build/Dockerfile.glibc241 with a recent official Rust toolchain and ROCm mounted.
# Supply isolated, patched ZLUDA/vkd3d checkouts and the usual package_release.sh inputs.
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
: "${D4R_RELEASE_BUILD_ROOT:?set the build output directory}"
: "${D4R_ZLUDA_SRC:?set a build-local ZLUDA checkout with patches 0002-0007 applied}"
: "${D4R_VKD3D_SRC:?set a build-local vkd3d-proton checkout with patches 0001 and 0002 applied}"
: "${D4R_ROCM_DIR:?set ROCm with clang and device libraries}"
BUILD="$(realpath -m "$D4R_RELEASE_BUILD_ROOT")"
[[ "$(getconf GNU_LIBC_VERSION)" == 'glibc 2.41' ]] || {
echo "This release build requires GLIBC 2.41; use the pinned Debian build image" >&2; exit 2;
}
# Helper generation modifies its source checkout. Refuse the external source-cache directory.
case "$(realpath "$D4R_ZLUDA_SRC")" in "$BUILD"/*) ;; *) echo "ZLUDA source must be inside $BUILD" >&2; exit 2 ;; esac
case "$(realpath "$D4R_VKD3D_SRC")" in "$BUILD"/*) ;; *) echo "vkd3d source must be inside $BUILD" >&2; exit 2 ;; esac
mkdir -p "$BUILD/logs"
for source in "$D4R_ZLUDA_SRC/ext/llvm-project/llvm/CMakeLists.txt" "$D4R_ZLUDA_SRC/ext/HiGHS/CMakeLists.txt"; do
[[ -f "$source" ]] || { echo "missing pinned source submodule: $source" >&2; exit 2; }
done
export CARGO_TARGET_DIR="$BUILD/zluda-target"
export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-8}"
export CMAKE_BUILD_PARALLEL_LEVEL="$CARGO_BUILD_JOBS"
export LIBRARY_PATH="$D4R_ROCM_DIR/lib${D4R_ROCM_LINK_STUBS:+:$D4R_ROCM_LINK_STUBS}"
export LD_LIBRARY_PATH="$D4R_ROCM_DIR/lib"
export HIP_PATH="$D4R_ROCM_DIR"
export ROCM_PATH="$D4R_ROCM_DIR"
export HIP_CLANG_PATH="$D4R_ROCM_DIR/lib/llvm/bin"
{
getconf GNU_LIBC_VERSION
rustc --version
cargo --version
gcc --version | head -1
winegcc --version | head -1
"$D4R_ROCM_DIR/lib/llvm/bin/clang++" --version | head -1
} > "$BUILD/toolchain.txt"
ZLUDA_SOURCE_ROOT="$D4R_ZLUDA_SRC" ROCM_ROOT="$D4R_ROCM_DIR" \
D4R_ZLUDA_PTX_HELPER_WORK="$BUILD/helpers" "$ROOT/scripts/build_zluda_ptx_helpers.sh" \
> "$BUILD/logs/helpers.log" 2>&1
echo 'Device helpers rebuilt'
(cd "$D4R_ZLUDA_SRC" && cargo build --offline --locked --release -p zluda \
&& cargo build --offline --locked --release -p ptx --example d4r_emit) \
> "$BUILD/logs/zluda.log" 2>&1
export D4R_ZLUDA_DIR="$CARGO_TARGET_DIR/release"
export D4R_ZLUDA_EMIT="$D4R_ZLUDA_DIR/examples/d4r_emit"
"$ROOT/scripts/check_glibc_compat.sh" 2.41 "$D4R_ZLUDA_DIR/libnvcuda.so"
echo 'ZLUDA and the offline emitter rebuilt; GLIBC check passed'
# A minimal ROCm compiler extraction may omit lld. Use the matching LLVM built above so
# all GPU targets link with the same AMDGPU/ELF support, inside the compatible environment.
for llvm_build in "$CARGO_TARGET_DIR"/release/build/llvm_zluda-*/out/build; do
[[ -f "$llvm_build/build.ninja" ]] || continue
ninja -j "$CARGO_BUILD_JOBS" -C "$llvm_build" lld > "$BUILD/logs/lld.log" 2>&1
export PATH="$llvm_build/bin:$PATH"
break
done
command -v lld >/dev/null || { echo 'missing AMDGPU linker' >&2; exit 2; }
"$ROOT/scripts/build_d4r_nvngx_shim.sh" > "$BUILD/logs/shim.log" 2>&1
"$ROOT/scripts/build_wine_nvcuda_bridge.sh" > "$BUILD/logs/bridge.log" 2>&1
"$ROOT/scripts/check_glibc_compat.sh" 2.41 "$ROOT/build/wine-nvcuda/x86_64-unix/nvcuda.dll.so"
if [[ ! -f "$BUILD/vkd3d-build/build.ninja" ]]; then
meson setup --cross-file "$D4R_VKD3D_SRC/build-win64.txt" --buildtype release \
-Denable_tests=false "$BUILD/vkd3d-build" "$D4R_VKD3D_SRC" > "$BUILD/logs/vkd3d.log" 2>&1
fi
ninja -j "$CARGO_BUILD_JOBS" -C "$BUILD/vkd3d-build" >> "$BUILD/logs/vkd3d.log" 2>&1
export D4R_VKD3D_DIR="$BUILD/vkd3d"
mkdir -p "$D4R_VKD3D_DIR"
x86_64-w64-mingw32-strip -o "$D4R_VKD3D_DIR/d3d12.dll" "$BUILD/vkd3d-build/libs/d3d12/d3d12.dll"
x86_64-w64-mingw32-strip -o "$D4R_VKD3D_DIR/d3d12core.dll" "$BUILD/vkd3d-build/libs/d3d12core/d3d12core.dll"
echo 'Shim, bridge and vkd3d-proton rebuilt'
export D4R_BUNDLE_TEX="$BUILD/kernels"
export D4R_DLSS_PTX_DIR="$BUILD/ptx"
python3 "$ROOT/kernels/tools/extract_dlss_ptx.py" "$D4R_BUNDLE_DLSS" "$D4R_DLSS_PTX_DIR" > "$BUILD/logs/extract.log"
build_textures() {
local arch="$1" folder fp8 accuracy out
folders=("$arch")
[[ "$arch" == gfx12* ]] && folders+=("$arch-fp8")
for folder in "${folders[@]}"; do
fp8=0
[[ "$folder" == *-fp8 ]] && fp8=1
for accuracy in 0 1; do
out="$D4R_BUNDLE_TEX/$folder"
[[ "$accuracy" == 1 ]] && out="$D4R_BUNDLE_TEX/accuracy/$folder"
D4R_PREFER_ACCURACY="$accuracy" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" \
D4R_DLSS_DLL="$D4R_BUNDLE_DLSS" "$ROOT/kernels/build.sh" tex "$out" \
> "$BUILD/logs/tex-$folder-$accuracy.log" 2>&1
echo "Texture kernels rebuilt: $folder accuracy=$accuracy"
done
done
}
pending=()
failed=0
for arch in ${D4R_GPU_ARCHS:-gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201}; do
build_textures "$arch" &
pending+=("$!")
if (( ${#pending[@]} >= 4 )); then
wait "${pending[0]}" || failed=1
pending=("${pending[@]:1}")
fi
done
for pid in "${pending[@]}"; do wait "$pid" || failed=1; done
[[ "$failed" == 0 ]] || { echo 'Texture target build failed' >&2; exit 1; }
python3 -m unittest discover -s "$ROOT/tests" -v > "$BUILD/logs/tests.log" 2>&1
export D4R_SKIP_BUILD=1
export D4R_MAX_GLIBC=2.41
export D4R_BUILD_INFO="$BUILD/toolchain.txt"
export D4R_PACKAGE_KERNEL_JOBS=4
"$ROOT/scripts/package_release.sh" "$BUILD/dist" > "$BUILD/logs/package.log" 2>&1
echo "Release packaged in $BUILD/dist"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_fp8_ops.cpp" -ldl \
-o "$ROOT/build/replay_dlss_fp8_ops"
printf 'Built %s\n' "$ROOT/build/replay_dlss_fp8_ops"
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
ROCM_ROOT="${ROCM_ROOT:-/opt/rocm}"
if [[ ! -f "$ROCM_ROOT/include/hip/hip_runtime_api.h" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ROCM_ROOT to a ROCm installation containing HIP headers and libamdhip64.so\n' >&2
exit 2
fi
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra -D__HIP_PLATFORM_AMD__=1 \
-I"$ROCM_ROOT/include" \
"$ROOT/tools/replay_dlss_histogram.cpp" -L"$ROCM_ROOT/lib" -lamdhip64 -ldl \
-Wl,-rpath,"$ROCM_ROOT/lib" \
-o "$ROOT/build/replay_dlss_histogram"
printf 'Built %s\n' "$ROOT/build/replay_dlss_histogram"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_kernel.cpp" -ldl \
-o "$ROOT/build/replay_dlss_kernel"
printf 'Built %s\n' "$ROOT/build/replay_dlss_kernel"
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_layer.cpp" -ldl \
-o "$ROOT/build/replay_dlss_layer"
printf 'Built %s\n' "$ROOT/build/replay_dlss_layer"
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_surface_half_store.cpp" -ldl \
-o "$ROOT/build/replay_dlss_surface_half_store"
printf 'Built %s\n' "$ROOT/build/replay_dlss_surface_half_store"
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_surface_store.cpp" -ldl \
-o "$ROOT/build/replay_dlss_surface_store"
printf 'Built %s\n' "$ROOT/build/replay_dlss_surface_store"
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CXX="${CXX:-g++}"
mkdir -p "$ROOT/build"
"$CXX" -std=c++20 -O2 -Wall -Wextra \
"$ROOT/tools/replay_dlss_texture_sample.cpp" -ldl \
-o "$ROOT/build/replay_dlss_texture_sample"
printf 'Built %s\n' "$ROOT/build/replay_dlss_texture_sample"
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
set -euo pipefail
# Builds vkd3d-proton with patches/vkd3d-proton/ applied (split command lists
# for the shim's same-frame DLSS, D4R_SHIM_SPLIT_FRAME) into OUT_DIR, which
# 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).
if [[ $# -ne 1 ]]; then
printf 'usage: %s OUT_DIR\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="$(realpath -m "$1")"
SRC="${VKD3D_PROTON_SRC:-$HOME/.cache/d4r-vkd3d-proton}"
COMMIT="${VKD3D_PROTON_COMMIT:-3dfc6f07}"
BUILD="$SRC-build"
[[ -d "$SRC/.git" ]] || git clone https://github.com/HansKristian-Work/vkd3d-proton.git "$SRC"
# -f: the clone is a build cache; the patch is reapplied below.
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"
ninja -C "$BUILD"
mkdir -p "$OUT"
x86_64-w64-mingw32-strip -o "$OUT/d3d12.dll" "$BUILD/libs/d3d12/d3d12.dll"
x86_64-w64-mingw32-strip -o "$OUT/d3d12core.dll" "$BUILD/libs/d3d12core/d3d12core.dll"
printf 'Built %s/d3d12.dll and d3d12core.dll\n' "$OUT"
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WINEGCC="${WINEGCC:-winegcc}"
WINEBUILD="${WINEBUILD:-winebuild}"
BRIDGE_ROOT="$ROOT/build/wine-nvcuda"
mkdir -p "$BRIDGE_ROOT/x86_64-unix" "$BRIDGE_ROOT/x86_64-windows"
MOTION_FLAGS=()
if [[ -x "${D4R_ROCM_DIR:-/opt/rocm}/lib/llvm/bin/clang++" ]]; then
"$ROOT/scripts/build_d4r_motion_kernels.sh" "$BRIDGE_ROOT/generated"
MOTION_FLAGS=(-DD4R_MOTION_KERNELS -I"$BRIDGE_ROOT/generated")
fi
"$WINEGCC" -m64 -shared -o "$BRIDGE_ROOT/x86_64-unix/nvcuda.dll" \
"${MOTION_FLAGS[@]}" \
"$ROOT/tools/wine_nvcuda_bridge.c" \
-Wb,--export="$ROOT/tools/wine_nvcuda_bridge.spec" -ldl -lpthread
"$WINEBUILD" --dll --fake-module -E "$ROOT/tools/wine_nvcuda_bridge.spec" \
-F nvcuda.dll -b x86_64-windows -o "$BRIDGE_ROOT/x86_64-windows/nvcuda.dll"
printf 'Built Wine nvcuda bridge in %s\n' "$BRIDGE_ROOT"
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_SOURCE_ROOT="${ZLUDA_SOURCE_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-/opt/rocm}"
HIPCC="${HIPCC:-$ROCM_ROOT/bin/hipcc}"
LLVM_DIS="${LLVM_DIS:-$ROCM_ROOT/lib/llvm/bin/llvm-dis}"
LLVM_AS="${LLVM_AS:-$ROCM_ROOT/lib/llvm/bin/llvm-as}"
OCML="${OCML:-$ROCM_ROOT/amdgcn/bitcode/ocml.bc}"
WORK_ROOT="${D4R_ZLUDA_PTX_HELPER_WORK:-${TMPDIR:-/tmp}/d4r-zluda-ptx-helpers}"
# D4R_ZLUDA_HELPER_FLAGS: extra compiler flags, e.g. -DD4R_WMMA12_SHIM for the gfx12-layout test build (never
# ship it: its gfx12 helpers use gfx11 WMMAs)
read -r -a EXTRA_FLAGS <<< "${D4R_ZLUDA_HELPER_FLAGS:-}"
if [[ -z "$ZLUDA_SOURCE_ROOT" || ! -f "$ZLUDA_SOURCE_ROOT/ptx/lib/zluda_ptx_impl.cpp" ]]; then
printf 'Set ZLUDA_SOURCE_ROOT to a ZLUDA source checkout\n' >&2
exit 2
fi
for dependency in "$HIPCC" "$LLVM_DIS" "$LLVM_AS" "$OCML"; do
if [[ ! -e "$dependency" ]]; then
printf 'Required ROCm/LLVM helper is missing: %s\n' "$dependency" >&2
exit 2
fi
done
mkdir -p "$WORK_ROOT"
SOURCE="$ZLUDA_SOURCE_ROOT/ptx/lib/zluda_ptx_impl.cpp"
PTX_LIB="$ZLUDA_SOURCE_ROOT/ptx/lib"
COMMON_FLAGS=(-DHIP_ENABLE_WARP_SYNC_BUILTINS -std=c++20 -Xclang -fdenormal-fp-math=dynamic
--rocm-path="$ROCM_ROOT" -I"$ROCM_ROOT/include"
-Wall -Wextra -Wsign-compare -Wconversion -x hip "$SOURCE" -nogpulib -O3
-mno-wavefrontsize64 --offload-device-only --offload-arch=gfx1030 -emit-llvm -c
-Xclang -mlink-bitcode-file -Xclang "$OCML" "${EXTRA_FLAGS[@]}")
build_one() {
local suffix="$1"
shift
local raw="$WORK_ROOT/zluda_ptx_impl${suffix}.raw.bc"
local clean="$WORK_ROOT/zluda_ptx_impl${suffix}.clean.bc"
local ll="$WORK_ROOT/zluda_ptx_impl${suffix}.ll"
local output="$PTX_LIB/zluda_ptx_impl${suffix}.bc"
"$HIPCC" "${COMMON_FLAGS[@]}" "$@" -o "$raw"
"$LLVM_DIS" "$raw" -o "$ll"
sed -E \
-e '/@llvm.used/d' \
-e '/wchar_size/d' \
-e '/llvm.module.flags/d' \
-e '/__hip_cuid/d' \
-e 's/optnone//g' \
-e 's/define hidden/define linkonce_odr/g' \
-e 's/"target-cpu"="gfx1030"//g' \
-e 's/"target-features"="[^"]+"//g' "$ll" |
"$LLVM_AS" -o "$clean" -
mv "$clean" "$output"
printf 'Wrote %s (%s bytes)\n' "$output" "$(stat -c '%s' "$output")"
}
build_one ""
build_one "_constrained" -ffp-model=strict -ffp-exception-behavior=ignore
# wave64 helpers (D4R_ZLUDA_WAVE64: two CUDA warps per wave; see d4r_warp_base in zluda_ptx_impl.cpp)
build_one "_w64" -mwavefrontsize64 -DD4R_WAVE64
build_one "_constrained_w64" -ffp-model=strict -ffp-exception-behavior=ignore -mwavefrontsize64 -DD4R_WAVE64
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail
section() {
printf '\n## %s\n' "$1"
}
show_if_available() {
local tool="$1"
shift
if command -v "$tool" >/dev/null 2>&1; then
"$tool" "$@" 2>&1 || true
else
printf '%s: not found\n' "$tool"
fi
}
section 'Operating system'
uname -a
section 'Display adapters and kernel drivers'
show_if_available lspci -nnk | rg -A4 -i 'vga|3d|display' || true
section 'ROCm / HIP'
show_if_available rocminfo | head -80 || true
show_if_available hipcc --version | head -20 || true
if command -v rocm-smi >/dev/null 2>&1; then
rocm-smi --showproductname --showdriverversion 2>&1 | head -50 || true
elif [[ -x /opt/rocm/bin/rocm-smi ]]; then
/opt/rocm/bin/rocm-smi --showproductname --showdriverversion 2>&1 | head -50 || true
fi
section 'Vulkan'
if command -v vulkaninfo >/dev/null 2>&1; then
vulkaninfo --summary 2>&1 | rg -i 'VULKANINFO|Instance Version|GPU[0-9]|apiVersion|driverVersion|vendorID|deviceID|deviceName|driverID|driverName|driverInfo' || true
else
printf 'vulkaninfo: not found\n'
fi
section 'Wine / Proton'
show_if_available wine --version
show_if_available protontricks --version
find "$HOME/.local/share/Steam/compatibilitytools.d" -maxdepth 3 -type f -name proton -print 2>/dev/null | head -20 || true
section 'Build and PE inspection tools'
for tool in x86_64-w64-mingw32-g++ cmake ninja llvm-objdump llvm-readobj objdump strings; do
if command -v "$tool" >/dev/null 2>&1; then
printf '%-28s %s\n' "$tool" "$(command -v "$tool")"
else
printf '%-28s %s\n' "$tool" 'not found'
fi
done
section 'Installed relevant Arch packages'
if command -v pacman >/dev/null 2>&1; then
pacman -Q 2>/dev/null | rg -i '(^| )(rocm|hip|vulkan|wine|mingw|clang|mesa)(-| )' || true
else
printf 'pacman: not found\n'
fi
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Reject Linux release libraries that need a newer GLIBC than the target runtime.
# Usage: check_glibc_compat.sh MAX_GLIBC LIBRARY [LIBRARY ...]
set -euo pipefail
if [[ $# -lt 2 || ! "$1" =~ ^[0-9]+\.[0-9]+$ ]]; then
printf 'usage: %s MAX_GLIBC LIBRARY [LIBRARY ...]\n' "$0" >&2
exit 2
fi
max="GLIBC_$1"
shift
command -v readelf >/dev/null || { echo 'readelf is required to check GLIBC compatibility' >&2; exit 2; }
failed=0
for library in "$@"; do
if [[ ! -f "$library" ]]; then
printf 'missing library: %s\n' "$library" >&2
failed=1
continue
fi
if ! versions="$(readelf -W --version-info "$library" 2>&1)"; then
printf 'cannot inspect %s: %s\n' "$library" "$versions" >&2
failed=1
continue
fi
required="$(printf '%s\n' "$versions" | grep -Eo 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu | tail -1 || true)"
if [[ -n "$required" && "$(printf '%s\n%s\n' "$max" "$required" | sort -Vu | tail -1)" != "$max" ]]; then
printf '%s requires %s (target: at most %s)\n' "$library" "$required" "$max" >&2
failed=1
fi
done
exit "$failed"
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env python3
"""Translate d4r.ini (see config/d4r.ini.default) into shell exports for the game launcher.
usage: d4r_config.py [--config PATH] [--print | --launch]
Prints "export VAR=value" lines for every setting the INI decides, skipping variables that are
already set in the environment (explicit environment always wins). --print lists the resulting
settings for humans instead. Without --config: $D4R_CONFIG, else ~/.config/d4r/d4r.ini, which is
created from config/d4r.ini.default on first use.
"""
import configparser
import os
import shlex
import shutil
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
DEFAULT_TEMPLATE = ROOT / "config" / "d4r.ini.default"
PRESETS = {"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "J": 10, "K": 11, "L": 12, "M": 13}
# friendly names for [DLSS] Model
MODEL_ALIASES = {"CNN": "E", "DLSS3": "E", "DLSS4": "K", "DLSS4.5": "M", "TRANSFORMER": "K"}
def fail(message):
print(f"d4r config: {message}", file=sys.stderr)
sys.exit(2)
def config_path(argv):
if "--config" in argv:
return Path(argv[argv.index("--config") + 1]).expanduser()
if os.environ.get("D4R_CONFIG"):
return Path(os.environ["D4R_CONFIG"]).expanduser()
path = Path.home() / ".config" / "d4r" / "d4r.ini"
if not path.exists() and DEFAULT_TEMPLATE.exists():
path.parent.mkdir(parents=True, exist_ok=True)
shutil.copyfile(DEFAULT_TEMPLATE, path)
print(f"d4r config: created {path} from the default template; edit it to change settings",
file=sys.stderr)
return path
def main(argv):
path = config_path(argv)
ini = configparser.ConfigParser(inline_comment_prefixes=(";", "#"), interpolation=None)
ini.optionxform = str # keep [Env] variable names as written
if path.exists():
ini.read(path)
def get(section, key):
value = ini.get(section, key, fallback="").strip()
return None if value == "" or value.lower() == "auto" else value
def flag(section, key):
value = get(section, key)
if value is None:
return None
if value.lower() in ("1", "true", "yes", "on"):
return True
if value.lower() in ("0", "false", "no", "off"):
return False
fail(f"[{section}] {key} must be true or false, not {value!r}")
def path_value(section, key):
value = get(section, key)
return os.path.expanduser(value) if value else None
if "--launch" in argv:
# PROTON_DIR, COMPAT_DATA_DIR and GAME_EXE for scripts/d4r_play.sh, one per line
values = [path_value("Launch", key) for key in ("ProtonDir", "CompatDataDir", "GameExe")]
missing = [key for key, value in zip(("ProtonDir", "CompatDataDir", "GameExe"), values) if not value]
if missing:
fail(f"set [Launch] {', '.join(missing)} in {path}")
print("\n".join(values))
return
env = {}
env["D4R_PREFER_ACCURACY"] = "1" if flag("Kernels", "PreferAccuracy") else "0"
model = get("DLSS", "Model")
if model is not None:
if model.isdigit():
env["D4R_DLSS_PRESET"] = model
elif model.upper() in PRESETS or model.upper() in MODEL_ALIASES:
env["D4R_DLSS_PRESET"] = str(PRESETS[MODEL_ALIASES.get(model.upper(), model.upper())])
else:
fail(f"[DLSS] Model {model!r}: use one of {', '.join(list(PRESETS) + list(MODEL_ALIASES))} or a preset number")
age = get("Latency", "FrameAge")
if age is not None:
if age not in ("0", "1", "2", "3"):
fail(f"[Latency] FrameAge must be 0-3, not {age!r}")
if age == "0":
# same-frame results: the game's command list is split around DLSS (patched vkd3d-proton)
env["D4R_SHIM_SPLIT_FRAME"] = "1"
else:
env["D4R_SHIM_SPLIT_FRAME"] = "0"
env["D4R_SHIM_MAX_IN_FLIGHT"] = age
for key, var in (("RuntimeDir", "D4R_RUNTIME_DIR"), ("ZludaDir", "D4R_ZLUDA_DIR"), ("RocmDir", "D4R_ROCM_DIR"),
("VkD3DDir", "D4R_VKD3D_DIR")):
value = path_value("Paths", key)
if value:
env[var] = value
# JIT caches (ZLUDA's compiled kernels among them): a directory, or per-zluda for the one the test
# runs warm for each ZLUDA build (~/.cache/d4r-perf-game-jit-<ZludaDir name>)
jit = get("Paths", "JitCacheDir")
if jit is not None:
if jit.lower() == "per-zluda":
zluda = env.get("D4R_ZLUDA_DIR") or os.environ.get("D4R_ZLUDA_DIR")
if not zluda:
fail("[Paths] JitCacheDir = per-zluda needs [Paths] ZludaDir")
jit = f"~/.cache/d4r-perf-game-jit-{Path(zluda).name}"
env["XDG_CACHE_HOME"] = os.path.expanduser(jit)
if age == "0" and "D4R_VKD3D_DIR" not in env and not os.environ.get("D4R_VKD3D_DIR"):
print("d4r config: FrameAge = 0 needs [Paths] VkD3DDir (the d4r-patched vkd3d-proton); without it the "
"shim falls back to older frames", file=sys.stderr)
mode = (get("Kernels", "NativeKernels") or "off").lower()
if mode not in ("fast", "exact", "off"):
fail(f"[Kernels] NativeKernels must be fast, exact or off, not {mode!r}")
if mode != "off":
directory = path_value("Paths", "NativeKernelDirFast" if mode == "fast" else "NativeKernelDirExact")
if not directory:
fail(f"[Kernels] NativeKernels = {mode} needs [Paths] NativeKernelDir{mode.capitalize()}")
if not Path(directory).is_dir():
fail(f"native kernel directory {directory} does not exist")
env["D4R_ZLUDA_NATIVE_DIR"] = directory
for key, var in (("Fp8Wmma", "D4R_ZLUDA_WMMA_FP8"), ("IgnoreDenormals", "D4R_ZLUDA_IGNORE_DENORMAL")):
value = flag("Kernels", key)
if value is not None:
env[var] = "1" if value else "0"
# RDNA4's native FP8 WMMA (on unless set off; ZLUDA and the bridge ignore it on other GPUs)
value = flag("Kernels", "NativeFp8")
env["D4R_ZLUDA_WMMA_FP8_NATIVE"] = "0" if value is False else "1"
value = flag("Kernels", "NativeSwinEncoders")
env["D4R_NATIVE_SWIN_ENCODERS"] = "0" if value is False else "1"
value = get("Kernels", "ImplicitMaxBlock")
if value:
env["D4R_ZLUDA_IMPLICIT_MAX_BLOCK"] = value
for key, var in (("VramInterop", "D4R_SHIM_VRAM_INTEROP"), ("InputSync", "D4R_SHIM_INPUT_SYNC"),
("LinearInputs", "D4R_SHIM_LINEAR_INPUTS"),
("DirectOutput", "D4R_SHIM_OUTPUT_DIRECT"), ("ElideNgxSync", "D4R_ELIDE_NGX_SYNC"),
("EvalSync", "D4R_SHIM_EVAL_SYNC")):
value = flag("Interop", key)
if value is not None:
env[var] = "1" if value else "0"
value = get("Interop", "MarkerPollUs")
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")
env["D4R_MOTION_DILATION"] = dilation or "0"
if value:
if not value.isdigit():
fail(f"[Interop] MarkerPollUs must be a number of microseconds, not {value!r}")
env["D4R_SHIM_MARKER_POLL_US"] = value
engine = path_value("Game", "EngineIni")
cvars = get("Game", "Cvars")
if engine and cvars:
env["D4R_UE_ENGINE_INI"] = engine
env["D4R_UE_CVARS"] = cvars
value = flag("OptiScaler", "FpsOverlay")
if value is False:
env["D4R_OPTISCALER_FPS_OVERLAY_TYPE"] = "0"
env["D4R_OPTISCALER_SHOW_FPS"] = "false"
elif get("OptiScaler", "FpsOverlayType"):
env["D4R_OPTISCALER_FPS_OVERLAY_TYPE"] = get("OptiScaler", "FpsOverlayType")
if get("OptiScaler", "LogLevel"):
env["D4R_OPTISCALER_LOG_LEVEL"] = get("OptiScaler", "LogLevel")
extra = []
ratios = [(mode_name, get("OptiScaler", f"QualityRatio{mode_name}"))
for mode_name in ("Quality", "Balanced", "Performance", "UltraPerformance")]
if any(ratio for _, ratio in ratios):
extra.append("QualityOverrides.QualityRatioOverrideEnabled=true")
extra += [f"QualityOverrides.QualityRatio{name}={ratio}" for name, ratio in ratios if ratio]
if get("OptiScaler", "Extra"):
extra.append(get("OptiScaler", "Extra"))
if extra:
env["D4R_EXTRA_OPTISCALER_CONFIG"] = ";".join(extra)
if flag("Overlay", "MangoHud"):
env["MANGOHUD"] = "1"
if get("Overlay", "MangoHudConfig"):
env["MANGOHUD_CONFIG"] = get("Overlay", "MangoHudConfig")
if flag("Debug", "Profile"):
env["D4R_PROFILE"] = "1"
if path_value("Debug", "LogDir"):
env["D4R_GAME_LOG_DIR"] = path_value("Debug", "LogDir")
if ini.has_section("Env"):
for key, value in ini.items("Env"):
env[key] = value.strip()
final = {key: value for key, value in env.items() if key not in os.environ}
if "--print" in argv:
print(f"d4r config: {path}{'' if path.exists() else ' (missing: built-in defaults)'}")
for key in sorted(env):
note = "" if key in final else f" (environment wins: {os.environ[key]})"
print(f" {key}={env[key]}{note}")
return
for key, value in sorted(final.items()):
print(f"export {key}={shlex.quote(value)}")
if __name__ == "__main__":
main(sys.argv[1:])
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
# One-command launch: runs the game configured in d4r.ini's [Launch] section with all d4r settings
# from the same file (see config/d4r.ini.default). Extra arguments go to the game.
# D4R_CONFIG=/path/to/other.ini scripts/d4r_play.sh
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
mapfile -t LAUNCH < <(python3 "$ROOT/scripts/d4r_config.py" --launch) || exit 2
[[ ${#LAUNCH[@]} -eq 3 ]] || exit 2
exec "$ROOT/scripts/run_game_d4r_optiscaler_proton.sh" "${LAUNCH[0]}" "${LAUNCH[1]}" "${LAUNCH[2]}" "$@"
+40
View File
@@ -0,0 +1,40 @@
# Source this to export the environment a Proton process needs to run
# official DLSS on AMD through d4r (ZLUDA + Wine CUDA bridge + NGX shim).
# Paths can be overridden before sourcing.
D4R_RUNTIME_DIR="${D4R_RUNTIME_DIR:-$HOME/.local/share/d4r-dlss}"
D4R_ZLUDA_DIR="${D4R_ZLUDA_DIR:-$HOME/.cache/d4r-zluda-current}"
# ROCm user-space runtime: a private copy under ~/.cache if present, otherwise the system /opt/rocm
if [[ -z "${D4R_ROCM_DIR:-}" ]]; then
D4R_ROCM_DIR="$HOME/.cache/d4r-rocm-deps/root/opt/rocm"
[[ -d "$D4R_ROCM_DIR" ]] || D4R_ROCM_DIR=/opt/rocm
fi
d4r_winpath() { printf 'Z:%s' "$(printf '%s' "$1" | tr '/' '\\')"; }
# dxvk-nvapi on a non-NVIDIA driver, reporting Ada so NGX uploads the FP8
# network weights that match the sm_89 PTX ZLUDA compiles.
export PROTON_ENABLE_NVAPI=1
export DXVK_NVAPI_ALLOW_OTHER_DRIVERS=1
export DXVK_NVAPI_GPU_ARCH=AD100
# ZLUDA and the ROCm user-cache runtime.
export LD_LIBRARY_PATH="$D4R_ZLUDA_DIR:$D4R_ROCM_DIR/lib:$D4R_ROCM_DIR/lib/llvm/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
export D4R_ZLUDA_LIBCUDA="$D4R_ZLUDA_DIR/libcuda.so"
# Kernels without PTX launch bounds (DLSS's convolutions) are compiled for at
# most 256-thread blocks, as CUDA itself allows 255 registers for them; the
# default 1024 bound caps gfx11 waves at 96 VGPRs and makes them spill.
export D4R_ZLUDA_IMPLICIT_MAX_BLOCK="${D4R_ZLUDA_IMPLICIT_MAX_BLOCK:-256}"
# f16 tensor-core MMAs (DLSS's convolutions) run on gfx11/gfx12 WMMA instead of a
# dot-product fallback (patches/zluda/0003 and 0007); 0 selects the fallback.
export D4R_ZLUDA_WMMA="${D4R_ZLUDA_WMMA:-1}"
# DLSS frames in flight. The presented upscaled image is this many game frames
# old at most: 3 = highest frame rate (Townfall ~86 fps, age 2-3), 2 = age 2
# (~75 fps), 1 = age 1, the lowest possible with the CPU staging path (~53 fps).
export D4R_SHIM_MAX_IN_FLIGHT="${D4R_SHIM_MAX_IN_FLIGHT:-3}"
# 1 keeps DLSS inputs and output in VRAM (vkd3d-proton Vulkan interop, no CPU
# staging): Townfall ~141 fps at age 2-3 with 3 in flight, ~113 fps at age 1
# with D4R_SHIM_MAX_IN_FLIGHT=1. Needs vkd3d-proton; falls back automatically.
export D4R_SHIM_VRAM_INTEROP="${D4R_SHIM_VRAM_INTEROP:-0}"
# Shim configuration (Windows paths inside the prefix).
export D4R_NVCUDA_BRIDGE="$(d4r_winpath "$D4R_RUNTIME_DIR/bin/nvcuda.dll")"
export D4R_NGX_CORE="${D4R_NGX_CORE:-$(d4r_winpath "$D4R_RUNTIME_DIR/ngx/_nvngx.dll")}"
export D4R_NGX_FEATURE_DIR="$(d4r_winpath "$D4R_RUNTIME_DIR/dlss")"
export D4R_SHIM_LOG="${D4R_SHIM_LOG:-$(d4r_winpath "$D4R_RUNTIME_DIR/d4r_nvngx.log")}"
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Fetches the ROCm user-space runtime the release bundles in d4r/rocm: HIP, HSA, comgr and
# rocprofiler-register from AMD's ROCm 7.2.4 packages for Ubuntu 22.04, plus the libelf and libnuma
# they need, which Steam's container runtime lacks. These builds need only glibc 2.34, so they run
# in SteamLinuxRuntime_4 on any distribution (a rolling distribution's ROCm may need a newer glibc).
#
# usage: scripts/fetch_rocm_runtime.sh [OUT_DIR] (default: ~/.cache/d4r-rocm-runtime)
# Result: OUT_DIR/lib/<soname> for each library and OUT_DIR/licenses/.
set -euo pipefail
OUT="$(realpath -m "${1:-$HOME/.cache/d4r-rocm-runtime}")"
AMD=https://repo.radeon.com/rocm/apt/7.2.4/pool/main
UBUNTU=http://archive.ubuntu.com/ubuntu/pool/main
# url sha256
PACKAGES=(
"$AMD/h/hip-runtime-amd/hip-runtime-amd_7.2.53211.70204-93~22.04_amd64.deb 2b0fc15d4456bc35370f33672b202b43f2af1aceac47a42c22d1370b2f46968f"
"$AMD/c/comgr/comgr_3.0.0.70204-93~22.04_amd64.deb 58460d117131369a248d334ba749609abea8591cd05752ac572c9a10f31ac006"
"$AMD/h/hsa-rocr/hsa-rocr_1.18.0.70204-93~22.04_amd64.deb 7fccbb91e38fadd126538f15e02c66e20db717a60eb03f2a045e47497bf67405"
"$AMD/r/rocprofiler-register/rocprofiler-register_0.6.0.70204-93~22.04_amd64.deb c2780e37a7217329b5d3d40e682ae6979481b1a59b86415a0cdf849b9c142bfd"
"$UBUNTU/e/elfutils/libelf1_0.186-1ubuntu0.1_amd64.deb 2cc781614b045b450a1e073ee3b0902f393ee58ede1d2ea4526ad805fcccf538"
"$UBUNTU/n/numactl/libnuma1_2.0.14-3ubuntu2_amd64.deb 0721c89001fbbd1ada23e89da5d60e762763c1a7b3dc814a2e9a518480a8043d"
)
# soname, the file it names inside the packages
LIBRARIES=(
"libamdhip64.so.7 opt/rocm-7.2.4/lib/libamdhip64.so.7"
"libamd_comgr.so.3 opt/rocm-7.2.4/lib/libamd_comgr.so.3"
"libhsa-runtime64.so.1 opt/rocm-7.2.4/lib/libhsa-runtime64.so.1"
"librocprofiler-register.so.0 opt/rocm-7.2.4/lib/librocprofiler-register.so.0"
"libelf.so.1 usr/lib/x86_64-linux-gnu/libelf.so.1"
"libnuma.so.1 usr/lib/x86_64-linux-gnu/libnuma.so.1"
)
LICENSES=(
"HIP-LICENSE.md opt/rocm-7.2.4/share/doc/hip/LICENSE.md"
"comgr-LICENSE.txt opt/rocm-7.2.4/share/doc/amd_comgr/LICENSE.txt"
"ROCr-LICENSE.md opt/rocm-7.2.4/share/doc/hsa-rocr/LICENSE.md"
"rocprofiler-register-LICENSE.md opt/rocm-7.2.4/share/doc/rocprofiler-register/LICENSE.md"
"libelf-copyright.txt usr/share/doc/libelf1/copyright"
"libnuma-copyright.txt usr/share/doc/libnuma1/copyright"
)
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
mkdir -p "$TMP/root"
for entry in "${PACKAGES[@]}"; do
read -r url sha <<< "$entry"
deb="$TMP/$(basename "$url")"
curl -fsSL -o "$deb" "$url"
echo "$sha $deb" | sha256sum -c --quiet
data="$(ar t "$deb" | grep '^data\.tar')"
ar p "$deb" "$data" | tar -x -C "$TMP/root" -f - --use-compress-program="$(case "$data" in *.zst) echo zstd -d ;; *.xz) echo xz -d ;; *) echo gzip -d ;; esac)"
done
rm -rf "$OUT"
mkdir -p "$OUT/lib" "$OUT/licenses"
for entry in "${LIBRARIES[@]}"; do
read -r soname path <<< "$entry"
cp -L "$TMP/root/$path" "$OUT/lib/$soname"
done
for entry in "${LICENSES[@]}"; do
read -r name path <<< "$entry"
cp "$TMP/root/$path" "$OUT/licenses/$name"
done
printf 'ROCm runtime in %s (%s)\n' "$OUT" "$(du -sh "$OUT" | cut -f1)"
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -euo pipefail
# Stages the pieces a Proton game needs under D4R_RUNTIME_DIR
# (default ~/.local/share/d4r-dlss):
# bin/nvcuda.dll Wine CUDA bridge (ELF builtin, preloaded by path by the shim)
# bin/d4r_nvngx.dll D3D12-to-CUDA NGX core shim (OptiScaler NvngxPath target)
# ngx/_nvngx.dll official NGX core
# dlss/nvngx_dlss.dll official DLSS SR feature DLL (also copied into bin/)
# usage: install_d4r_runtime.sh PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL
if [[ $# -ne 2 ]]; then
printf 'usage: %s PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
RUNTIME="${D4R_RUNTIME_DIR:-$HOME/.local/share/d4r-dlss}"
"$ROOT/scripts/build_d4r_nvngx_shim.sh"
"$ROOT/scripts/build_wine_nvcuda_bridge.sh"
mkdir -p "$RUNTIME/bin" "$RUNTIME/ngx" "$RUNTIME/dlss"
cp -f "$ROOT/build/wine-nvcuda/x86_64-unix/nvcuda.dll.so" "$RUNTIME/bin/nvcuda.dll"
cp -f "$ROOT/build/d4r_nvngx.dll" "$RUNTIME/bin/d4r_nvngx.dll"
copy_unless_same() { [[ "$(realpath "$1")" == "$(realpath -m "$2")" ]] || cp -f "$1" "$2"; }
copy_unless_same "$1" "$RUNTIME/ngx/_nvngx.dll"
copy_unless_same "$2" "$RUNTIME/dlss/nvngx_dlss.dll"
# The NGX core's CUDA init ignores the feature search paths it is given and
# scans the directory of the module that calls it, i.e. the shim's.
cp -f "$RUNTIME/dlss/nvngx_dlss.dll" "$RUNTIME/bin/nvngx_dlss.dll"
sha256sum "$RUNTIME"/ngx/_nvngx.dll "$RUNTIME"/dlss/nvngx_dlss.dll
printf 'Installed d4r runtime in %s\n' "$RUNTIME"
+252
View File
@@ -0,0 +1,252 @@
#!/usr/bin/env bash
# Builds the drag-in release: a zip whose contents are extracted into the folder that holds a game's
# main .exe, like an OptiScaler release. packaging/D4R_README.txt describes the result.
#
# usage: scripts/package_release.sh [OUT_DIR] (default: dist/)
#
# Inputs (environment):
# D4R_OPTISCALER OptiScaler release archive (.7z or .zip) or extracted folder (required; 0.9.4 tested)
# D4R_DLSS_DLLS colon-separated nvngx_dlss.dll files whose kernel code the native kernels accept
# (required; only hashes of their PTX go into the release)
# D4R_ZLUDA_DIR ZLUDA build with patches/zluda applied (libnvcuda.so) default ~/.cache/d4r-zluda-current
# D4R_VKD3D_DIR d4r-patched vkd3d-proton (d3d12.dll, d3d12core.dll) default ~/.cache/d4r-vkd3d-d4r
# D4R_ROCM_DIR ROCm with clang, for the kernels default /opt/rocm
# D4R_ROCM_RUNTIME ROCm runtime bundled as d4r/rocm (scripts/fetch_rocm_runtime.sh)
# default ~/.cache/d4r-rocm-runtime
# D4R_MAX_GLIBC highest GLIBC ABI the Linux libraries may require default 2.41
# D4R_GPU_ARCHS GPU targets to build kernels for default gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201
# (RDNA4 targets also get a <target>-fp8 folder: the kernels for d4r.ini NativeFp8 = on)
# D4R_OPTISCALER_LICENSE OptiScaler's LICENSE (GPL-3.0) text; default: the system's SPDX copy
# D4R_VKD3D_SRC vkd3d-proton source checkout, for its license files default ~/.cache/d4r-vkd3d-proton
# D4R_ZLUDA_SRC ZLUDA source checkout, for its license files default: D4R_ZLUDA_DIR's ../d4r-zluda-upstream
# SOURCE_DATE_EPOCH timestamp given to every packaged file default: the last commit's
# D4R_BUILD_INFO optional build-toolchain/provenance text to include in d4r/source/
# D4R_PACKAGE_KERNEL_JOBS independent target builds at once (default 1)
# The zip also contains NVIDIA's files and the texture kernels built from NVIDIA's PTX; redistributing
# those is up to whoever publishes it (they are not covered by d4r's license):
# D4R_BUNDLE_DLSS nvngx_dlss.dll to include D4R_BUNDLE_NGX _nvngx.dll to include
# D4R_BUNDLE_TEX directory with texture-kernel code objects (kernels/build.sh tex), one subdirectory
# per target folder (gfx1101, gfx1201, gfx1201-fp8, ...), or a flat gfx1101 directory for
# older builds
# Accuracy texture sets go in accuracy/<target>/, built with D4R_PREFER_ACCURACY=1.
# D4R_ZLUDA_EMIT d4r_emit from the patched ZLUDA build; required in full builds when an accuracy
# texture set or L's unfolded texture variants are not supplied in D4R_BUNDLE_TEX.
# D4R_BUNDLE_NVIDIA=0 leaves them out (d4r-VERSION-nonvidia.zip; users then add the two DLLs themselves).
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OUT="$(realpath -m "${1:-$ROOT/dist}")"
VERSION="$(cat "$ROOT/packaging/VERSION")"
VARIANT=full
[[ "${D4R_BUNDLE_NVIDIA:-1}" == 0 ]] && VARIANT=clean
NAME="d4r-$VERSION"
[[ "$VARIANT" == clean ]] && NAME="$NAME-nonvidia"
STAGE="$OUT/$NAME"
ZLUDA="${D4R_ZLUDA_DIR:-$HOME/.cache/d4r-zluda-current}"
VKD3D="${D4R_VKD3D_DIR:-$HOME/.cache/d4r-vkd3d-d4r}"
ROCM="${D4R_ROCM_DIR:-/opt/rocm}"
ROCM_RUNTIME="${D4R_ROCM_RUNTIME:-$HOME/.cache/d4r-rocm-runtime}"
ARCHS="${D4R_GPU_ARCHS:-gfx1100 gfx1101 gfx1102 gfx1103 gfx1200 gfx1201}"
: "${D4R_OPTISCALER:?set D4R_OPTISCALER to the OptiScaler release archive or folder}"
: "${D4R_DLSS_DLLS:?set D4R_DLSS_DLLS to the nvngx_dlss.dll files the kernel manifest accepts}"
for f in "$ZLUDA/libnvcuda.so" "$VKD3D/d3d12.dll" "$VKD3D/d3d12core.dll" "$ROCM_RUNTIME/lib/libamdhip64.so.7"; do
[[ -f "$f" ]] || { echo "missing $f (the ROCm runtime comes from scripts/fetch_rocm_runtime.sh)" >&2; exit 2; }
done
# D4R_SKIP_BUILD=1 packages the shim and bridge already in build/ (e.g. the binaries that were tested)
if [[ "${D4R_SKIP_BUILD:-0}" != 1 ]]; then
"$ROOT/scripts/build_d4r_nvngx_shim.sh" >/dev/null
"$ROOT/scripts/build_wine_nvcuda_bridge.sh" >/dev/null
fi
rm -rf "$STAGE"
mkdir -p "$STAGE/d4r/zluda" "$STAGE/d4r/rocm" "$STAGE/d4r/ngx" "$STAGE/d4r/kernels" "$STAGE/d4r/licenses" "$STAGE/d4r/source"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
# OptiScaler, as dxgi.dll with its INI preconfigured for d4r
if [[ -d "$D4R_OPTISCALER" ]]; then
OPTI="$D4R_OPTISCALER"
else
OPTI="$TMP/optiscaler"
mkdir -p "$OPTI"
case "$D4R_OPTISCALER" in
*.7z) 7z x -y -o"$OPTI" "$D4R_OPTISCALER" >/dev/null ;;
*.zip) unzip -q -o "$D4R_OPTISCALER" -d "$OPTI" ;;
*) echo "D4R_OPTISCALER must be a .7z, a .zip or a folder" >&2; exit 2 ;;
esac
fi
cp "$OPTI/OptiScaler.dll" "$STAGE/dxgi.dll"
python3 - "$OPTI/OptiScaler.ini" "$ROOT/packaging/optiscaler.settings" "$STAGE/OptiScaler.ini" <<'PY'
import re, sys
lines = open(sys.argv[1], encoding="utf-8", newline="").read().split("\n") # keeps the file's line endings
for setting in open(sys.argv[2], encoding="utf-8"):
setting = setting.strip()
if not setting or setting.startswith("#"):
continue
path, value = setting.split("=", 1)
section, key = path.split(".", 1)
start = next((i for i, l in enumerate(lines) if l.strip() == f"[{section}]"), None)
if start is None:
sys.exit(f"OptiScaler.ini has no [{section}]")
end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("[")), len(lines))
for i in range(start + 1, end):
if re.match(rf"{re.escape(key)}\s*=", lines[i]):
lines[i] = f"{key}={value}" + ("\r" if lines[i].endswith("\r") else "")
break
else:
sys.exit(f"OptiScaler.ini has no {key} in [{section}]")
open(sys.argv[3], "w", encoding="utf-8", newline="").write("\n".join(lines))
PY
# d4r-patched vkd3d-proton: same-frame DLSS results
cp "$VKD3D/d3d12.dll" "$VKD3D/d3d12core.dll" "$STAGE/"
# d4r itself
cp "$ROOT/build/d4r_nvngx.dll" "$STAGE/d4r/nvngx.dll"
cp "$ROOT/build/wine-nvcuda/x86_64-unix/nvcuda.dll.so" "$STAGE/d4r/nvcuda.dll"
cp "$ZLUDA/libnvcuda.so" "$STAGE/d4r/zluda/libcuda.so"
cp -r "$ROCM_RUNTIME/lib" "$STAGE/d4r/rocm/lib"
"$ROOT/scripts/check_glibc_compat.sh" "${D4R_MAX_GLIBC:-2.41}" \
"$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"
if [[ "$VARIANT" == full ]]; then
: "${D4R_BUNDLE_DLSS:?set D4R_BUNDLE_DLSS}" "${D4R_BUNDLE_NGX:?set D4R_BUNDLE_NGX}" "${D4R_BUNDLE_TEX:?set D4R_BUNDLE_TEX}"
cp "$D4R_BUNDLE_DLSS" "$STAGE/d4r/nvngx_dlss.dll"
cp "$D4R_BUNDLE_NGX" "$STAGE/d4r/ngx/_nvngx.dll"
else
printf 'Put NVIDIA'"'"'s NGX runtime, _nvngx.dll, in this folder (see D4R_README.txt).\r\n' > "$STAGE/d4r/ngx/README.txt"
fi
IFS=: read -r -a DLLS <<< "$D4R_DLSS_DLLS"
# one folder per target; RDNA4 targets also get <target>-fp8 (native FP8 WMMA, d4r.ini NativeFp8), which the
# bridge serves instead when that setting is on
folders=()
for arch in $ARCHS; do
folders+=("$arch")
[[ "$arch" == gfx12* ]] && folders+=("$arch-fp8")
done
# Older texture bundles predate L. Complete them from the user's DLSS DLL rather
# than silently shipping only M's folded variants under the new L support claim.
ensure_l_textures() {
local dir="$1" accuracy="$2" missing=0 mv range v name
local names=(rrlite_dec0_4x4)
for mv in mvhi mvlo; do
for range in hdr ldr; do
names+=("rrlite_enc0_4x4_${mv}_${range}")
for v in 3_1 3_2; do names+=("rrlite_post_${v}_${mv}_${range}"); done
done
done
for name in "${names[@]}"; do [[ -f "$dir/$name.hsaco" ]] || missing=1; done
if [[ "$missing" == 1 ]]; then
: "${D4R_ZLUDA_EMIT:?set D4R_ZLUDA_EMIT or supply the unfolded L texture variants in D4R_BUNDLE_TEX}"
D4R_PREFER_ACCURACY="$accuracy" D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" \
D4R_DLSS_DLL="$D4R_BUNDLE_DLSS" "$ROOT/kernels/build.sh" l "$dir" >/dev/null
fi
}
build_target() {
local folder="$1" arch fp8 tex_dir accurate accurate_tex f
arch="${folder%-fp8}"
fp8=0
[[ "$folder" == *-fp8 ]] && fp8=1
D4R_PREFER_ACCURACY=0 D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" k "$STAGE/d4r/kernels/$folder" >/dev/null
D4R_PREFER_ACCURACY=0 D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" m "$STAGE/d4r/kernels/$folder" >/dev/null
rm -f "$STAGE/d4r/kernels/$folder"/*.resolution.txt # empty LTO notes from clang's -save-temps
if [[ "$VARIANT" == full ]]; then
tex_dir=""
if [[ -d "$D4R_BUNDLE_TEX/$folder" ]]; then
tex_dir="$D4R_BUNDLE_TEX/$folder"
elif [[ "$folder" == gfx1101 ]]; then
tex_dir="$D4R_BUNDLE_TEX" # older, flat gfx1101 texture-kernel builds
fi
if [[ -n "$tex_dir" ]]; then
for f in "$tex_dir"/*.hsaco; do # texture kernels only; the layers above are built from source
[[ -f "$f" ]] || continue
[[ -e "$STAGE/d4r/kernels/$folder/$(basename "$f")" ]] || cp "$f" "$STAGE/d4r/kernels/$folder/"
done
fi
fi
[[ "$VARIANT" != full ]] || ensure_l_textures "$STAGE/d4r/kernels/$folder" 0
python3 "$ROOT/kernels/tools/kernel_manifest.py" "$STAGE/d4r/kernels/$folder" "${DLLS[@]}"
# Every release target also gets conservative network and texture variants. Do not copy fast
# texture objects into this set: their compiler policy is fixed inside the binary.
accurate="$STAGE/d4r/kernels/accuracy/$folder"
D4R_PREFER_ACCURACY=1 D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" k "$accurate" >/dev/null
D4R_PREFER_ACCURACY=1 D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" "$ROOT/kernels/build.sh" m "$accurate" >/dev/null
if [[ "$VARIANT" == full ]]; then
accurate_tex="$D4R_BUNDLE_TEX/accuracy/$folder"
if [[ -f "$accurate_tex/d4r-accuracy.txt" && "$(cat "$accurate_tex/d4r-accuracy.txt")" == 1 ]]; then
for f in "$accurate_tex"/*.hsaco; do
[[ -f "$f" ]] || continue
[[ -e "$accurate/$(basename "$f")" ]] || cp "$f" "$accurate/"
done
else
: "${D4R_ZLUDA_EMIT:?set D4R_ZLUDA_EMIT or supply D4R_BUNDLE_TEX/accuracy/$folder}"
D4R_PREFER_ACCURACY=1 D4R_ROCM_DIR="$ROCM" D4R_GPU_ARCH="$arch" D4R_NATIVE_FP8="$fp8" \
D4R_DLSS_DLL="$D4R_BUNDLE_DLSS" "$ROOT/kernels/build.sh" tex "$accurate" >/dev/null
fi
fi
if [[ "$VARIANT" == full ]]; then
ensure_l_textures "$accurate" 1
for f in "$STAGE/d4r/kernels/$folder"/*.hsaco; do
[[ -f "$accurate/$(basename "$f")" ]] || {
echo "missing accuracy variant of $(basename "$f") for $folder" >&2; exit 2;
}
done
fi
rm -f "$accurate"/*.resolution.txt
python3 "$ROOT/kernels/tools/kernel_manifest.py" "$accurate" "${DLLS[@]}"
}
kernel_jobs="${D4R_PACKAGE_KERNEL_JOBS:-1}"
[[ "$kernel_jobs" =~ ^[1-9][0-9]*$ ]] || { echo "D4R_PACKAGE_KERNEL_JOBS must be positive" >&2; exit 2; }
pending=()
kernel_failed=0
for folder in "${folders[@]}"; do
build_target "$folder" &
pending+=("$!")
if (( ${#pending[@]} >= kernel_jobs )); then
wait "${pending[0]}" || kernel_failed=1
pending=("${pending[@]:1}")
fi
done
for pid in "${pending[@]}"; do wait "$pid" || kernel_failed=1; done
[[ "$kernel_failed" == 0 ]] || { echo "native target build failed; no release ZIP created" >&2; exit 1; }
# licenses and sources
ZLUDA_SRC="${D4R_ZLUDA_SRC:-$(dirname "$ZLUDA")/d4r-zluda-upstream}"
VKD3D_SRC="${D4R_VKD3D_SRC:-$HOME/.cache/d4r-vkd3d-proton}"
L="$STAGE/d4r/licenses"
cp "$ROOT/LICENSE" "$L/d4r-LICENSE.txt"
cp "$ROOT/NOTICE" "$L/d4r-NOTICE.txt"
cp "$ZLUDA_SRC/LICENSE-APACHE" "$L/ZLUDA-LICENSE-APACHE.txt"
cp "$ZLUDA_SRC/LICENSE-MIT" "$L/ZLUDA-LICENSE-MIT.txt"
cp "$ZLUDA_SRC/ext/llvm-project/llvm/LICENSE.TXT" "$L/LLVM-LICENSE.txt"
cp "$VKD3D_SRC/LICENSE" "$L/vkd3d-proton-LICENSE.txt"
cp "$VKD3D_SRC/COPYING" "$L/vkd3d-proton-COPYING.txt"
cp "${D4R_OPTISCALER_LICENSE:-/usr/share/licenses/spdx/GPL-3.0-only.txt}" "$L/OptiScaler-LICENSE-GPL-3.0.txt"
for f in "$ROCM_RUNTIME"/licenses/*; do cp "$f" "$L/ROCm-$(basename "$f")"; done
mkdir -p "$STAGE/d4r/source/patches"
cp -r "$ROOT/patches/zluda" "$ROOT/patches/vkd3d-proton" "$STAGE/d4r/source/patches/"
ZLUDA_COMMIT="$(git -C "$ZLUDA_SRC" rev-parse HEAD 2>/dev/null || echo unknown)"
VKD3D_COMMIT="$(git -C "$VKD3D_SRC" rev-parse HEAD 2>/dev/null || echo unknown)"
# "@clean " / "@full " lines belong to one variant only
variant() { sed -n -e "s/^@$VARIANT //" -e '/^@[a-z]* /d' -e p; }
file_version() { [[ -f "$1" ]] && strings -el "$1" | grep -A1 '^FileVersion$' | sed -n 2p | tr ',' '.' | tr -d ' '; }
sed -e "s/@VERSION@/$VERSION/g" -e "s/@ZLUDA_COMMIT@/$ZLUDA_COMMIT/g" -e "s/@VKD3D_COMMIT@/$VKD3D_COMMIT/g" \
-e "s/@DLSS_VERSION@/$(file_version "$STAGE/d4r/nvngx_dlss.dll")/g" -e "s/@NGX_VERSION@/$(file_version "$STAGE/d4r/ngx/_nvngx.dll")/g" \
"$ROOT/packaging/SOURCES.txt" | variant > "$STAGE/d4r/source/SOURCES.txt"
if [[ -n "${D4R_BUILD_INFO:-}" ]]; then
cp "$D4R_BUILD_INFO" "$STAGE/d4r/source/BUILD_INFO.txt"
fi
sed -e "s/@VERSION@/$VERSION/g" "$ROOT/packaging/D4R_README.txt" | variant | sed 's/$/\r/' > "$STAGE/D4R_README.txt"
# One timestamp for every file (SOURCE_DATE_EPOCH, default the last commit): ZLUDA's kernel cache is keyed on
# its library's size and mtime, so every extraction of the zip shares one cache.
EPOCH="${SOURCE_DATE_EPOCH:-$(git -C "$ROOT" log -1 --format=%ct)}"
find "$STAGE" -exec touch -h -d "@$EPOCH" {} +
# The zip holds the folder's contents, so it can be extracted straight into the game folder.
rm -f "$OUT/$NAME.zip"
(cd "$STAGE" && find . -type f | LC_ALL=C sort | sed 's|^\./||' | zip -q -X -9 "$OUT/$NAME.zip" -@)
(cd "$OUT" && sha256sum "$NAME.zip" > "$NAME.zip.sha256")
printf 'Built %s (%s)\n' "$OUT/$NAME.zip" "$(du -h "$OUT/$NAME.zip" | cut -f1)"
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
# usage: run_bench_dlss_kernel.sh FATBIN REPLAY_DIR [ITERATIONS [OUTPUT_PREFIX]]
# Replays a launch captured with D4R_CUDA_REPLAY_DUMP_DIR (wine_nvcuda_bridge.c).
if [[ $# -lt 2 ]]; then
printf 'usage: %s FATBIN REPLAY_DIR [ITERATIONS [OUTPUT_PREFIX]]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
[[ -x "$ROOT/build/bench_dlss_kernel" && "$ROOT/build/bench_dlss_kernel" -nt "$ROOT/tools/bench_dlss_kernel.cpp" ]] ||
"$ROOT/scripts/build_bench_dlss_kernel.sh" >/dev/null
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/bench_dlss_kernel" "$@"
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -euo pipefail
# Runs the D3D12 harness against d4r_nvngx.dll in an isolated Wine prefix.
# usage: run_d3d12_dlss_harness.sh PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL OUTPUT_RAW [FRAMES [IN_W IN_H OUT_W OUT_H]]
if [[ $# -lt 3 ]]; then
printf 'usage: %s PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL OUTPUT_RAW [FRAMES]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CORE_PATH="$(realpath "$1")"
FEATURE_DLL_PATH="$(realpath "$2")"
OUTPUT_PATH="$(realpath -m "$3")"
FRAMES="${4:-6}"
SIZES=("${@:5}")
WINE_BIN="${WINE:-wine}"
WINEPREFIX="${D4R_WINEPREFIX:-${TMPDIR:-/tmp}/d4r-wineprefix}"
APP_DIR="${D4R_HARNESS_APPDIR:-${TMPDIR:-/tmp}/d4r-d3d12-harness-app}"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
mkdir -p "$APP_DIR" "$WINEPREFIX/drive_c/windows/system32"
"$ROOT/scripts/build_d3d12_dlss_harness.sh"
"$ROOT/scripts/build_wine_nvcuda_bridge.sh"
cp -f "$ROOT/build/wine-nvcuda/x86_64-windows/nvcuda.dll" "$WINEPREFIX/drive_c/windows/system32/nvcuda.dll"
cp -f "$ROOT/build/d3d12_dlss_harness.exe" "$ROOT/build/d4r_nvngx.dll" "$APP_DIR/"
cp -f "$FEATURE_DLL_PATH" "$APP_DIR/nvngx_dlss.dll"
winpath() { WINEPREFIX="$WINEPREFIX" winepath -w "$1"; }
WINE_OVERRIDES="${WINEDLLOVERRIDES:-}"
for override in 'dxgi=n,b' 'd3d12=n,b' 'd3d12core=n,b' 'nvcuda=b'; do
dll_name="${override%%=*}"
if [[ ";$WINE_OVERRIDES;" != *";$dll_name="* ]]; then
WINE_OVERRIDES="${WINE_OVERRIDES:+$WINE_OVERRIDES;}$override"
fi
done
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
WINEDLLPATH="$ROOT/build/wine-nvcuda/x86_64-windows:$ROOT/build/wine-nvcuda/x86_64-unix${WINEDLLPATH:+:$WINEDLLPATH}" \
WINEDLLOVERRIDES="$WINE_OVERRIDES" WINEPREFIX="$WINEPREFIX" WINEDEBUG="${D4R_WINEDEBUG:--all}" \
D4R_NGX_CORE="$(winpath "$CORE_PATH")" D4R_NGX_FEATURE_DIR="$(winpath "$APP_DIR")" \
D4R_SHIM_LOG="$(winpath "$APP_DIR/d4r_nvngx.log")" \
"$WINE_BIN" "$(winpath "$APP_DIR/d3d12_dlss_harness.exe")" "$(winpath "$APP_DIR/d4r_nvngx.dll")" \
"$(winpath "$OUTPUT_PATH")" "$FRAMES" "${SIZES[@]}"
printf '\nShim log (%s):\n' "$APP_DIR/d4r_nvngx.log"
cat "$APP_DIR/d4r_nvngx.log"
@@ -0,0 +1,149 @@
#!/usr/bin/env bash
set -euo pipefail
umask 077
# Runs the synthetic D3D12 harness through a locally supplied OptiScaler
# dxgi.dll and the d4r shim. All proxy files and the NVAPI identity bridge are
# staged in disposable /tmp paths; the Proton installation is not modified.
# usage: run_d3d12_dlss_harness_optiscaler_proton.sh PROTON_DIR OPTISCALER_DLL OUTPUT_RAW [FRAMES [IN_W IN_H OUT_W OUT_H]]
if [[ $# -lt 3 ]]; then
printf 'usage: %s PROTON_DIR OPTISCALER_DLL OUTPUT_RAW [FRAMES [IN_W IN_H OUT_W OUT_H]]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
OPTISCALER_DLL="$(realpath "$2")"
OUTPUT_PATH="$(realpath -m "$3")"
shift 3
source "$ROOT/scripts/d4r_proton_env.sh"
for path in "$D4R_RUNTIME_DIR/bin/d4r_nvngx.dll" "$D4R_RUNTIME_DIR/bin/nvcuda.dll" \
"$D4R_RUNTIME_DIR/bin/nvngx_dlss.dll" "$D4R_RUNTIME_DIR/ngx/_nvngx.dll"; do
if [[ ! -f "$path" ]]; then
printf 'Missing staged d4r runtime file: %s\n' "$path" >&2
exit 2
fi
done
# DLSS Enabler has been found installed under the name OptiScaler.dll on this
# machine. Reject it here: its proxy rejects dxgi/NGX harness naming and can
# open a modal error dialog during LoadLibrary.
EXPORT_HEADER="$(x86_64-w64-mingw32-objdump -p "$OPTISCALER_DLL" | sed -n '/The Export Tables/,+6p')"
if [[ "$EXPORT_HEADER" != *OptiScaler.dll* ]]; then
printf 'Expected a real OptiScaler DLL (PE export name OptiScaler.dll): %s\n' "$OPTISCALER_DLL" >&2
exit 2
fi
"$ROOT/scripts/build_d4r_nvapi_identity.sh" >/dev/null
APP_DIR="${D4R_OPTISCALER_APP_DIR:-${TMPDIR:-/tmp}/d4r-optiscaler-harness-${UID}-$(date +%s%N)}"
mkdir -p "$APP_DIR"
LAUNCHER_DIR="$(mktemp -d "${TMPDIR:-/tmp}/d4r-optiscaler-proton.XXXXXXXX")"
COMPAT_DIR="${D4R_OPTISCALER_COMPAT_DIR:-${TMPDIR:-/tmp}/d4r-optiscaler-compat-$UID}"
mkdir -p "$COMPAT_DIR"
cp -f "$OPTISCALER_DLL" "$APP_DIR/dxgi.dll"
INPUT_HOOK="${D4R_OPTISCALER_ENABLE_DLSS_INPUTS:-false}"
ORIGINAL_HOOK="${D4R_OPTISCALER_HOOK_ORIGINAL_NVNGX_ONLY:-$INPUT_HOOK}"
if [[ "$INPUT_HOOK" != true && "$INPUT_HOOK" != false ]] ||
[[ "$ORIGINAL_HOOK" != true && "$ORIGINAL_HOOK" != false ]]; then
printf 'OptiScaler hook settings must be true or false\n' >&2
exit 2
fi
# D4R_OPTISCALER_STAGE_CORE=0 keeps the official core in the runtime directory,
# as in a game install; the shim then loads it below OptiScaler's hooks.
STAGE_CORE="${D4R_OPTISCALER_STAGE_CORE:-1}"
if [[ "$INPUT_HOOK" == true && "$STAGE_CORE" == 1 ]]; then
if [[ "$ORIGINAL_HOOK" != true || "$APP_DIR" != "${APP_DIR,,}" ]]; then
printf 'The DLSS input hook requires HookOriginalNvngxOnly=true and a lowercase app path\n' >&2
exit 2
fi
# OptiScaler hooks game-side nvngx loads. Keep the official core's required
# filename inside the harness EXE directory and pass a lowercase z: path;
# its hook then leaves this internal core load alone.
cp -f "$D4R_RUNTIME_DIR/ngx/_nvngx.dll" "$APP_DIR/_nvngx.dll"
cp -f "$D4R_RUNTIME_DIR/dlss/nvngx_dlss.dll" "$APP_DIR/nvngx_dlss.dll"
core_windows_path="$(d4r_winpath "$APP_DIR/_nvngx.dll")"
export D4R_NGX_CORE="z:${core_windows_path#Z:}"
fi
cat > "$APP_DIR/OptiScaler.ini" <<EOF
[Upscalers]
Dx12Upscaler=dlss
[FrameGen]
Enabled=false
FGInput=nofg
FGOutput=nofg
[DLSS]
Enabled=true
[Inputs]
EnableDlssInputs=$INPUT_HOOK
[Hooks]
HookOriginalNvngxOnly=$ORIGINAL_HOOK
[FSR]
FsrAgilitySDKUpgrade=false
[Libraries]
NvngxPath=$(d4r_winpath "$D4R_RUNTIME_DIR/bin/d4r_nvngx.dll")
NvngxDlssPath=$(d4r_winpath "$D4R_RUNTIME_DIR/bin")
[NvApi]
OverrideNvapiDll=false
[Spoofing]
Dxgi=false
[Plugins]
LoadAsiPlugins=false
[Log]
LogToFile=true
LogLevel=1
EOF
# Proton refreshes nvapi64.dll in the prefix on every run. Make a temporary
# launcher that copies our identity bridge instead. Its other files are links
# to the unmodified Proton installation.
cp -f "$PROTON_DIR/proton" "$PROTON_DIR/filelock.py" "$PROTON_DIR/version" "$LAUNCHER_DIR/"
ln -s "$PROTON_DIR/files" "$LAUNCHER_DIR/files"
ln -s "$PROTON_DIR/protonfixes" "$LAUNCHER_DIR/protonfixes"
LAUNCHER="$LAUNCHER_DIR/proton" python3 - <<'PY'
import os
from pathlib import Path
path = Path(os.environ["LAUNCHER"])
source = path.read_text()
old = 'try_copy(g_proton.arch_pe_dir("wine/nvapi", False) + "nvapi64.dll", "drive_c/windows/system32",'
new = 'try_copy(os.environ.get("D4R_NVAPI_IDENTITY_DLL", g_proton.arch_pe_dir("wine/nvapi", False) + "nvapi64.dll"), "drive_c/windows/system32",'
if source.count(old) != 1:
raise SystemExit("Proton NVAPI copy point changed; cannot stage identity bridge")
path.write_text(source.replace(old, new))
PY
chmod +x "$LAUNCHER_DIR/proton"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="$COMPAT_DIR"
PROTON_ENABLE_NVAPI=1 WINEDEBUG=-all "$PROTON_DIR/proton" run cmd /c exit 0 >/dev/null
NVAPI_REAL="$PROTON_DIR/files/lib/wine/nvapi/x86_64-windows/nvapi64.dll"
if [[ ! -f "$NVAPI_REAL" ]]; then
printf 'Cannot find Proton DXVK-NVAPI at %s\n' "$NVAPI_REAL" >&2
exit 2
fi
cp -f "$NVAPI_REAL" "$COMPAT_DIR/pfx/drive_c/windows/system32/d4r_nvapi64_real.dll"
export D4R_NVAPI_IDENTITY_DLL="$ROOT/build/nvapi64.dll"
export D4R_HARNESS_APP_DIR="$APP_DIR"
export D4R_HARNESS_NGX_DLL="$APP_DIR/dxgi.dll"
export D4R_HARNESS_LOAD_NGX_EARLY=1
export D4R_HARNESS_TRACE="$(d4r_winpath "$APP_DIR/harness.trace")"
export D4R_SHIM_LOG="$(d4r_winpath "$APP_DIR/d4r_nvngx.log")"
export D4R_PROTON_COMPAT_DATA="$COMPAT_DIR"
export DXVK_CONFIG="${DXVK_CONFIG:-dxgi.customVendorId = 10de}"
"$ROOT/scripts/run_d3d12_dlss_harness_proton.sh" "$LAUNCHER_DIR" "$OUTPUT_PATH" "$@"
if [[ ! -s "$OUTPUT_PATH" || ! -f "$APP_DIR/OptiScaler.log" || ! -f "$APP_DIR/d4r_nvngx.log" ]] ||
! rg -q 'DLSSFeatureDx12::Init _CreateFeature result: NVSDK_NGX_Result_Success' "$APP_DIR/OptiScaler.log" ||
! rg -q 'NVSDK_NGX_CUDA_CreateFeature -> 0x00000001' "$APP_DIR/d4r_nvngx.log" ||
! rg -q 'frame [0-9]+ done:' "$APP_DIR/d4r_nvngx.log"; then
printf 'OptiScaler did not complete the official DLSS path; inspect %s\n' "$APP_DIR" >&2
exit 1
fi
printf 'OptiScaler DLSS harness output: %s\n' "$OUTPUT_PATH"
printf 'OptiScaler, shim, and stage logs: %s\n' "$APP_DIR"
sha256sum "$OUTPUT_PATH"
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
# Runs the D3D12 harness through a Proton build's own launcher script, so the
# prefix, DXVK/vkd3d-proton/dxvk-nvapi and DLL overrides match a Steam game.
# usage: run_d3d12_dlss_harness_proton.sh PROTON_DIR OUTPUT_RAW [FRAMES [IN_W IN_H OUT_W OUT_H]]
if [[ $# -lt 2 ]]; then
printf 'usage: %s PROTON_DIR OUTPUT_RAW [FRAMES [IN_W IN_H OUT_W OUT_H]]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
OUTPUT_PATH="$(realpath -m "$2")"
shift 2
source "$ROOT/scripts/d4r_proton_env.sh"
if [[ "${D4R_HARNESS_SKIP_BUILD:-0}" != 1 ]]; then
"$ROOT/scripts/build_d3d12_dlss_harness.sh" >/dev/null
fi
HARNESS_APP_DIR="${D4R_HARNESS_APP_DIR:-$ROOT/build}"
mkdir -p "$HARNESS_APP_DIR"
HARNESS_EXE="$HARNESS_APP_DIR/d3d12_dlss_harness.exe"
if [[ "$(realpath -m "$HARNESS_EXE")" != "$(realpath -m "$ROOT/build/d3d12_dlss_harness.exe")" ]]; then
cp -f "$ROOT/build/d3d12_dlss_harness.exe" "$HARNESS_EXE"
fi
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="${D4R_PROTON_COMPAT_DATA:-${TMPDIR:-/tmp}/d4r-proton-harness-compat}"
mkdir -p "$STEAM_COMPAT_DATA_PATH"
# D4R_HARNESS_NGX_DLL selects the NGX DLL the harness drives (default: the
# shim; point it at OptiScaler installed as nvngx.dll to test OptiScaler).
NGX_DLL="${D4R_HARNESS_NGX_DLL:-$D4R_RUNTIME_DIR/bin/d4r_nvngx.dll}"
"$PROTON_DIR/proton" run "$HARNESS_EXE" "$(d4r_winpath "$NGX_DLL")" \
"$(d4r_winpath "$OUTPUT_PATH")" "$@"
printf '\nShim log:\n'
if [[ -f "$D4R_RUNTIME_DIR/d4r_nvngx.log" ]]; then
tail -n 20 "$D4R_RUNTIME_DIR/d4r_nvngx.log"
fi
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
# Zero-copy D3D12 <-> HIP sharing probe under Proton (see the .cpp).
# usage: run_d3d12_hip_interop_probe.sh PROTON_DIR REPORT_FILE [WIDTH HEIGHT]
if [[ $# -lt 2 ]]; then
printf 'usage: %s PROTON_DIR REPORT_FILE [WIDTH HEIGHT]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
REPORT="$(realpath -m "$2")"
shift 2
source "$ROOT/scripts/d4r_proton_env.sh"
"$ROOT/scripts/build_d3d12_hip_interop_probe.sh" >/dev/null
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="${D4R_PROTON_COMPAT_DATA:-${TMPDIR:-/tmp}/d4r-proton-harness-compat}"
mkdir -p "$STEAM_COMPAT_DATA_PATH"
"$PROTON_DIR/proton" run "$ROOT/build/d3d12_hip_interop_probe.exe" \
"$(d4r_winpath "$D4R_RUNTIME_DIR/bin/nvcuda.dll")" "$(d4r_winpath "$REPORT")" "$@" || status=$?
cat "$REPORT"
exit "${status:-0}"
+170
View File
@@ -0,0 +1,170 @@
#!/usr/bin/env bash
set -euo pipefail
# Launches a Windows game through a GE-Proton build's integrated OptiScaler
# (PROTON_USE_OPTISCALER) with OptiScaler's DLSS backend routed into the d4r
# shim, i.e. official NVIDIA DLSS executed through the Wine CUDA bridge and
# ZLUDA on the AMD GPU.
#
# usage: run_game_d4r_optiscaler_proton.sh PROTON_DIR COMPAT_DATA_DIR GAME_EXE [ARGS...]
#
# The Proton installation and game directory are not modified. The prefix's
# system32/umu/OptiScaler.ini (rewritten by GE-Proton from
# PROTON_OPTISCALER_CONFIG) is restored when the game exits, and the real
# DXVK-NVAPI is placed next to the identity bridge as d4r_nvapi64_real.dll.
# With D4R_VKD3D_DIR (a directory holding d3d12.dll and d3d12core.dll, e.g. the
# d4r-patched vkd3d-proton), those replace Proton's vkd3d-proton in the prefix
# for this launch; the prefix's previous copies are backed up to the log
# directory and restored when the game exits.
# With D4R_UE_ENGINE_INI (the game's Saved/Config/Windows/Engine.ini) and
# D4R_UE_CVARS ("r.A=0;r.B=1"), those console variables are added to its
# [SystemSettings] for this launch only: an existing file is backed up to the
# log directory and restored on exit, a new one is removed again. Unreal games
# apply tonemapper sharpening and chromatic fringe after the upscaler; e.g.
# Townfall's r.Tonemapper.Sharpen and r.SceneColorFringeQuality turn DLSS's
# clean thin lines into haloed, stippled and beaded ones.
# Logs go to D4R_GAME_LOG_DIR (default: a timestamped capture directory).
if [[ $# -lt 3 ]]; then
printf 'usage: %s PROTON_DIR COMPAT_DATA_DIR GAME_EXE [ARGS...]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROTON_DIR="$(realpath "$1")"
COMPAT_DIR="$(realpath "$2")"
GAME_EXE="$(realpath "$3")"
shift 3
# User settings from d4r.ini (config/d4r.ini.default documents them); explicit environment wins.
# D4R_NO_CONFIG=1 ignores the file (automated tests); D4R_CONFIG picks another file.
if [[ "${D4R_NO_CONFIG:-0}" != 1 ]]; then
python3 "$ROOT/scripts/d4r_config.py" --print >&2 || true
D4R_CONFIG_EXPORTS="$(python3 "$ROOT/scripts/d4r_config.py")" || exit 2
eval "$D4R_CONFIG_EXPORTS"
fi
source "$ROOT/scripts/d4r_proton_env.sh"
PREFIX="$COMPAT_DIR/pfx"
UMU="$PREFIX/drive_c/windows/system32/umu"
LOG_DIR="${D4R_GAME_LOG_DIR:-$HOME/.cache/d4r-dlss-captures/game-$(basename "$GAME_EXE" .exe)-$(date +%Y%m%d-%H%M%S)}"
mkdir -p "$LOG_DIR"
[[ -d "$PREFIX" ]] || { printf 'No Proton prefix at %s\n' "$PREFIX" >&2; exit 2; }
# A second launch would join the running wineserver, and whichever run exits
# first would restore its OptiScaler.ini backup underneath the other.
SERVER_DIR="/tmp/.wine-$(id -u)/server-$(stat -c '%D' "$PREFIX" | sed 's/^0*//')-$(printf '%x' "$(stat -c '%i' "$PREFIX")")"
if [[ -S "$SERVER_DIR/socket" ]] && fuser "$SERVER_DIR/socket" >/dev/null 2>&1; then
printf 'A wineserver is already running for %s; close that game first\n' "$PREFIX" >&2
exit 2
fi
"$ROOT/scripts/build_d4r_nvapi_identity.sh" >/dev/null
NVAPI_REAL="$PROTON_DIR/files/lib/wine/nvapi/x86_64-windows/nvapi64.dll"
[[ -f "$NVAPI_REAL" ]] || { printf 'Cannot find DXVK-NVAPI at %s\n' "$NVAPI_REAL" >&2; exit 2; }
cp -f "$NVAPI_REAL" "$PREFIX/drive_c/windows/system32/d4r_nvapi64_real.dll"
# Temporary launcher: identical to the Proton build except that the NVAPI copy
# installs the identity bridge (so OptiScaler enables its DLSS backend).
LAUNCHER_DIR="$(mktemp -d "${TMPDIR:-/tmp}/d4r-game-proton.XXXXXXXX")"
for entry in "$PROTON_DIR"/*; do
[[ "$(basename "$entry")" == proton ]] || ln -s "$entry" "$LAUNCHER_DIR/$(basename "$entry")"
done
cp -f "$PROTON_DIR/proton" "$LAUNCHER_DIR/proton"
LAUNCHER="$LAUNCHER_DIR/proton" python3 - <<'PY'
import os
from pathlib import Path
path = Path(os.environ["LAUNCHER"])
source = path.read_text()
variants = [
'g_proton.arch_pe_dir("wine/nvapi", False) + "nvapi64.dll"',
'g_proton.arch_pe_dir("wine/" + nvapi_path, False) + "nvapi64.dll"',
]
for old in variants:
target = f'try_copy({old}, "drive_c/windows/system32",'
if source.count(target) == 1:
new = f'try_copy(os.environ.get("D4R_NVAPI_IDENTITY_DLL", {old}), "drive_c/windows/system32",'
path.write_text(source.replace(target, new))
break
else:
raise SystemExit("Proton NVAPI copy point not found; cannot stage identity bridge")
if os.environ.get("D4R_VKD3D_DIR"):
source = path.read_text()
old = 'try_copy(g_proton.arch_pe_dir("wine/vkd3d-proton", False) + f + ".dll", "drive_c/windows/system32",'
new = ('try_copy(os.path.join(os.environ["D4R_VKD3D_DIR"], f + ".dll"), "drive_c/windows/system32",')
if source.count(old) != 1:
raise SystemExit("Proton vkd3d-proton copy point not found; cannot stage D4R_VKD3D_DIR")
path.write_text(source.replace(old, new))
PY
# GE-Proton rewrites OptiScaler.ini from PROTON_OPTISCALER_CONFIG; keep the
# user's configuration and put it back afterwards.
INI="$UMU/OptiScaler.ini"
[[ -f "$INI" ]] && cp -f "$INI" "$LOG_DIR/OptiScaler.ini.before"
VKD3D_BACKUP="$LOG_DIR/vkd3d-prefix-backup"
if [[ -n "${D4R_VKD3D_DIR:-}" ]]; then
export D4R_VKD3D_DIR="$(realpath "$D4R_VKD3D_DIR")"
for dll in d3d12.dll d3d12core.dll; do
[[ -f "$D4R_VKD3D_DIR/$dll" ]] || { printf 'D4R_VKD3D_DIR lacks %s\n' "$dll" >&2; exit 2; }
done
mkdir -p "$VKD3D_BACKUP"
for dll in d3d12.dll d3d12core.dll; do
[[ -f "$PREFIX/drive_c/windows/system32/$dll" ]] && cp -f "$PREFIX/drive_c/windows/system32/$dll" "$VKD3D_BACKUP/$dll"
done
fi
ENGINE_INI="${D4R_UE_ENGINE_INI:-}"
ENGINE_INI_STATE=""
restore_prefix() {
[[ -f "$LOG_DIR/OptiScaler.ini.before" ]] && cp -f "$LOG_DIR/OptiScaler.ini.before" "$INI"
case "$ENGINE_INI_STATE" in
restore) cp -f "$LOG_DIR/Engine.ini.before" "$ENGINE_INI" ;;
remove) rm -f "$ENGINE_INI" ;;
esac
if [[ -n "${D4R_VKD3D_DIR:-}" ]]; then
for dll in d3d12.dll d3d12core.dll; do
[[ -f "$VKD3D_BACKUP/$dll" ]] && cp -f "$VKD3D_BACKUP/$dll" "$PREFIX/drive_c/windows/system32/$dll"
done
fi
rm -rf "$LAUNCHER_DIR"
}
trap restore_prefix EXIT
if [[ -n "$ENGINE_INI" && -n "${D4R_UE_CVARS:-}" ]]; then
if [[ -f "$ENGINE_INI" ]]; then
cp -f "$ENGINE_INI" "$LOG_DIR/Engine.ini.before"
ENGINE_INI_STATE=restore
else
mkdir -p "$(dirname "$ENGINE_INI")"
ENGINE_INI_STATE=remove
fi
{ printf '\n[SystemSettings]\n'; tr ';' '\n' <<<"$D4R_UE_CVARS"; printf '\n'; } >> "$ENGINE_INI"
fi
OPTI_CONFIG="Upscalers.Dx12Upscaler=dlss;DLSS.Enabled=true"
OPTI_CONFIG+=";Libraries.NvngxPath=$(d4r_winpath "$D4R_RUNTIME_DIR/bin/d4r_nvngx.dll")"
OPTI_CONFIG+=";Libraries.NvngxDlssPath=$(d4r_winpath "$D4R_RUNTIME_DIR/bin")"
# Game-side DLSS inputs stay hooked; only NGX loads outside the game directory
# are redirected, which lets the shim request the official core by an
# exe-relative path.
OPTI_CONFIG+=";Inputs.EnableDlssInputs=true;Hooks.HookOriginalNvngxOnly=true"
OPTI_CONFIG+=";NvApi.OverrideNvapiDll=false;FrameGen.Enabled=false;FrameGen.FGInput=nofg;FrameGen.FGOutput=nofg"
OPTI_CONFIG+=";Log.LogToFile=true;Log.LogLevel=${D4R_OPTISCALER_LOG_LEVEL:-2}"
# Detailed FPS overlay with frame-time graph (the user's own INI default too).
OPTI_CONFIG+=";Menu.ShowFps=${D4R_OPTISCALER_SHOW_FPS:-true};Menu.FpsOverlayType=${D4R_OPTISCALER_FPS_OVERLAY_TYPE:-3}"
OPTI_CONFIG+="${D4R_EXTRA_OPTISCALER_CONFIG:+;$D4R_EXTRA_OPTISCALER_CONFIG}"
export PROTON_USE_OPTISCALER=1
export PROTON_OPTISCALER_CONFIG="$OPTI_CONFIG"
export D4R_NVAPI_IDENTITY_DLL="$ROOT/build/nvapi64.dll"
export DXVK_CONFIG="${DXVK_CONFIG:-dxgi.customVendorId = 10de}"
export D4R_SHIM_LOG="$(d4r_winpath "$LOG_DIR/d4r_nvngx.log")"
export STEAM_COMPAT_CLIENT_INSTALL_PATH="${STEAM_COMPAT_CLIENT_INSTALL_PATH:-$HOME/.local/share/Steam}"
export STEAM_COMPAT_DATA_PATH="$COMPAT_DIR"
export PROTON_LOG=1 PROTON_LOG_DIR="$LOG_DIR"
export WINEDEBUG="${WINEDEBUG:--all}"
# Games load dozens of modules per launch; do not capture them unless asked.
export D4R_CUDA_CAPTURE="${D4R_CUDA_CAPTURE:-0}"
printf 'd4r game launch: %s\nlogs: %s\n' "$GAME_EXE" "$LOG_DIR"
status=0
(cd "$(dirname "$GAME_EXE")" && "$LAUNCHER_DIR/proton" waitforexitandrun "$GAME_EXE" "$@") \
>"$LOG_DIR/launcher.log" 2>&1 || status=$?
cp -f "$UMU/OptiScaler.log" "$LOG_DIR/OptiScaler.log" 2>/dev/null || true
printf 'game exited with status %s\n' "$status"
exit "$status"
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ROCM_ROOT="${ROCM_ROOT:-/opt/rocm}"
"$ROOT/scripts/build_hip_vk_interop_probe.sh"
LD_LIBRARY_PATH="$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/hip_vk_interop_probe"
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 3 ]]; then
printf 'usage: %s PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL WRITABLE_APPDATA_DIRECTORY\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CORE_PATH="$(realpath "$1")"
FEATURE_DLL_PATH="$(realpath "$2")"
DATA_PATH="$(realpath -m "$3")"
WINE_BIN="${WINE:-wine}"
WINEPREFIX="${D4R_WINEPREFIX:-${TMPDIR:-/tmp}/d4r-wineprefix}"
APP_DIR="${D4R_NGX_CUDA_APPDIR:-${TMPDIR:-/tmp}/d4r-ngxcuda-app}"
CAPTURE_DIR="${D4R_CUDA_CAPTURE_DIR:-${TMPDIR:-/tmp}/d4r-dlss-cuda-modules}"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
TMP_ROOT="$(realpath -m "${TMPDIR:-/tmp}")"
WINEPREFIX="$(realpath -m "$WINEPREFIX")"
APP_DIR="$(realpath -m "$APP_DIR")"
DATA_PATH="$(realpath -m "$DATA_PATH")"
CAPTURE_DIR="$(realpath -m "$CAPTURE_DIR")"
case "$WINEPREFIX/" in
"$TMP_ROOT/"*) ;;
*)
printf 'D4R_WINEPREFIX must be an isolated prefix under %s; refusing to modify a non-temporary prefix\n' "$TMP_ROOT" >&2
exit 2
;;
esac
for isolated_path in "$APP_DIR" "$DATA_PATH" "$CAPTURE_DIR"; do
case "$isolated_path/" in
"$TMP_ROOT/"*) ;;
*)
printf 'App directory, appdata, and CUDA captures must stay under %s; refusing to write outside temporary storage\n' "$TMP_ROOT" >&2
exit 2
;;
esac
done
if [[ ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the temporary or installed ZLUDA/HIP runtimes\n' >&2
exit 2
fi
mkdir -p "$WINEPREFIX/drive_c/windows/system32" "$DATA_PATH" "$APP_DIR" "$CAPTURE_DIR"
"$ROOT/scripts/build_ngx_cuda_probe.sh"
"$ROOT/scripts/build_wine_nvcuda_bridge.sh"
cp -f "$ROOT/build/wine-nvcuda/x86_64-windows/nvcuda.dll" "$WINEPREFIX/drive_c/windows/system32/nvcuda.dll"
APP_EXE_PATH="$APP_DIR/ngx_cuda_probe.exe"
APP_FEATURE_DLL_PATH="$APP_DIR/nvngx_dlss.dll"
cp -f "$ROOT/build/ngx_cuda_probe.exe" "$APP_EXE_PATH"
cp -f "$FEATURE_DLL_PATH" "$APP_FEATURE_DLL_PATH"
CORE_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$CORE_PATH")"
FEATURE_DLL_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$APP_FEATURE_DLL_PATH")"
DATA_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$DATA_PATH")"
APP_EXE_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$APP_EXE_PATH")"
WINE_OVERRIDES="${WINEDLLOVERRIDES:-}"
for override in 'dxgi=n,b' 'd3d12=n,b' 'd3d12core=n,b' 'nvcuda=b'; do
dll_name="${override%%=*}"
if [[ ";$WINE_OVERRIDES;" != *";$dll_name="* ]]; then
WINE_OVERRIDES="${WINE_OVERRIDES:+$WINE_OVERRIDES;}$override"
fi
done
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
WINEDLLPATH="$ROOT/build/wine-nvcuda/x86_64-windows:$ROOT/build/wine-nvcuda/x86_64-unix${WINEDLLPATH:+:$WINEDLLPATH}" \
WINEDLLOVERRIDES="$WINE_OVERRIDES" WINEPREFIX="$WINEPREFIX" \
WINEDEBUG="${D4R_WINEDEBUG:--all}" \
D4R_CUDA_CAPTURE_DIR="$CAPTURE_DIR" \
"$WINE_BIN" "$APP_EXE_WIN_PATH" "$CORE_WIN_PATH" "$FEATURE_DLL_WIN_PATH" "$DATA_WIN_PATH"
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 3 ]]; then
printf 'usage: %s PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL WRITABLE_APPDATA_DIRECTORY\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CORE_PATH="$(realpath "$1")"
FEATURE_DLL_PATH="$(realpath "$2")"
DATA_PATH="$(realpath -m "$3")"
WINE_BIN="${WINE:-wine}"
WINEPREFIX="${D4R_WINEPREFIX:-${TMPDIR:-/tmp}/d4r-wineprefix}"
mkdir -p "$WINEPREFIX" "$DATA_PATH"
"$ROOT/scripts/build_ngx_d3d12_probe.sh"
CORE_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$CORE_PATH")"
FEATURE_DLL_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$FEATURE_DLL_PATH")"
DATA_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$DATA_PATH")"
WINEPREFIX="$WINEPREFIX" WINEDEBUG="${D4R_WINEDEBUG:--all}" \
"$WINE_BIN" "$ROOT/build/ngx_d3d12_probe.exe" "$CORE_WIN_PATH" "$FEATURE_DLL_WIN_PATH" "$DATA_WIN_PATH"
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
printf 'usage: %s PATH_TO_NVNGX_DLSS_DLL\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DLL_PATH="$(realpath "$1")"
WINE_BIN="${WINE:-wine}"
WINEPREFIX="${D4R_WINEPREFIX:-${TMPDIR:-/tmp}/d4r-wineprefix}"
"$ROOT/scripts/build_ngx_load_probe.sh"
mkdir -p "$WINEPREFIX"
DLL_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$DLL_PATH")"
WINEPREFIX="$WINEPREFIX" WINEDEBUG="${D4R_WINEDEBUG:--all}" \
"$WINE_BIN" "$ROOT/build/ngx_load_probe.exe" "$DLL_WIN_PATH"
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 3 ]]; then
printf 'usage: %s PATH_TO_NGX_CORE_DLL PATH_TO_NVNGX_DLSS_DLL WRITABLE_APPDATA_DIRECTORY\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CORE_PATH="$(realpath "$1")"
FEATURE_DLL_PATH="$(realpath "$2")"
DATA_PATH="$(realpath -m "$3")"
WINE_BIN="${WINE:-wine}"
WINEPREFIX="${D4R_WINEPREFIX:-${TMPDIR:-/tmp}/d4r-wineprefix}"
mkdir -p "$WINEPREFIX" "$DATA_PATH"
"$ROOT/scripts/build_ngx_vulkan_probe.sh"
CORE_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$CORE_PATH")"
FEATURE_DLL_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$FEATURE_DLL_PATH")"
DATA_WIN_PATH="$(WINEPREFIX="$WINEPREFIX" winepath -w "$DATA_PATH")"
WINEPREFIX="$WINEPREFIX" WINEDEBUG="${D4R_WINEDEBUG:--all}" \
"$WINE_BIN" "$ROOT/build/ngx_vulkan_probe.exe" "$CORE_WIN_PATH" "$FEATURE_DLL_WIN_PATH" "$DATA_WIN_PATH"
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_fp8_ops.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_fp8_ops"
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -ne 1 ]]; then
printf 'usage: %s PATH_TO_LOCALLY_CAPTURED_DLSS_HISTOGRAM_FATBIN\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_histogram.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_histogram" "$1"
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ $# -lt 1 || $# -gt 2 ]]; then
printf 'usage: %s PATH_TO_LOCALLY_CAPTURED_DLSS_FATBIN [KERNEL_NAME]\n' "$0" >&2
exit 2
fi
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_kernel.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_kernel" "$@"
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_surface_half_store.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_surface_half_store"
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_surface_store.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_surface_store"
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ZLUDA_ROOT="${ZLUDA_ROOT:-}"
ROCM_ROOT="${ROCM_ROOT:-}"
if [[ -z "$ZLUDA_ROOT" || -z "$ROCM_ROOT" || ! -f "$ZLUDA_ROOT/libcuda.so" || ! -f "$ROCM_ROOT/lib/libamdhip64.so" ]]; then
printf 'Set ZLUDA_ROOT and ROCM_ROOT to the ZLUDA and HIP runtimes\n' >&2
exit 2
fi
"$ROOT/scripts/build_replay_dlss_texture_sample.sh"
LD_LIBRARY_PATH="$ZLUDA_ROOT:$ROCM_ROOT/lib:$ROCM_ROOT/lib/llvm/lib:${LD_LIBRARY_PATH:-}" \
"$ROOT/build/replay_dlss_texture_sample"
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env python3
"""Verify all original M11 source pack bytes remain in this reorganized tree."""
import csv, hashlib
from pathlib import Path
root=Path(__file__).resolve().parent.parent
manifest=root/'docs/archive/m11-source-snapshot/MIGRATION_MAP.tsv'
bad=[]
with manifest.open(newline='',encoding='utf-8') as f:
for row in csv.DictReader(f,delimiter='\t'):
path=root/row['new_path']
if not path.is_file():
bad.append('MISSING '+row['new_path']);continue
sha=hashlib.sha256(path.read_bytes()).hexdigest()
if sha!=row['sha256'] or path.stat().st_size!=int(row['bytes']):
bad.append('MISMATCH '+row['new_path'])
if bad:
print('\n'.join(bad[:50]));raise SystemExit(f'FAILED: {len(bad)} mismatches')
print('OK: source file bytes and paths match MIGRATION_MAP.tsv')
+10
View File
@@ -0,0 +1,10 @@
# M11 historical Windows scripts
The source archive's native-Windows M11 scripts are under
[`../../windows/m11/tools/`](../../windows/m11/tools/) and its shim build scripts
under [`../../windows/m11/src/`](../../windows/m11/src/).
They deliberately retain their original **internal** layout because many derive
paths from `$PSScriptRoot`. This pointer does not imply they are interchangeable
with the mainline `scripts/windows/` build and release tooling. See
[`../../docs/windows-m11.md`](../../docs/windows-m11.md).
@@ -0,0 +1,17 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$Module,
[Parameter(Mandatory=$true)][string]$Candidate,
[Parameter(Mandatory=$true)][string]$FixtureDirectory,
[string]$HipRoot, [string]$Probe, [string]$OutputDirectory,
[ValidateRange(1,10000)][int]$Pairs=32,
[ValidateRange(1,256)][int[]]$Batches=@(1,64),
[ValidateSet('events','dispatch')][string[]]$Timings=@('events','dispatch'))
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$Probe) { $Probe=Join-Path $repo 'build/windows-rdna4-therock/d4r_native_replay_probe.exe' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/native-benchmark-'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
& python.exe (Join-Path $repo 'tools/windows/benchmark_native_replay.py') --probe $Probe --hip-root $HipRoot `
--module $Module --candidate $Candidate --fixture-dir $FixtureDirectory --output-dir $OutputDirectory `
--pairs $Pairs --batches @Batches --timings @Timings
if ($LASTEXITCODE) { throw "Native benchmark failed. Logs: $OutputDirectory" }
+28
View File
@@ -0,0 +1,28 @@
[CmdletBinding()]
param([string]$AdlxRoot, [string]$BuildDirectory, [string]$Compiler)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$commit='32b5a740d42295c5dfe9026b9f52683da0f3af91'
if (!$AdlxRoot) { $AdlxRoot=Join-Path $repo 'external/ADLX' }
if (!$BuildDirectory) { $BuildDirectory=Join-Path $repo 'build/gpu-telemetry' }
if (!$Compiler) { $Compiler=Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64/bin/x86_64-w64-mingw32-clang.exe' }
if (!(Test-Path -LiteralPath $AdlxRoot)) {
& git clone --no-checkout https://github.com/GPUOpen-LibrariesAndSDKs/ADLX.git $AdlxRoot
if ($LASTEXITCODE) { throw 'ADLX SDK download failed.' }
& git -C $AdlxRoot checkout --detach $commit
if ($LASTEXITCODE) { throw 'ADLX SDK checkout failed.' }
}
if ((& git -C $AdlxRoot rev-parse HEAD).Trim() -ne $commit -or (& git -C $AdlxRoot status --porcelain)) {
throw "Expected clean ADLX SDK $commit; use a separate AdlxRoot."
}
if (!(Test-Path -LiteralPath $Compiler)) { throw 'Set Compiler to an x64 LLVM-MinGW clang.exe.' }
New-Item -ItemType Directory -Force $BuildDirectory | Out-Null
$exe=Join-Path $BuildDirectory 'd4r_gpu_telemetry.exe'
& $Compiler -std=c11 -O2 -Wall -Wextra -Wno-unknown-pragmas -DWIN32_LEAN_AND_MEAN -D_M_AMD64 `
-isystem "$AdlxRoot/SDK/Include" (Join-Path $repo 'tools/windows/gpu_telemetry.c') -o $exe
if ($LASTEXITCODE) { throw "GPU telemetry compile failed: $LASTEXITCODE" }
@{sdkCommit=$commit; sdkLicense=(Join-Path $AdlxRoot 'ADLX SDK License Agreement.pdf');
executable=$exe; compiler=$Compiler; sha256=(Get-FileHash -LiteralPath $exe -Algorithm SHA256).Hash} |
ConvertTo-Json | Set-Content -LiteralPath (Join-Path $BuildDirectory 'build-info.json') -Encoding UTF8
Write-Host "Built local read-only telemetry: $exe"
# The SDK, driver DLL and SDK-dependent binary are not added to public packages.
+47
View File
@@ -0,0 +1,47 @@
[CmdletBinding()]
param(
[string]$HipRoot = $env:HIP_PATH,
[ValidateSet('gfx1100','gfx1101','gfx1102','gfx1103','gfx1150','gfx1151','gfx1152','gfx1153','gfx1154','gfx1200','gfx1201')]
[string]$GpuArch = 'gfx1101',
[int]$Parallel = [Math]::Max(1, [Environment]::ProcessorCount - 1)
)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { throw 'Pass -HipRoot or set HIP_PATH to the Windows HIP SDK root.' }
$HipRoot = [IO.Path]::GetFullPath($HipRoot)
if (!(Test-Path -LiteralPath (Join-Path $HipRoot 'include/hip/hip_runtime_api.h'))) {
throw "HIP headers not found under $HipRoot"
}
& (Join-Path $PSScriptRoot 'setup-native-engine.ps1')
if ($LASTEXITCODE) { throw "Native engine dependency setup failed: $LASTEXITCODE" }
$tools = Join-Path $repo '.tools'
$cmake = Join-Path $tools 'python/cmake/data/bin/cmake.exe'
$ninja = Join-Path $tools 'python/ninja/data/bin/ninja.exe'
if (!(Test-Path -LiteralPath $cmake)) { $cmake = Join-Path $tools 'python/bin/cmake.exe' }
if (!(Test-Path -LiteralPath $ninja)) { $ninja = Join-Path $tools 'python/bin/ninja.exe' }
if (!(Test-Path -LiteralPath $cmake) -or !(Test-Path -LiteralPath $ninja)) {
throw 'Pinned CMake/Ninja missing. Run scripts/windows/setup-windows-tools.ps1 first.'
}
$toolchain = Join-Path $tools 'llvm-mingw-20260922-ucrt-x86_64/bin'
$cCompiler = Join-Path $toolchain 'x86_64-w64-mingw32-clang.exe'
$cxxCompiler = Join-Path $toolchain 'x86_64-w64-mingw32-clang++.exe'
if (!(Test-Path -LiteralPath $cCompiler) -or !(Test-Path -LiteralPath $cxxCompiler)) {
throw 'Pinned llvm-mingw compiler missing. Run scripts/windows/setup-windows-tools.ps1 first.'
}
$oldPath = $env:PATH
$env:PATH = "$toolchain;$oldPath"
try {
$build = Join-Path $repo "build/native-engine-windows-$GpuArch"
$headers = Join-Path $tools 'Vulkan-Headers-v1.4.341'
$volk = Join-Path $tools 'volk'
& $cmake --fresh -S $repo -B $build -G Ninja "-DCMAKE_MAKE_PROGRAM=$ninja" `
"-DCMAKE_C_COMPILER=$cCompiler" "-DCMAKE_CXX_COMPILER=$cxxCompiler" `
"-DD4R_HIP_ROOT=$HipRoot" "-DD4R_GPU_ARCH=$GpuArch" `
'-DD4R_BUILD_NATIVE_ENGINE=ON' "-DD4R_VULKAN_HEADERS_ROOT=$headers" "-DD4R_VOLK_ROOT=$volk" `
"-DD4R_MINHOOK_ROOT=$(Join-Path $repo 'external/MinHook')"
if ($LASTEXITCODE) { throw "Native engine configure failed: $LASTEXITCODE" }
& $cmake --build $build --target d4r_engine_k d4r_engine_m d4r_engine_rr --parallel $Parallel
if ($LASTEXITCODE) { throw "Native engine build failed: $LASTEXITCODE" }
} finally { $env:PATH = $oldPath }
Write-Host "Built native runners in ${build}: d4r-k.exe, d4r-m.exe, d4r-rr.exe."
@@ -0,0 +1,68 @@
[CmdletBinding()]
param([ValidateSet('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0')]
[string]$Layer='enc1', [ValidateSet('source','cu','wgp')][string]$Mode='source',
[ValidateSet('baseline','load','store','both')][string]$NonTemporal='baseline',
[ValidateSet(0,1,2,4)][int]$PosTiles=0, [switch]$ShareValues, [switch]$PrivateValues,
[switch]$PackedAccumulator,
[string]$HipRoot, [string]$OutputDirectory)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if ($ShareValues -and $PrivateValues) { throw 'Choose shared or private V storage.' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo "build/native-k-experiment-$Layer-$Mode-$NonTemporal-pos$PosTiles-share$([int][bool]$ShareValues)-private$([int][bool]$PrivateValues)-packed$([int][bool]$PackedAccumulator)" }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
foreach ($baseline in @('build/native-k-gfx1201','build/windows-rdna4-therock','dist/windows-rdna4-command-list')) {
if ($OutputDirectory.StartsWith([IO.Path]::GetFullPath((Join-Path $repo $baseline)), [StringComparison]::OrdinalIgnoreCase)) {
throw 'Keep experimental objects outside the validated baseline/package.'
}
}
$compiler=Join-Path $HipRoot 'lib/llvm/bin/clang++.exe'
if (!(Test-Path -LiteralPath $compiler)) { $compiler=Join-Path $HipRoot 'bin/clang++.exe' }
$name="dltss_pwin_${Layer}_layer"
$source=Join-Path $repo "kernels/k/$name.hip"
$flags=@()
if ((Get-Content -LiteralPath $source -Raw) -match '// d4r-build-flags: ([^\r\n]+)') { $flags=$Matches[1].Trim().Split(' ') }
if ($Mode -ne 'source') {
$flags=@($flags | Where-Object { $_ -ne '-mcumode' -and $_ -ne '-mno-cumode' })
$flags+=if ($Mode -eq 'cu') { '-mcumode' } else { '-mno-cumode' }
}
if ($NonTemporal -in @('load','both')) { $flags+='-DPWIN_NT_LOAD' }
if ($NonTemporal -in @('store','both')) { $flags+='-DPWIN_NT_STORE' }
if ($PosTiles) {
if ($Layer -notin @('enc0','enc1','dec0')) { throw 'Token tiling is audited for position-only layers only.' }
$flags+=if ($Layer -eq 'enc1') { "-DD4R_K_ENC1_POS_MT=$PosTiles" } else { "-DD4R_K_POS_MT=$PosTiles" }
}
if ($ShareValues) {
if ($Layer -notin @('enc0','dec0') -and !($Layer -eq 'enc1' -and $PosTiles)) {
throw 'ShareValues requires a position-only template.'
}
$flags+='-DPOS_VSHARE'
}
if ($PackedAccumulator) { $flags+='-DD4R_K_PACKED_ACC' }
if ($PrivateValues) { $flags+='-DD4R_K_PRIVATE_V' }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$object=Join-Path $OutputDirectory "$name.hsaco"
$arguments=@('-x','hip','-std=c++17','--offload-arch=gfx1201','--offload-device-only',
'--no-gpu-bundle-output','-mno-wavefrontsize64','-nogpuinc','-nogpulib','-O3',
'-DD4R_DEVICE_ONLY_MINIMAL','-DD4R_K_FP16_BASELINE')+$flags+@($source,'-o',$object)
$ErrorActionPreference='Continue'
& $compiler @arguments > (Join-Path $OutputDirectory "$name.build.stdout.log") 2> (Join-Path $OutputDirectory "$name.build.stderr.log")
$ErrorActionPreference='Stop'
if ($LASTEXITCODE) { throw "Experimental K compile failed: $Layer" }
& (Join-Path (Split-Path $compiler) 'llvm-objdump.exe') --disassemble --mcpu=gfx1201 $object `
> (Join-Path $OutputDirectory "$name.isa.txt")
if ($LASTEXITCODE) { throw 'Native object ISA extraction failed.' }
& (Join-Path (Split-Path $compiler) 'llvm-readobj.exe') --notes $object `
> (Join-Path $OutputDirectory "$name.metadata.txt")
if ($LASTEXITCODE) { throw 'Native object metadata extraction failed.' }
@{layer=$Layer; architecture='gfx1201'; experimental=$true; numericalValidation='pending';
mode=$Mode; nonTemporal=$NonTemporal; tokenTilesPerWave=$PosTiles; shareValues=[bool]$ShareValues;
privateValues=[bool]$PrivateValues;
packedAccumulator=[bool]$PackedAccumulator;
compiler=$compiler; arguments=$arguments;
sourceCommit=(git -C $repo rev-parse HEAD); workingTreeDirty=[bool](& git -C $repo status --porcelain);
compilerVersion=(& $compiler --version | Out-String).Trim();
sha256=(Get-FileHash -LiteralPath $object -Algorithm SHA256).Hash} |
ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputDirectory "$name.build-info.json") -Encoding UTF8
Write-Host "Compiled gfx1201 K experiment: $Layer mode=$Mode nonTemporal=$NonTemporal posTiles=$PosTiles shareValues=$([bool]$ShareValues). Validate before installing."
# No override manifest or game installation is produced by this script.
@@ -0,0 +1,40 @@
[CmdletBinding()]
param([ValidateSet('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0')]
[string]$Layer='enc1', [string]$HipRoot, [string]$OutputDirectory)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo 'build/native-k-f16-wmma-experimental' }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
if ($OutputDirectory -eq [IO.Path]::GetFullPath((Join-Path $repo 'build/native-k-gfx1201'))) {
throw 'Keep the validated baseline separate from this experimental build.'
}
$compiler=Join-Path $HipRoot 'lib/llvm/bin/clang++.exe'
if (!(Test-Path -LiteralPath $compiler)) { $compiler=Join-Path $HipRoot 'bin/clang++.exe' }
if (!(Test-Path -LiteralPath $compiler)) { throw "HIP compiler missing under $HipRoot" }
$name="dltss_pwin_${Layer}_layer"
$source=Join-Path $repo "kernels/k/$name.hip"
$flags=@()
if ((Get-Content -LiteralPath $source -Raw) -match '// d4r-build-flags: ([^\r\n]+)') { $flags=$Matches[1].Trim().Split(' ') }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$object=Join-Path $OutputDirectory "$name.hsaco"
$ErrorActionPreference='Continue'
& $compiler -x hip -std=c++17 --offload-arch=gfx1201 --offload-device-only --no-gpu-bundle-output `
-mno-wavefrontsize64 -nogpuinc -nogpulib -O3 -DD4R_DEVICE_ONLY_MINIMAL `
-DD4R_K_FP16_BASELINE -DD4R_K_F16_WMMA @flags $source -o $object `
> (Join-Path $OutputDirectory "$name.build.stdout.log") 2> (Join-Path $OutputDirectory "$name.build.stderr.log")
$ErrorActionPreference='Stop'
if ($LASTEXITCODE) { throw "Experimental K FP16 WMMA compile failed: $Layer" }
$isa=Join-Path $OutputDirectory "$name.isa.txt"
& (Join-Path (Split-Path $compiler) 'llvm-objdump.exe') --disassemble --mcpu=gfx1201 $object > $isa
if ($LASTEXITCODE -or !(Select-String -LiteralPath $isa -Pattern 'v_wmma_f16_16x16x16_f16')) {
throw 'Packed FP16 WMMA is absent from ISA; no alternative instruction is accepted.'
}
& (Join-Path (Split-Path $compiler) 'llvm-readobj.exe') --notes $object `
> (Join-Path $OutputDirectory "$name.metadata.txt")
if ($LASTEXITCODE) { throw 'Native object metadata extraction failed.' }
@{layer=$Layer; architecture='gfx1201'; experimental=$true; numericalValidation='pending';
compiler=$compiler; sha256=(Get-FileHash -LiteralPath $object -Algorithm SHA256).Hash} |
ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory "$name.build-info.json") -Encoding UTF8
Write-Host "Compiled experimental gfx1201 packed FP16 WMMA: $Layer. Validate before selecting another layer."
# This script does not generate an override manifest or install into the game.
+60
View File
@@ -0,0 +1,60 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$HipRoot, [string]$OutputDirectory, [switch]$HardwarePacking, [switch]$TokenLanes)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo $(if ($HardwarePacking) { 'build/native-m-fp8-hardware-pack' } else { 'build/native-m-fp8-experimental' }) }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
if ($OutputDirectory -eq [IO.Path]::GetFullPath((Join-Path $repo 'build/native-m-gfx1201'))) {
throw 'Keep the validated FP16 baseline separate from the experimental FP8 build.'
}
$DlssDll=(Get-Item -LiteralPath $DlssDll -ErrorAction Stop).FullName
$compiler=Join-Path $HipRoot 'lib/llvm/bin/clang++.exe'
if (!(Test-Path -LiteralPath $compiler)) { $compiler=Join-Path $HipRoot 'bin/clang++.exe' }
if (!(Test-Path -LiteralPath $compiler)) { throw "HIP compiler missing under $HipRoot" }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$disassembler=Join-Path (Split-Path $compiler) 'llvm-objdump.exe'
if (!(Test-Path -LiteralPath $disassembler)) { throw 'HIP llvm-objdump is required to confirm native FP8 instructions.' }
foreach ($source in Get-ChildItem -LiteralPath (Join-Path $repo 'kernels/m') -Filter '*.hip' | Sort-Object Name) {
$flags=@()
if ((Get-Content -LiteralPath $source.FullName -Raw) -match '// d4r-build-flags: ([^\r\n]+)') { $flags=$Matches[1].Trim().Split(' ') }
if ($HardwarePacking) { $flags+='-DD4R_FP8_HW_PACK' }
if ($TokenLanes) { $flags+='-DSWIN_TOKEN_LANES' }
$object=Join-Path $OutputDirectory ($source.BaseName+'.hsaco')
$ErrorActionPreference='Continue'
& $compiler -x hip -std=c++17 --offload-arch=gfx1201 --offload-device-only --no-gpu-bundle-output `
-mno-wavefrontsize64 -nogpuinc -nogpulib -O3 -DD4R_DEVICE_ONLY_MINIMAL `
-DSWIN_EXACT -DSWIN_EXACT_PV -DD4R_FP8_WMMA @flags $source.FullName `
-o $object > (Join-Path $OutputDirectory ($source.BaseName+'.build.stdout.log')) `
2> (Join-Path $OutputDirectory ($source.BaseName+'.build.stderr.log'))
$ErrorActionPreference='Stop'
if ($LASTEXITCODE) { throw "Experimental FP8 compile failed: $($source.Name)" }
$isa=Join-Path $OutputDirectory ($source.BaseName+'.isa.txt')
& $disassembler --disassemble --mcpu=gfx1201 $object > $isa
if ($LASTEXITCODE -or !(Select-String -LiteralPath $isa -Pattern 'v_wmma_f32_16x16x16_fp8_fp8')) {
throw "Native FP8 WMMA is absent from $($source.Name); no FP16 fallback is accepted."
}
if ($HardwarePacking -and !(Select-String -LiteralPath $isa -Pattern 'v_cvt_pk_fp8_f32')) { throw 'Native FP8 operand packing is absent from ISA.' }
Write-Host "Compiled gfx1201 FP8 WMMA: $($source.BaseName)"
}
if ($HardwarePacking) {
$probeDirectory=Join-Path $OutputDirectory 'packing-probe'
New-Item -ItemType Directory -Force $probeDirectory | Out-Null
& $compiler -x hip -std=c++17 --offload-arch=gfx1201 --offload-device-only --no-gpu-bundle-output `
-mno-wavefrontsize64 -nogpuinc -nogpulib -O3 -DD4R_DEVICE_ONLY_MINIMAL `
-DD4R_FP8_WMMA -DD4R_FP8_HW_PACK -DSWIN_EXACT -DSWIN_EXACT_PV `
(Join-Path $repo 'tools/windows/fp8_pack_probe.hip') -o (Join-Path $probeDirectory 'fp8_pack_probe.hsaco')
if ($LASTEXITCODE) { throw 'Native hardware packing diagnostic compile failed.' }
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $OutputDirectory $DlssDll
if ($LASTEXITCODE) { throw 'Experimental FP8 manifest generation failed.' }
@{architecture='gfx1201'; family='M'; experimental=$true; nativeFp8=$true; accuracy=$true;
numerics='SWIN_EXACT; SWIN_EXACT_PV; FP8 WMMA for e4m3 GEMMs; exact FP16 attention';
validation='not validated; do not install before layer/full-network checks'; tokenLanes=[bool]$TokenLanes;
compiler=$compiler; compilerVersion=(& $compiler --version | Select-Object -First 1);
sourceCommit=(& git -C $repo rev-parse HEAD).Trim(); nativeFp8IsaVerified=$true; hardwarePacking=[bool]$HardwarePacking;
sourceWorkingTreeDirty=[bool](& git -C $repo status --porcelain);
dlssSha256=(Get-FileHash -LiteralPath $DlssDll -Algorithm SHA256).Hash;
modules=@(Get-ChildItem -LiteralPath $OutputDirectory -Filter '*.hsaco' | Get-FileHash -Algorithm SHA256)} |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'build-info.json') -Encoding UTF8
Write-Host "Experimental native FP8 M objects: $OutputDirectory (baseline unchanged)"
+59
View File
@@ -0,0 +1,59 @@
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$DlssdDll,
[ValidateSet('D','E')][string]$Preset='D',
[string]$OutputDirectory,
[string]$GitBash='C:\Program Files\Git\bin\bash.exe'
)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$DlssdDll=(Get-Item -LiteralPath $DlssdDll -ErrorAction Stop).FullName
$GitBash=(Get-Item -LiteralPath $GitBash -ErrorAction Stop).FullName
$expectedHash='4bc7ea5fcb2f32cf86bc2cb072e8d2860914a0be511cbdcb2fc206c1d9d83b80'
$hash=(Get-FileHash -LiteralPath $DlssdDll -Algorithm SHA256).Hash.ToLowerInvariant()
if($hash -ne $expectedHash){throw "Unsupported nvngx_dlssd.dll SHA256 $hash; expected NVIDIA DLSS 310.9.1 ($expectedHash)."}
if(!$OutputDirectory){$OutputDirectory=Join-Path $repo ("build/native-rr-$($Preset.ToLower())-windows-gfx1101")}
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
$buildRoot=[IO.Path]::GetFullPath((Join-Path $repo 'build'))
if(!$OutputDirectory.StartsWith($buildRoot+'\',[StringComparison]::OrdinalIgnoreCase)){
throw "RR model output must stay under the ignored build directory: $OutputDirectory"
}
if(Test-Path -LiteralPath $OutputDirectory){throw "Use a new RR model output directory: $OutputDirectory"}
$glslang=Join-Path $repo '.tools/glslang-16.6.0/bin'
$pythonHome=Split-Path (Get-Command python.exe -ErrorAction Stop).Source
$pythonShim=Join-Path $repo '.tools/rr-build-bin'
New-Item -ItemType Directory -Force $pythonShim | Out-Null
$python3=Join-Path $pythonShim 'python3.exe'
Copy-Item -LiteralPath (Get-Command python.exe).Source -Destination $python3 -Force
$pythonVendor=Join-Path $repo '.tools/python/vendor'
$cygpath=Join-Path (Split-Path (Split-Path $GitBash -Parent) -Parent) 'usr/bin/cygpath.exe'
if(!(Test-Path -LiteralPath $cygpath)){throw "Git for Windows cygpath missing: $cygpath"}
foreach($tool in @($python3,(Join-Path $glslang 'glslangValidator.exe'))){if(!(Test-Path -LiteralPath $tool)){throw "RR build tool missing: $tool"}}
$unixRepo=(& $cygpath -u $repo).Trim()
$unixDll=(& $cygpath -u $DlssdDll).Trim()
$unixOut=(& $cygpath -u $OutputDirectory).Trim()
if(!$unixRepo -or !$unixDll -or !$unixOut){throw 'Git Bash path conversion failed.'}
$oldPath=$env:PATH
$oldPythonPath=$env:PYTHONPATH
$env:PATH="$pythonShim;$pythonHome;$glslang;$(Split-Path $GitBash -Parent);$oldPath"
$env:PYTHONPATH=$pythonVendor
$env:D4R_RR_GFX11='1'
$env:D4R_RR_RELAXED='0'
$log=Join-Path $buildRoot ("native-rr-$($Preset.ToLower())-windows-build.log")
try{
& $python3 -c 'import numpy; print("numpy", numpy.__version__)'
if($LASTEXITCODE){throw 'Pinned NumPy could not load in the Windows RR build environment.'}
$command="cd '$unixRepo' && D4R_RR_GFX11=1 D4R_RR_RELAXED=0 bash engine/rr/build_native_model.sh --dll '$unixDll' '$Preset' '$unixOut'"
$previousPreference=$ErrorActionPreference
try{
$ErrorActionPreference='Continue'
& $GitBash -lc $command *> $log
$bashExit=$LASTEXITCODE
}finally{$ErrorActionPreference=$previousPreference}
if($bashExit){throw "RR model build failed with exit $bashExit; see $log"}
foreach($required in @('rr.txt','model.json','enc0_m.spv','dec0_m.spv','hkpn.spv','enc0.args','hkpn.args')){
if(!(Test-Path -LiteralPath (Join-Path $OutputDirectory $required))){throw "RR build incomplete; missing $required"}
}
Write-Host "Built local preset $Preset native RR model: $OutputDirectory"
Write-Host "DLL SHA256: $hash. Build log: $log"
}finally{$env:PATH=$oldPath;$env:PYTHONPATH=$oldPythonPath}
+19
View File
@@ -0,0 +1,19 @@
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$DlssDll,
[string]$Kernel = 'hiluma_engine_output_depthinv_mvlo_hdr_max_v2_rel',
[string]$HipRoot = 'C:\Program Files\AMD\ROCm\7.2',
[string]$ZludaRoot,
[ValidateSet('cu','wgp')][string]$ShaderMode='cu',
[string]$GpuArch='gfx1201',
[string]$OutputDirectory
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
[void](Get-D4RGpuTargetInfo $GpuArch)
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo "build/private-textures-$GpuArch" }
& python (Join-Path $repo 'tools/windows/build_native_texture.py') --dlss-dll $DlssDll --hip-root $HipRoot `
--zluda-root $ZludaRoot --kernel $Kernel --output-directory $OutputDirectory --shader-mode $ShaderMode --gpu-arch $GpuArch
if ($LASTEXITCODE) { throw "Native texture build failed ($LASTEXITCODE); inspect the output work directory." }
@@ -0,0 +1,93 @@
[CmdletBinding()]
param(
[string]$SourceRoot,
[string]$BuildToolsRoot,
[string]$InstallRoot,
[int]$Jobs = 6
)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/OptiScaler' }
if (!$InstallRoot) { $InstallRoot = Join-Path $repo 'dist/optiscaler-windows-d4r' }
$SourceRoot = [IO.Path]::GetFullPath($SourceRoot)
$InstallRoot = [IO.Path]::GetFullPath($InstallRoot)
$base = '45a2001303ddff632e279f77aef85ceede5832cb'
$patches = @(Get-ChildItem -LiteralPath (Join-Path $repo 'patches/optiscaler') -Filter '*.patch' | Sort-Object Name)
if (!$patches.Count) { throw 'OptiScaler source patches are missing.' }
$previousPath = $env:PATH
try {
# Git for Windows' submodule helper needs its POSIX utility directory.
$gitExe = (Get-Command git -ErrorAction Stop).Source
$gitInstall = [IO.Path]::GetFullPath((Join-Path (Split-Path $gitExe) '..'))
$gitUtilities = Join-Path $gitInstall 'usr/bin'
if (Test-Path -LiteralPath $gitUtilities) { $env:PATH = "$gitUtilities;$env:PATH" }
if (!(Test-Path -LiteralPath (Join-Path $SourceRoot '.git'))) {
& git clone --filter=blob:none --no-checkout https://github.com/optiscaler/OptiScaler.git $SourceRoot
if ($LASTEXITCODE) { throw 'OptiScaler clone failed.' }
& git -C $SourceRoot checkout --detach $base
if ($LASTEXITCODE) { throw 'Pinned OptiScaler checkout failed.' }
}
& git -C $SourceRoot merge-base --is-ancestor $base HEAD
if ($LASTEXITCODE) { throw "OptiScaler must be based on audited commit $base" }
foreach ($patch in $patches) {
$ErrorActionPreference = 'Continue'
& git -C $SourceRoot apply --reverse --check $patch.FullName 2>$null
$alreadyApplied = $LASTEXITCODE -eq 0
$ErrorActionPreference = 'Stop'
if (!$alreadyApplied) {
& git -C $SourceRoot apply --check $patch.FullName
if ($LASTEXITCODE) { throw "Source patch conflicts: $($patch.Name); existing changes retained." }
& git -C $SourceRoot apply $patch.FullName
if ($LASTEXITCODE) { throw "Source patch failed: $($patch.Name)" }
}
}
# Verify existing checkouts directly. A complete local checkout does not
# need Git's shell-based submodule helper (or a network connection).
$submodulePaths=@(& git -C $SourceRoot config --file .gitmodules --get-regexp '\.path$' | ForEach-Object { ($_ -split ' ',2)[1] })
$submodules=@()
foreach ($path in $submodulePaths) {
$tree=(& git -C $SourceRoot ls-tree HEAD -- $path) -split '\s+',4
if ($tree.Count -lt 4 -or $tree[0] -ne '160000') { throw "Missing pinned submodule: $path" }
$checkout=Join-Path $SourceRoot $path
$actual=if (Test-Path -LiteralPath (Join-Path $checkout '.git')) { (& git -C $checkout rev-parse HEAD).Trim() } else { '' }
if ($actual -ne $tree[2]) {
& git -C $SourceRoot submodule update --init --depth 1 -- $path
if ($LASTEXITCODE) { throw "Pinned OptiScaler submodule failed: $path" }
$actual=(& git -C $checkout rev-parse HEAD).Trim()
if ($actual -ne $tree[2]) { throw "Wrong submodule revision: $path" }
}
$submodules+=(' '+$actual+' '+$path)
}
if (!$BuildToolsRoot -and (Test-Path -LiteralPath (Join-Path $repo '.tools/vs2022/MSBuild/Current/Bin/MSBuild.exe'))) {
$BuildToolsRoot = Join-Path $repo '.tools/vs2022'
}
if (!$BuildToolsRoot) {
$vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio/Installer/vswhere.exe'
if (Test-Path -LiteralPath $vswhere) {
$BuildToolsRoot = & $vswhere -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath
}
}
if (!$BuildToolsRoot) { throw 'MSVC v143 Build Tools and Windows SDK 10.0.26100 are required; see patches/optiscaler/README.md.' }
$msbuild = Join-Path $BuildToolsRoot 'MSBuild/Current/Bin/MSBuild.exe'
if (!(Test-Path -LiteralPath $msbuild)) { throw "MSBuild missing: $msbuild" }
New-Item -ItemType Directory -Force $InstallRoot | Out-Null
$log = Join-Path $InstallRoot 'build.log'
$ErrorActionPreference = 'Continue'
& $msbuild (Join-Path $SourceRoot 'OptiScaler.sln') "/m:$Jobs" /p:Configuration=Release /p:Platform=x64 `
/p:PostBuildEventUseInBuild=false /verbosity:quiet "/flp:logfile=$log;verbosity=normal"
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "OptiScaler build failed ($LASTEXITCODE); see $log" }
foreach ($file in @('OptiScaler.dll', 'OptiScaler.pdb')) {
Copy-Item -LiteralPath (Join-Path $SourceRoot "x64/Release/$file") -Destination $InstallRoot -Force
}
Copy-Item -LiteralPath (Join-Path $SourceRoot 'LICENSE') -Destination (Join-Path $InstallRoot 'GPL-3.0.txt') -Force
foreach ($patch in $patches) { Copy-Item -LiteralPath $patch.FullName -Destination $InstallRoot -Force }
$metadata = @{base=$base; sourceCommit=(& git -C $SourceRoot rev-parse HEAD).Trim();
sourceDirty=[bool](& git -C $SourceRoot status --porcelain); backendAbi=1;
buildTools=$BuildToolsRoot; msbuildVersion=(& $msbuild -version -nologo | Select-Object -Last 1);
patches=@($patches | ForEach-Object { @{name=$_.Name; sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash} });
dllSha256=(Get-FileHash -LiteralPath (Join-Path $InstallRoot 'OptiScaler.dll') -Algorithm SHA256).Hash;
submodules=$submodules}
$metadata | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $InstallRoot 'build-info.json') -Encoding UTF8
Write-Host "Built OptiScaler with external Windows d4r backend: $InstallRoot"
} finally { $env:PATH = $previousPath }
@@ -0,0 +1,44 @@
[CmdletBinding()]
param(
[string[]]$GpuArchitectures,
[ValidateSet('stable','therock')][string]$RuntimeProfile='therock',
[string]$ZludaRoot, [string]$DlssDll,
[switch]$PackageGames,
[string]$BuildRoot, [string]$OutputRoot, [string]$ArchiveDirectory
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$GpuArchitectures) { $GpuArchitectures=@(Get-D4RGpuTargets | ForEach-Object { $_.architecture }) }
foreach ($arch in $GpuArchitectures) { [void](Get-D4RGpuTargetInfo $arch) }
if (@($GpuArchitectures | Select-Object -Unique).Count -ne $GpuArchitectures.Count) { throw 'Duplicate GPU target.' }
if (!$BuildRoot) { $BuildRoot=Join-Path $repo 'build/windows-gpu-coverage' }
if (!$OutputRoot) { $OutputRoot=Join-Path $repo 'dist/windows-gpu-coverage' }
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if ($ArchiveDirectory -and !$PackageGames) { throw 'ArchiveDirectory requires PackageGames.' }
if ($PackageGames -and (!$DlssDll -or ![IO.Path]::IsPathRooted($DlssDll) -or !(Test-Path -LiteralPath $DlssDll))) {
throw 'PackageGames requires an absolute path to your local nvngx_dlss.dll; it will not be redistributed.'
}
New-Item -ItemType Directory -Force $BuildRoot | Out-Null
if ($ArchiveDirectory) { New-Item -ItemType Directory -Force $ArchiveDirectory | Out-Null }
$results=[Collections.Generic.List[object]]::new()
foreach ($arch in $GpuArchitectures) {
$build="$BuildRoot-$arch"; $diag="$OutputRoot-$arch"
$log=Join-Path $BuildRoot "$arch-build.log"
Write-Host "Building $arch (compile/package only; no GPU workloads). Log: $log"
& (Join-Path $PSScriptRoot 'build-windows-rdna4.ps1') -RuntimeProfile $RuntimeProfile -GpuArch $arch `
-ZludaRoot $ZludaRoot -BuildDirectory $build -InstallDirectory $diag *> $log
$row=[ordered]@{architecture=$arch; compiled=$true; hardwareTestExecuted=$false; buildDirectory=$build; diagnosticRoot=$diag; log=$log}
if ($PackageGames) {
$k="$BuildRoot-native-k-$arch"; $m="$BuildRoot-native-m-$arch"; $game="$OutputRoot-game-$arch"
& (Join-Path $PSScriptRoot 'stage-native-k.ps1') -DlssDll $DlssDll -PackageRoot $diag -GpuArch $arch -OutputDirectory $k
& (Join-Path $PSScriptRoot 'stage-native-m.ps1') -DlssDll $DlssDll -PackageRoot $diag -GpuArch $arch -OutputDirectory $m
$packageArgs=@{DiagnosticRoot=$diag; GpuArch=$arch; PackageRoot=$game; ZludaRoot=$ZludaRoot; KernelKRoot=$k; KernelMRoot=$m}
if ($ArchiveDirectory) { $packageArgs.ArchivePath=Join-Path $ArchiveDirectory "d4r-windows-$arch.zip" }
& (Join-Path $PSScriptRoot 'package-windows-game.ps1') @packageArgs
$row.gamePackage=$game
}
$results.Add($row)
$results | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $BuildRoot 'matrix-build.json') -Encoding UTF8
Write-Host "Compiled $arch; hardware validation remains separate."
}
+79
View File
@@ -0,0 +1,79 @@
[CmdletBinding()]
param(
[string]$HipRoot = $env:HIP_PATH,
[ValidateSet('stable', 'therock')][string]$RuntimeProfile = 'stable',
[string]$GpuArch = 'gfx1201',
[string]$ZludaRoot,
[string]$ToolchainRoot,
[string]$BuildDirectory,
[string]$InstallDirectory
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
[void](Get-D4RGpuTargetInfo $GpuArch)
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if ($RuntimeProfile -eq 'therock') {
if (!$PSBoundParameters.ContainsKey('HipRoot')) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$BuildDirectory) { $BuildDirectory = Join-Path $repo 'build/windows-rdna4-therock' }
if (!$InstallDirectory) { $InstallDirectory = Join-Path $repo 'dist/windows-rdna4-therock' }
}
if (!$HipRoot) { $HipRoot = 'C:\Program Files\AMD\ROCm\7.2' }
if (!$BuildDirectory) { $BuildDirectory = Join-Path $repo 'build/windows-rdna4' }
if (!$InstallDirectory) { $InstallDirectory = Join-Path $repo 'dist/windows-rdna4-diagnostics' }
if ($GpuArch -ne 'gfx1201') {
if (!$PSBoundParameters.ContainsKey('BuildDirectory')) { $BuildDirectory += "-$GpuArch" }
if (!$PSBoundParameters.ContainsKey('InstallDirectory')) { $InstallDirectory += "-$GpuArch" }
}
$HipRoot = [IO.Path]::GetFullPath($HipRoot).TrimEnd('\', '/')
$BuildDirectory = [IO.Path]::GetFullPath($BuildDirectory).TrimEnd('\', '/')
$InstallDirectory = [IO.Path]::GetFullPath($InstallDirectory).TrimEnd('\', '/')
if (!$ZludaRoot -and (Test-Path (Join-Path $repo '.tools/zluda/zluda/nvcuda.dll'))) {
$ZludaRoot = Join-Path $repo '.tools/zluda/zluda'
}
if (!$ToolchainRoot -and (Test-Path (Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64'))) {
$ToolchainRoot = Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64'
}
$cmakeCommand = Get-Command cmake -ErrorAction SilentlyContinue
$cmake = if ($cmakeCommand) { $cmakeCommand.Source } else { Join-Path $repo '.tools/python/cmake/data/bin/cmake.exe' }
$ninjaCommand = Get-Command ninja -ErrorAction SilentlyContinue
$ninja = if ($ninjaCommand) { $ninjaCommand.Source } else { Join-Path $repo '.tools/python/ninja/data/bin/ninja.exe' }
if (!(Test-Path $ninja)) { $ninja = Join-Path $repo '.tools/python/bin/ninja.exe' }
if (!(Test-Path $cmake) -or !(Test-Path $ninja)) {
throw 'CMake >=3.24 and Ninja required. See docs/windows-rdna4-port.md for local tool setup.'
}
New-Item -ItemType Directory -Force $BuildDirectory | Out-Null
$minhook = Join-Path $repo 'external/MinHook'
if (!(Test-Path (Join-Path $minhook 'include/MinHook.h'))) {
& git clone --depth 1 --branch v1.3.4 https://github.com/TsudaKageyu/minhook.git $minhook
if ($LASTEXITCODE) { throw 'MinHook 1.3.4 source download failed.' }
}
$minhookCommit = (& git -C $minhook rev-parse HEAD).Trim()
if ($minhookCommit -ne 'c3fcafdc10146beb5919319d0683e44e3c30d537') {
throw "Expected audited MinHook 1.3.4 source, found $minhookCommit"
}
$originalPath = $env:PATH
try {
$configure = @('--fresh', '-S', $repo, '-B', $BuildDirectory, '-G', 'Ninja', '-DCMAKE_BUILD_TYPE=RelWithDebInfo',
"-DCMAKE_MAKE_PROGRAM=$ninja", "-DD4R_HIP_ROOT=$HipRoot", "-DD4R_GPU_ARCH=$GpuArch", "-DCMAKE_INSTALL_PREFIX=$InstallDirectory")
if ($ToolchainRoot) {
$compiler = Join-Path $ToolchainRoot 'bin/x86_64-w64-mingw32-clang++.exe'
if (!(Test-Path $compiler)) { throw "Compiler missing: $compiler" }
$env:PATH = "$(Join-Path $ToolchainRoot 'bin');$originalPath"
$configure += "-DCMAKE_CXX_COMPILER=$compiler"
$configure += "-DCMAKE_C_COMPILER=$(Join-Path $ToolchainRoot 'bin/x86_64-w64-mingw32-clang.exe')"
}
if ($ZludaRoot) { $configure += "-DD4R_ZLUDA_ROOT=$ZludaRoot" }
$ErrorActionPreference = 'Continue'
& $cmake @configure 2>&1 | Tee-Object (Join-Path $BuildDirectory 'configure.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "CMake configure exit=$LASTEXITCODE" }
$ErrorActionPreference = 'Continue'
& $cmake --build $BuildDirectory --parallel 4 2>&1 | Tee-Object (Join-Path $BuildDirectory 'build.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "Build exit=$LASTEXITCODE" }
$ErrorActionPreference = 'Continue'
& $cmake --install $BuildDirectory 2>&1 | Tee-Object (Join-Path $BuildDirectory 'install.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "Install exit=$LASTEXITCODE" }
Write-Host "Built diagnostics: $InstallDirectory"
} finally { $env:PATH = $originalPath }
+70
View File
@@ -0,0 +1,70 @@
[CmdletBinding()]
param([string]$SourceRoot, [string]$HipRoot = 'C:\Program Files\AMD\ROCm\7.2', [string]$WorkRoot)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/ZLUDA' }
if (!$WorkRoot) { $WorkRoot = Join-Path $repo 'build/zluda-helpers-windows' }
$toolchain = Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64'
$compiler = Join-Path $HipRoot 'bin/clang++.exe'
$dis = Join-Path $HipRoot 'bin/llvm-dis.exe'
$assembler = Join-Path $HipRoot 'bin/llvm-as.exe'
$ocml = Join-Path $HipRoot 'amdgcn/bitcode/ocml.bc'
foreach ($file in @($compiler,$dis,$assembler,$ocml)) {
if (!(Test-Path $file)) { throw "HIP helper dependency missing: $file" }
}
New-Item -ItemType Directory -Force $WorkRoot | Out-Null
$configInclude = Join-Path $WorkRoot 'libcxx-config'
New-Item -ItemType Directory -Force $configInclude | Out-Null
Copy-Item -LiteralPath (Join-Path $toolchain 'include/c++/v1/__config_site') -Destination $configInclude -Force
Copy-Item -LiteralPath (Join-Path $SourceRoot 'ext/llvm-project/libcxx/vendor/llvm/default_assertion_handler.in') `
-Destination (Join-Path $configInclude '__assertion_handler') -Force
# HIP 7.2's long shuffle overloads assume every non-MSVC compiler has LP64.
# Windows GNU also has 32-bit long. Correct that public header in a private
# mirror; the installed SDK remains untouched and the GPU target is unchanged.
$hipInclude = Join-Path $WorkRoot 'hip-include'
New-Item -ItemType Directory -Force $hipInclude | Out-Null
Copy-Item -LiteralPath (Join-Path $HipRoot 'include/hip') -Destination $hipInclude -Recurse -Force
$warpHeader = Join-Path $hipInclude 'hip/amd_detail/amd_warp_functions.h'
$warpSource = [IO.File]::ReadAllText($warpHeader)
$warpSource = $warpSource.Replace('#ifndef _MSC_VER', '#if __SIZEOF_LONG__ == 8')
[IO.File]::WriteAllText($warpHeader,$warpSource,[Text.UTF8Encoding]::new($false))
$variants = @(
@{Suffix=''; Flags=@()},
@{Suffix='_constrained'; Flags=@('-ffp-model=strict','-ffp-exception-behavior=ignore')},
@{Suffix='_w64'; Flags=@('-mwavefrontsize64','-DD4R_WAVE64')},
@{Suffix='_constrained_w64'; Flags=@('-ffp-model=strict','-ffp-exception-behavior=ignore','-mwavefrontsize64','-DD4R_WAVE64')}
)
foreach ($variant in $variants) {
$name = 'zluda_ptx_impl' + $variant.Suffix
$raw = Join-Path $WorkRoot "$name.raw.bc"
$ir = Join-Path $WorkRoot "$name.ll"
$output = Join-Path $SourceRoot "ptx/lib/$name.bc"
$arguments = @('-x','hip','-std=c++20','--target=x86_64-w64-windows-gnu','-stdlib=libc++',
'--offload-arch=gfx1030','--offload-device-only','-emit-llvm','-c','-nogpulib','-O3',
'-mno-wavefrontsize64','-DHIP_ENABLE_WARP_SYNC_BUILTINS',
'-Xclang','-fdenormal-fp-math=dynamic',
'-isystem',(Join-Path $SourceRoot 'ext/llvm-project/libcxx/include'),
'-isystem',$configInclude,
'-isystem',(Join-Path $toolchain 'include'),
'-I',$hipInclude,
'-Xclang','-mlink-bitcode-file','-Xclang',$ocml)
$arguments += $variant.Flags
$arguments += @('-o',$raw,(Join-Path $SourceRoot 'ptx/lib/zluda_ptx_impl.cpp'))
$ErrorActionPreference = 'Continue'
& $compiler @arguments 2>&1 | Tee-Object (Join-Path $WorkRoot "$name.compile.log")
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "PTX helper compile failed: $name ($LASTEXITCODE)" }
& $dis $raw -o $ir
if ($LASTEXITCODE) { throw "Disassemble failed: $raw" }
$clean = [Collections.Generic.List[string]]::new()
foreach ($line in [IO.File]::ReadLines($ir)) {
if ($line -match '@llvm.used|wchar_size|llvm.module.flags|__hip_cuid') { continue }
$line = $line -replace 'optnone','' -replace 'define hidden','define linkonce_odr'
$line = $line -replace '"target-cpu"="gfx1030"','' -replace '"target-features"="[^"]+"',''
$clean.Add($line)
}
[IO.File]::WriteAllLines($ir,$clean,[Text.UTF8Encoding]::new($false))
& $assembler $ir -o $output
if ($LASTEXITCODE) { throw "Assemble failed: $ir" }
Write-Host "Built $output ($((Get-Item $output).Length) bytes)"
}
+45
View File
@@ -0,0 +1,45 @@
[CmdletBinding()]
param([string]$SourceRoot, [string]$BuildRoot, [int]$Jobs = 4)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/ZLUDA' }
if (!$BuildRoot) { $BuildRoot = Join-Path $repo 'build/zluda-llvm-windows-gnu' }
$toolchain = Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64'
$cmake = Join-Path $repo '.tools/python/cmake/data/bin/cmake.exe'
$ninja = Join-Path $repo '.tools/python/bin/ninja.exe'
if (!(Test-Path $ninja)) { $ninja = Join-Path $repo '.tools/python/ninja/data/bin/ninja.exe' }
if (!(Test-Path (Join-Path $SourceRoot 'ext/llvm-project/llvm/CMakeLists.txt'))) {
throw 'Run git submodule update --init --depth 1 ext/llvm-project in the ZLUDA checkout.'
}
New-Item -ItemType Directory -Force $BuildRoot | Out-Null
& (Join-Path $PSScriptRoot 'prepare-zluda-llvm-source.ps1') -LlvmSourceRoot (Join-Path $SourceRoot 'ext/llvm-project')
$oldPath = $env:PATH
try {
$env:PATH = "$(Join-Path $toolchain 'bin');$oldPath"
$arguments = @('-S', (Join-Path $SourceRoot 'ext/llvm-project/llvm'), '-B', $BuildRoot,
'-G', 'Ninja', "-DCMAKE_MAKE_PROGRAM=$ninja", '-DCMAKE_BUILD_TYPE=Release',
"-DCMAKE_C_COMPILER=$(Join-Path $toolchain 'bin/x86_64-w64-mingw32-clang.exe')",
"-DCMAKE_CXX_COMPILER=$(Join-Path $toolchain 'bin/x86_64-w64-mingw32-clang++.exe')",
'-DLLVM_TARGETS_TO_BUILD=AMDGPU', '-DLLVM_ENABLE_PROJECTS=llvm;lld',
'-DLLVM_ENABLE_WARNINGS=OFF', '-DLLVM_ENABLE_TERMINFO=OFF', '-DLLVM_ENABLE_LIBXML2=OFF',
'-DLLVM_ENABLE_LIBEDIT=OFF', '-DLLVM_ENABLE_LIBPFM=OFF', '-DLLVM_ENABLE_ZLIB=OFF',
'-DLLVM_ENABLE_ZSTD=OFF', '-DLLVM_INCLUDE_BENCHMARKS=OFF', '-DLLVM_INCLUDE_EXAMPLES=OFF',
'-DLLVM_INCLUDE_TESTS=OFF', '-DLLVM_BUILD_TESTS=OFF', '-DLLVM_BUILD_TOOLS=OFF',
'-DLLVM_OPTIMIZED_TABLEGEN=ON', '-DLLVM_PARALLEL_LINK_JOBS=1')
$ErrorActionPreference = 'Continue'
& $cmake @arguments 2>&1 | Tee-Object (Join-Path $BuildRoot 'configure.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "LLVM configure failed ($LASTEXITCODE)" }
$ErrorActionPreference = 'Continue'
& $cmake --build $BuildRoot --parallel $Jobs --target llvm-config llvm-libraries lldCommon lldELF `
2>&1 | Tee-Object (Join-Path $BuildRoot 'build.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "LLVM build failed ($LASTEXITCODE)" }
& (Join-Path $BuildRoot 'bin/llvm-config.exe') --version
if ($LASTEXITCODE) { throw 'llvm-config verification failed' }
@{sourceBase=(& git -C (Join-Path $SourceRoot 'ext/llvm-project') rev-parse HEAD).Trim(); fullSourceDeltaVerified=$true;
sourcePatches=@(Get-ChildItem (Join-Path $repo 'patches/zluda-llvm') -Filter *.patch | ForEach-Object {
@{name=$_.Name; sha256=(Get-FileHash -LiteralPath $_.FullName).Hash}})} |
ConvertTo-Json -Depth 5 | Set-Content (Join-Path $BuildRoot 'd4r-llvm-build-info.json') -Encoding UTF8
Write-Host "Native Windows LLVM: $BuildRoot"
} finally { $env:PATH = $oldPath }
+96
View File
@@ -0,0 +1,96 @@
[CmdletBinding()]
param([string]$SourceRoot, [string]$LlvmBuildRoot, [string]$InstallRoot, [switch]$FetchOnly, [switch]$CacheTestsOnly, [switch]$CompilerTestsOnly, [int]$Jobs = 4)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/ZLUDA' }
if (!$LlvmBuildRoot) { $LlvmBuildRoot = Join-Path $repo 'build/zluda-llvm-windows-gnu' }
if (!$InstallRoot) { $InstallRoot = Join-Path $repo 'dist/zluda-windows-final' }
$rust = Join-Path $repo '.tools/rust-1.98.1-gnu'
$toolchain = Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64'
$target = Join-Path $repo 'build/zluda-rust-windows-gnu'
New-Item -ItemType Directory -Force $target,$InstallRoot | Out-Null
$settings = @{
PATH="$(Join-Path $rust 'bin');$(Join-Path $toolchain 'bin');$(Join-Path $repo '.tools/python/cmake/data/bin');$(Join-Path $repo '.tools/python/bin');C:\Program Files\Git\usr\bin;$env:PATH"
CARGO_HOME=(Join-Path $repo '.tools/cargo-home')
CARGO_TARGET_DIR=$target
CARGO_BUILD_JOBS="$Jobs"
RUSTC=(Join-Path $rust 'bin/rustc.exe')
CC=(Join-Path $toolchain 'bin/x86_64-w64-mingw32-clang.exe')
CXX=(Join-Path $toolchain 'bin/x86_64-w64-mingw32-clang++.exe')
AR=(Join-Path $toolchain 'bin/llvm-ar.exe')
CXXSTDLIB='c++'
LIBRARY_PATH=(Join-Path $rust 'lib/rustlib/x86_64-pc-windows-gnu/lib/self-contained')
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER=(Join-Path $toolchain 'bin/x86_64-w64-mingw32-clang.exe')
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS='-C link-arg=-static'
ZLUDA_LLVM_BUILD_DIR=$LlvmBuildRoot
}
$previous = @{}
foreach ($name in $settings.Keys) {
$previous[$name] = [Environment]::GetEnvironmentVariable($name,'Process')
[Environment]::SetEnvironmentVariable($name,$settings[$name],'Process')
}
Push-Location $SourceRoot
try {
$cargo = Join-Path $rust 'bin/cargo.exe'
if (!(Test-Path $cargo)) { throw 'Run setup-rust-toolchain.ps1 first.' }
if ($CompilerTestsOnly) {
$ErrorActionPreference = 'Continue'
& $cargo test --locked --release --target x86_64-pc-windows-gnu -p llvm_zluda shader_mode_tests `
2>&1 | Tee-Object (Join-Path $target 'compiler-tests.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "ZLUDA compiler regression tests failed ($LASTEXITCODE)" }
return
}
if ($CacheTestsOnly) {
$ErrorActionPreference = 'Continue'
& $cargo test --locked --release --target x86_64-pc-windows-gnu -p zluda_cache `
2>&1 | Tee-Object (Join-Path $target 'cache-tests.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "ZLUDA cache regression tests failed ($LASTEXITCODE)" }
return
}
if ($FetchOnly) {
$ErrorActionPreference = 'Continue'
& $cargo fetch --locked --target x86_64-pc-windows-gnu 2>&1 | Tee-Object (Join-Path $target 'fetch.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "Cargo fetch failed ($LASTEXITCODE)" }
return
}
if (!(Test-Path (Join-Path $LlvmBuildRoot 'bin/llvm-config.exe'))) { throw 'Run build-zluda-llvm.ps1 first.' }
foreach ($variant in @('','_constrained','_w64','_constrained_w64')) {
if (!(Test-Path "ptx/lib/zluda_ptx_impl$variant.bc")) { throw 'Run build-zluda-helpers.ps1 first.' }
}
$ErrorActionPreference = 'Continue'
& $cargo build --locked --release --target x86_64-pc-windows-gnu -p zluda -p nvapi -p zluda_trace `
2>&1 | Tee-Object (Join-Path $target 'build.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "ZLUDA build failed ($LASTEXITCODE)" }
$ErrorActionPreference = 'Continue'
& $cargo build --locked --release --target x86_64-pc-windows-gnu -p ptx --example d4r_emit `
2>&1 | Tee-Object (Join-Path $target 'emit-build.log')
$ErrorActionPreference = 'Stop'
if ($LASTEXITCODE) { throw "d4r_emit build failed ($LASTEXITCODE)" }
$release = Join-Path $target 'x86_64-pc-windows-gnu/release'
Copy-Item -LiteralPath (Join-Path $release 'nvcuda.dll') -Destination $InstallRoot -Force
Copy-Item -LiteralPath (Join-Path $release 'nvapi64.dll') -Destination $InstallRoot -Force
# The C++ dependencies select libc++ dynamically even when Rust requests
# static GNU support libraries. Keep these portable runtime DLLs local.
foreach ($runtime in @('libc++.dll', 'libunwind.dll')) {
Copy-Item -LiteralPath (Join-Path $toolchain "bin/$runtime") -Destination $InstallRoot -Force
}
New-Item -ItemType Directory -Force (Join-Path $InstallRoot 'trace') | Out-Null
Copy-Item -LiteralPath (Join-Path $release 'zluda_trace.dll') -Destination (Join-Path $InstallRoot 'trace/nvcuda.dll') -Force
Copy-Item -LiteralPath (Join-Path $release 'examples/d4r_emit.exe') -Destination $InstallRoot -Force
@{base='ee2f25a180099fa42f36b2346732e1f2470a03ad'; target='x86_64-pc-windows-gnu';
sourceCommit=(& git rev-parse HEAD); workingTreeDirty=[bool](& git status --porcelain);
rust='1.98.1'; llvm=(& (Join-Path $LlvmBuildRoot 'bin/llvm-config.exe') --version);
llvmSource=$(if (Test-Path (Join-Path $LlvmBuildRoot 'd4r-llvm-build-info.json')) {
Get-Content (Join-Path $LlvmBuildRoot 'd4r-llvm-build-info.json') -Raw | ConvertFrom-Json
} else { $null });
files=@(Get-ChildItem -LiteralPath $InstallRoot -Filter '*.dll' | Get-FileHash -Algorithm SHA256)} |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $InstallRoot 'build-info.json') -Encoding UTF8
Write-Host "Native Windows d4r ZLUDA runtime: $InstallRoot"
} finally {
Pop-Location
foreach ($name in $previous.Keys) { [Environment]::SetEnvironmentVariable($name,$previous[$name],'Process') }
}
+58
View File
@@ -0,0 +1,58 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][int]$GameProcessId, [Parameter(Mandatory=$true)][string]$OutputPath)
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing
if (!('D4RWindowCapture' -as [type])) {
Add-Type @'
using System;
using System.Runtime.InteropServices;
using System.Text;
public static class D4RWindowCapture {
public delegate bool Callback(IntPtr window, IntPtr data);
[StructLayout(LayoutKind.Sequential)] public struct Rect { public int Left, Top, Right, Bottom; }
[DllImport("user32.dll")] public static extern bool EnumWindows(Callback callback, IntPtr data);
[DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr window, out uint process);
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr window, out Rect rect);
[DllImport("user32.dll",CharSet=CharSet.Unicode)] public static extern int GetWindowText(IntPtr window, StringBuilder text, int count);
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr window);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] public static extern IntPtr SetThreadDpiAwarenessContext(IntPtr context);
}
'@
}
$windows = [Collections.Generic.List[object]]::new()
$previousDpi=[D4RWindowCapture]::SetThreadDpiAwarenessContext([IntPtr](-4))
try {
$callback = [D4RWindowCapture+Callback]{ param($window,$data)
[uint32]$owner = 0
[void][D4RWindowCapture]::GetWindowThreadProcessId($window,[ref]$owner)
if ($owner -eq $GameProcessId) {
$rect = [D4RWindowCapture+Rect]::new()
[void][D4RWindowCapture]::GetWindowRect($window,[ref]$rect)
$title = [Text.StringBuilder]::new(512)
[void][D4RWindowCapture]::GetWindowText($window,$title,512)
$windows.Add([pscustomobject]@{handle=$window; title=$title.ToString(); visible=[D4RWindowCapture]::IsWindowVisible($window); rect=$rect;
area=($rect.Right-$rect.Left)*($rect.Bottom-$rect.Top)})
}
return $true
}
[void][D4RWindowCapture]::EnumWindows($callback,[IntPtr]::Zero)
$windows | Select-Object handle,title,visible,area | Format-Table
$chosen = $windows | Where-Object { $_.visible -and $_.area -gt 4096 } | Sort-Object area -Descending | Select-Object -First 1
if (!$chosen) { throw "No visible game window for PID $GameProcessId" }
if ([D4RWindowCapture]::GetForegroundWindow() -ne $chosen.handle) {
throw 'Game window is not foreground; capture refused to avoid including unrelated overlapping windows.'
}
$rect = $chosen.rect
$bitmap = [Drawing.Bitmap]::new($rect.Right-$rect.Left,$rect.Bottom-$rect.Top)
$graphics = [Drawing.Graphics]::FromImage($bitmap)
try {
$graphics.CopyFromScreen($rect.Left,$rect.Top,0,0,$bitmap.Size)
$bitmap.Save([IO.Path]::GetFullPath($OutputPath),[Drawing.Imaging.ImageFormat]::Png)
} finally {
$graphics.Dispose(); $bitmap.Dispose()
}
Write-Host "Captured game window: $OutputPath"
} finally {
if ($previousDpi -ne [IntPtr]::Zero) { [void][D4RWindowCapture]::SetThreadDpiAwarenessContext($previousDpi) }
}
+25
View File
@@ -0,0 +1,25 @@
[CmdletBinding()]
param([string]$SourceRoot)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/ZLUDA' }
$base = 'ee2f25a180099fa42f36b2346732e1f2470a03ad'
$relative = 'build/zluda-patch-check-' + [Guid]::NewGuid().ToString('N')
$snapshot = Join-Path $repo $relative
New-Item -ItemType Directory -Force $snapshot | Out-Null
$archive = "$snapshot.tar"
& git -C $SourceRoot archive --format=tar "--output=$archive" $base
if ($LASTEXITCODE) { throw 'Could not archive the pinned ZLUDA base.' }
& tar.exe -xf $archive -C $snapshot
if ($LASTEXITCODE) { throw 'Could not extract the ZLUDA patch-check snapshot.' }
Push-Location $repo
try {
foreach ($patch in (Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda') -Filter '*.patch' | Sort-Object Name)) {
& git apply "--directory=$relative" --check $patch.FullName
if ($LASTEXITCODE) { throw "Fresh-source patch check failed: $($patch.Name)" }
& git apply "--directory=$relative" --whitespace=nowarn $patch.FullName
if ($LASTEXITCODE) { throw "Fresh-source patch apply failed: $($patch.Name)" }
Write-Host "PASS patch $($patch.Name)"
}
Write-Host "Pinned-source patch snapshot: $snapshot"
} finally { Pop-Location }
+271
View File
@@ -0,0 +1,271 @@
# Checks a d4r install on Windows. It only reads files and prints what it finds.
# Run it from the game folder (the one holding the game's .exe and d4r\), or give that folder:
# powershell -ExecutionPolicy Bypass -File d4r\d4r-check.ps1 [GAME_FOLDER]
# Add -Report to also write one ZIP (logs, this output, GPU and driver) to send with a bug report.
[CmdletBinding()]
param(
[string]$GameFolder,
[switch]$Report,
[string]$InventoryFile, # tests: a gpu-inventory.json to use instead of running the GPU query
[string]$ReportDirectory # tests: where -Report writes its ZIP (default: your Desktop)
)
$ErrorActionPreference = 'Stop'
if (!$GameFolder) {
$GameFolder = if ((Split-Path $PSScriptRoot -Leaf) -eq 'd4r') { Split-Path $PSScriptRoot -Parent } else { (Get-Location).Path }
}
$game = [IO.Path]::GetFullPath($GameFolder).TrimEnd('\')
$d4r = Join-Path $game 'd4r'
$problems = 0
$lines = [Collections.Generic.List[string]]::new()
function Say([string]$text) { $lines.Add($text); Write-Host $text }
function Ok([string]$text) { Say (' ok ' + $text) }
function Bad([string]$text) { Say (' MISSING ' + $text); $script:problems++ }
function Note([string]$text) { Say (' note ' + $text) }
function Hash([string]$path) { (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash }
function Version([string]$path) {
try { $v = (Get-Item -LiteralPath $path).VersionInfo; if ($v.FileVersion) { return ($v.FileVersion -replace ',\s*', '.') } } catch {}
return 'unknown'
}
function Read-TextFile([string]$path) { [IO.File]::ReadAllText($path) }
Say "d4r install in $game"
if (!(Test-Path -LiteralPath $d4r -PathType Container)) {
Say 'no d4r folder here; run this from the folder with the game .exe (extract the d4r ZIP there first)'
exit 1
}
if (@(Get-ChildItem -LiteralPath $game -Filter '*.exe' -File -ErrorAction SilentlyContinue).Count) { Ok 'game executable next to d4r\' }
else { Note 'no .exe next to d4r\ (the d4r files must sit in the folder of the game''s main .exe; for Unreal Engine games that is <game>\<Project>\Binaries\Win64)' }
# --- the install's own file list ---------------------------------------------------------------
$manifest = $null
$manifestPath = Join-Path $d4r 'package.json'
if (Test-Path -LiteralPath $manifestPath) {
try { $manifest = Get-Content -LiteralPath $manifestPath -Raw | ConvertFrom-Json } catch { $manifest = $null }
}
if (!$manifest) { Bad 'd4r\package.json is missing or damaged (extract the d4r ZIP again)' }
# --- files --------------------------------------------------------------------------------------
$required = @('dxgi.dll', 'OptiScaler.ini', 'd4r\_nvngx.dll', 'd4r\d4r.ini', 'd4r\dll-pins.txt',
'd4r\hip\bin\amdhip64_7.dll', 'd4r\zluda\nvcuda.dll', 'd4r\zluda\nvapi64.dll', 'd4r\nvapi\backend\nvapi64.dll')
foreach ($file in $required) {
if (Test-Path -LiteralPath (Join-Path $game $file) -PathType Leaf) { Ok $file }
else { Bad "$file (extract the d4r ZIP again over the game folder)" }
}
if ($manifest) {
$edited = @('OptiScaler.ini', 'd4r/d4r.ini') # players are meant to edit these
$damaged = 0
foreach ($entry in $manifest.files) {
$path = Join-Path $game ($entry.path -replace '/', '\')
if (!(Test-Path -LiteralPath $path -PathType Leaf)) {
if ($required -notcontains ($entry.path -replace '/', '\')) { Bad "$($entry.path) (extract the d4r ZIP again)" }
continue
}
if ((Hash $path) -ne $entry.sha256) {
if ($entry.path -eq 'dxgi.dll') { Note 'dxgi.dll is not the one that came with d4r (another OptiScaler or ReShade?). Move it away and extract the d4r ZIP again' }
elseif ($edited -contains $entry.path) { Note "$($entry.path) has been edited (fine if you did it)" }
else { Bad "$($entry.path) differs from the release (damaged or replaced; extract the d4r ZIP again)"; $damaged++ }
}
}
if (!$damaged) { Ok 'every other d4r file matches the release' }
}
# --- OptiScaler.ini ---------------------------------------------------------------------------
$optiIni = Join-Path $game 'OptiScaler.ini'
if (Test-Path -LiteralPath $optiIni) {
$text = Read-TextFile $optiIni
if ($text -notmatch '(?im)^\s*AllowExternalBackend\s*=\s*true') { Bad 'OptiScaler.ini: [DLSS] AllowExternalBackend must be true (this is not the d4r OptiScaler.ini)' }
if ($text -notmatch '(?im)^\s*Dx12Upscaler\s*=\s*dlss') { Note 'OptiScaler.ini: [Upscalers] Dx12Upscaler is not dlss; the game will not use d4r' }
$m = [regex]::Match($text, '(?im)^\s*NvngxPath\s*=\s*(\S+)')
if (!$m.Success) { Bad 'OptiScaler.ini: [Libraries] NvngxPath is missing (it must name the d4r folder)' }
else {
$folder = $m.Groups[1].Value
$resolved = if ([IO.Path]::IsPathRooted($folder)) { $folder } else { Join-Path $game $folder }
if (Test-Path -LiteralPath (Join-Path $resolved '_nvngx.dll')) { Ok "OptiScaler.ini NvngxPath = $folder" }
else { Bad "OptiScaler.ini NvngxPath = $folder does not hold _nvngx.dll (use NvngxPath=d4r, or the full path of the d4r folder)" }
}
}
# --- NVIDIA DLLs (never shipped; the exact versions come from dll-pins.txt) -----------------------
$pins = @()
$pinsPath = Join-Path $d4r 'dll-pins.txt'
if (Test-Path -LiteralPath $pinsPath) {
foreach ($line in Get-Content -LiteralPath $pinsPath) {
$line = $line.Trim()
if (!$line -or $line.StartsWith('#')) { continue }
$f = $line -split '\s+'
if ($f.Count -ge 4 -and $f[1].Length -eq 64) { $pins += [pscustomobject]@{ kind = $f[0]; sha = $f[1].ToUpperInvariant(); version = $f[2]; status = $f[3] } }
}
}
function Check-Nvidia([string]$kind, [string]$relative, [string]$label, [string]$source) {
$path = Join-Path $game $relative
$wanted = @($pins | Where-Object { $_.kind -eq $kind } | ForEach-Object { $_.version }) -join ' or '
if (!$wanted) { Note "$label cannot be checked (d4r\dll-pins.txt is missing or damaged)"; return }
if (!(Test-Path -LiteralPath $path -PathType Leaf)) { Bad "${relative}: copy NVIDIA's $label here (version $wanted; $source)"; return }
$hash = Hash $path
$pin = @($pins | Where-Object { $_.kind -eq $kind -and $_.sha -eq $hash }) | Select-Object -First 1
if (!$pin) { Bad "$relative is version $(Version $path), which d4r does not accept. d4r on Windows needs exactly $wanted ($source)"; return }
if ($pin.status -eq 'validated') { Ok "$relative ($label $($pin.version), tested on Windows)" }
else { Ok "$relative ($label $($pin.version))"; Note "$label $($pin.version) is accepted but has had less Windows testing" }
}
Check-Nvidia 'dlss' 'd4r\dlss\nvngx_dlss.dll' 'nvngx_dlss.dll' 'many games ship one in their folder; see WINDOWS_README.txt'
Check-Nvidia 'ngx' 'd4r\ngx\_nvngx.dll' '_nvngx.dll' 'it is part of NVIDIA''s display driver package; see WINDOWS_README.txt'
# --- GPU and the build for it --------------------------------------------------------------------
$registryPath = Join-Path $d4r 'gpu-targets.json'
$registry = @()
if (Test-Path -LiteralPath $registryPath) { $registry = @((Get-Content -LiteralPath $registryPath -Raw | ConvertFrom-Json).targets) }
$inventory = $null
if ($InventoryFile) { $inventory = Get-Content -LiteralPath $InventoryFile -Raw | ConvertFrom-Json }
elseif (Test-Path -LiteralPath (Join-Path $d4r 'd4r_gpu_inventory.exe')) {
$work = Join-Path ([IO.Path]::GetTempPath()) ('d4r-check-' + [Guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $work | Out-Null
try {
$info = New-Object Diagnostics.ProcessStartInfo
$info.FileName = Join-Path $d4r 'd4r_gpu_inventory.exe'
$info.Arguments = '--hip-root "' + (Join-Path $d4r 'hip') + '" --output-dir "' + $work + '"'
$info.UseShellExecute = $false; $info.CreateNoWindow = $true
$info.RedirectStandardOutput = $true; $info.RedirectStandardError = $true
$info.EnvironmentVariables['D4R_DIAG_DIR'] = $work
$process = New-Object Diagnostics.Process; $process.StartInfo = $info
[void]$process.Start()
$null = $process.StandardOutput.ReadToEndAsync(); $null = $process.StandardError.ReadToEndAsync()
if (!$process.WaitForExit(30000)) { $process.Kill(); $process.WaitForExit() }
if (Test-Path -LiteralPath (Join-Path $work 'gpu-inventory.json')) { $inventory = Get-Content -LiteralPath (Join-Path $work 'gpu-inventory.json') -Raw | ConvertFrom-Json }
} catch {} finally {
$process.Dispose()
Get-ChildItem -LiteralPath $work -File -ErrorAction SilentlyContinue | ForEach-Object { Remove-Item -LiteralPath $_.FullName }
Remove-Item -LiteralPath $work -ErrorAction SilentlyContinue
}
}
$arch = $null
if (!$inventory) { Note 'could not ask the AMD runtime about your GPU (d4r_gpu_inventory.exe is missing, or the AMD graphics driver is not installed or is too old)' }
else {
$supported = @($registry | ForEach-Object { $_.architecture })
$devices = @($inventory.devices | Where-Object { $_.wavefrontSize -eq 32 -and ($supported -contains $_.architecture -or !$supported.Count) })
if (!$devices.Count) {
$seen = @($inventory.devices | ForEach-Object { "$($_.name) ($($_.architecture))" }) -join ', '
Bad ("no supported RDNA3/RDNA4 GPU found by the AMD runtime. It sees: " + $(if ($seen) { $seen } else { 'nothing' }) + '. Update the AMD Adrenalin driver; RDNA2 and older are not supported')
} else {
foreach ($device in $devices) {
$a = $device.architecture
$missing = @()
foreach ($rel in @("d4r\_nvngx_$a.dll", "d4r\pixel_convert_$a.hsaco", "d4r\nvapi\$a\nvapi64.dll", "d4r\native\$a\d4r-kernels.txt")) {
if (!(Test-Path -LiteralPath (Join-Path $game $rel))) { $missing += $rel }
}
$native = @(Get-ChildItem -LiteralPath (Join-Path $d4r "native\$a") -Filter '*.hsaco' -ErrorAction SilentlyContinue).Count
if ($missing.Count) { Bad "GPU $($device.name) ($a): this release has no complete build for it (missing: $($missing -join ', '))" }
else {
Ok "GPU $($device.name) ($a): build present, $native native kernels"
if (!$arch) { $arch = $a }
}
if ($a -ne 'gfx1201') { Note "only the RX 9070 XT (gfx1201) has been tested on real hardware; $a is compile-tested" }
}
}
if (@($inventory.devices | Where-Object { $_.wavefrontSize -eq 32 }).Count -gt 1) { Note 'several GPUs found; d4r uses the one the game renders on' }
}
if ($arch -and $registry.Count) {
$info = @($registry | Where-Object { $_.architecture -eq $arch }) | Select-Object -First 1
$bad = 0
$objects = @(Get-Item -LiteralPath (Join-Path $d4r "pixel_convert_$arch.hsaco") -ErrorAction SilentlyContinue) +
@(Get-ChildItem -LiteralPath (Join-Path $d4r "native\$arch") -Filter '*.hsaco' -ErrorAction SilentlyContinue)
foreach ($object in $objects) {
$stream = [IO.File]::OpenRead($object.FullName)
try { $header = New-Object byte[] 64; [void]$stream.Read($header, 0, 64) } finally { $stream.Dispose() }
if ($header[0] -ne 127 -or $header[1] -ne 69 -or $header[2] -ne 76 -or $header[3] -ne 70 -or $header[48] -ne $info.elfMachine) {
Bad "$($object.Name) is not built for $arch (do not rename or mix files from other GPUs; extract the d4r ZIP again)"; $bad++
}
}
if ($objects.Count -and !$bad) { Ok "all $($objects.Count) GPU code objects are built for $arch" }
}
# --- Linux / Wine leftovers ------------------------------------------------------------------------
$proxyFound = $false
foreach ($name in @('d3d12.dll', 'd3d12core.dll')) {
$proxy = Join-Path $game $name
if (Test-Path -LiteralPath $proxy -PathType Leaf) {
$item = Get-Item -LiteralPath $proxy
if ($item.Length -le 64MB -and [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($proxy)) -match '(?i)vkd3d|wined3d') {
Bad "$name in the game folder is vkd3d-proton/Wine (left over from a Linux install?). Move it out; d4r on Windows uses native D3D12"
$proxyFound = $true
}
}
}
if (!$proxyFound) { Ok 'no vkd3d/Wine d3d12.dll in the game folder' }
# --- d4r.ini ---------------------------------------------------------------------------------------
$iniPath = Join-Path $d4r 'd4r.ini'
$model = 'K'
if (Test-Path -LiteralPath $iniPath) {
$section = ''; $iniProblems = 0
$known = @{ 'dlss.model' = 1; 'dlss.showwatermark' = 1; 'interop.asyncinterop' = 1; 'debug.validateoutput' = 1; 'debug.log' = 1; 'paths.cachedir' = 1; 'kernels.nativefp8' = 1 }
$boolean = @('dlss.showwatermark', 'interop.asyncinterop', 'debug.validateoutput', 'kernels.nativefp8')
foreach ($raw in (Read-TextFile $iniPath).TrimStart([char]0xFEFF) -split "`n") {
$line = $raw.Trim()
if (!$line -or $line.StartsWith(';') -or $line.StartsWith('#')) { continue }
if ($line.StartsWith('[')) { $section = $line.Trim('[', ']').Trim(); continue }
$eq = $line.IndexOf('='); if ($eq -lt 0) { continue }
$key = $line.Substring(0, $eq).Trim()
$value = ($line.Substring($eq + 1) -replace '\s[;#].*$', '').Trim()
$name = ("$section.$key").ToLowerInvariant()
$v = $value.ToLowerInvariant()
if (!$known.ContainsKey($name)) { Note "d4r.ini: [$section] $key is not a Windows setting; ignored"; $iniProblems++ }
elseif ($name -eq 'dlss.model') {
if (@('', 'auto', 'k', 'dlss4', '11') -contains $v) { $model = 'K' }
elseif (@('m', 'dlss4.5', '13') -contains $v) { $model = 'M' }
else { Note "d4r.ini: [DLSS] Model '$value' is not available on Windows (use K or M); K will be used"; $iniProblems++ }
}
elseif ($boolean -contains $name) {
if (@('', 'auto', '1', 'true', 'yes', 'on', '0', 'false', 'no', 'off') -notcontains $v) { Note "d4r.ini: [$section] $key must be true or false, not '$value'; the default will be used"; $iniProblems++ }
}
elseif ($name -eq 'debug.log' -and @('', 'auto', 'normal', 'verbose') -notcontains $v) { Note "d4r.ini: [Debug] Log must be normal or verbose, not '$value'; normal will be used"; $iniProblems++ }
}
if (!$iniProblems) { Ok "d4r.ini is valid (model $model)" }
}
# --- what the last game start said -----------------------------------------------------------------
$log = Join-Path $d4r 'd4r_nvngx.log'
if (Test-Path -LiteralPath $log) {
$messages = @(Get-Content -LiteralPath $log | Where-Object { $_ -match '^d4r: ' })
$failed = @($messages | Where-Object { $_ -match 'DLSS disabled' })
if ($failed.Count) { foreach ($m in $failed | Select-Object -First 3) { Bad ('last game start: ' + $m.Substring(5)) } }
elseif ($messages.Count) { Ok ('last game start: ' + $messages[0].Substring(5)) }
else { Note 'd4r\d4r_nvngx.log has no d4r summary line yet (the game may not have chosen DLSS)' }
foreach ($m in $messages | Where-Object { $_ -notmatch 'DLSS disabled|player mode' } | Select-Object -First 5) { Note ('last game start: ' + $m.Substring(5)) }
} else { Note 'no d4r\d4r_nvngx.log yet: start the game once and choose DLSS (or FSR/XeSS) in its graphics settings' }
if (Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Path -and $_.Path.StartsWith($game + '\', [StringComparison]::OrdinalIgnoreCase) -and $_.ProcessName -notmatch '^(powershell|pwsh)$' }) {
Note 'the game is running; its log is rewritten at every start'
}
Say ''
if ($problems -eq 0) { Say 'Everything d4r needs is in place.' } else { Say "$problems thing(s) to fix above." }
# --- bug-report ZIP ------------------------------------------------------------------------------
if ($Report) {
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$destination = if ($ReportDirectory) { $ReportDirectory } else { [Environment]::GetFolderPath('Desktop') }
$staging = Join-Path ([IO.Path]::GetTempPath()) ("d4r-report-$stamp")
New-Item -ItemType Directory -Force -Path $staging | Out-Null
try {
$lines | Set-Content -LiteralPath (Join-Path $staging 'check.txt') -Encoding UTF8
foreach ($file in @('d4r\d4r_nvngx.log', 'd4r\d4r.ini', 'OptiScaler.ini', 'OptiScaler.log')) {
$source = Join-Path $game $file
if (Test-Path -LiteralPath $source) { Copy-Item -LiteralPath $source -Destination (Join-Path $staging (Split-Path $file -Leaf)) }
}
Get-ChildItem -LiteralPath $game -Filter 'OptiScaler*.log' -File | ForEach-Object { Copy-Item -LiteralPath $_.FullName -Destination $staging -Force }
try { Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion, DriverDate | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $staging 'driver.json') -Encoding UTF8 } catch {}
if ($inventory) { $inventory | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $staging 'gpu-inventory.json') -Encoding UTF8 }
Get-ChildItem -LiteralPath $game -Recurse -File -ErrorAction SilentlyContinue |
Where-Object { $_.FullName.StartsWith($d4r + '\') -or $_.Name -in @('dxgi.dll', 'OptiScaler.ini') } |
ForEach-Object { '{0} {1,12} {2}' -f (Hash $_.FullName), $_.Length, $_.FullName.Substring($game.Length + 1) } |
Set-Content -LiteralPath (Join-Path $staging 'files.sha256.txt') -Encoding UTF8
$zip = Join-Path $destination "d4r-report-$stamp.zip"
Compress-Archive -Path (Join-Path $staging '*') -DestinationPath $zip -Force
Write-Host ''
Write-Host "Bug report written: $zip" -ForegroundColor Cyan
Write-Host 'Also tell us: GPU, game, K or M, and what the image looked like. The logs can contain local folder names; look before posting publicly.'
} finally {
Get-ChildItem -LiteralPath $staging -File -ErrorAction SilentlyContinue | ForEach-Object { Remove-Item -LiteralPath $_.FullName }
Remove-Item -LiteralPath $staging -ErrorAction SilentlyContinue
}
}
if ($problems) { exit 1 }
+32
View File
@@ -0,0 +1,32 @@
# Parse completed diagnostic records. Empty streams are valid, including games
# that refuse a debugger before initializing the upscaler.
function Get-D4RGameSummary {
param([AllowEmptyString()][string]$Stdout='', [AllowEmptyString()][string]$Stderr='',
[AllowEmptyString()][string]$Debugger='', [int]$Preset=11, [double]$RunSeconds=0,
[bool]$ValidateOutput=$false, $GameCrash=$null)
$gameExit=[regex]::Match($Debugger, 'EXIT code=0x([0-9a-f]+)')
$exitCode=if ($gameExit.Success) { '0x'+$gameExit.Groups[1].Value } else { 'diagnostic_timeout' }
$frames=[regex]::Matches($Stdout, '(?m)^D4R_FRAME cpu_frame_copies=([0-9]+) frame_age=([0-9]+) interop_ngx_ms=([0-9.]+)\r?$')
$checks=[regex]::Matches($Stdout, '(?m)^D4R_OUTPUT_VALIDATION elements=([0-9]+) nan=([0-9]+) inf=([0-9]+) diagnostics_cpu_bytes=8\r?$')
$launches=[regex]::Matches($Stderr, '\[d4r-launch\] kernel="([^"]+)" backend=(native|translated)')
$kernels=@($launches | ForEach-Object { $_.Groups[1].Value+' '+$_.Groups[2].Value } | Group-Object | ForEach-Object {
$parts=$_.Name.Split(' '); @{kernel=$parts[0]; backend=$parts[1]; launches=$_.Count}
})
$capabilities=@([regex]::Matches($Stdout, '(?m)^D4R_CAPABILITIES available=(-?[0-9]+) feature_init=(0x[0-9a-f]+) needs_driver=(-?[0-9]+)\r?$') |
ForEach-Object { $_.Groups[2].Value } | Select-Object -Unique)
$session=if ($frames.Count) { 'completed-dlss-frames' }
elseif ($capabilities -contains '0xbad00004') { 'ngx-feature-not-found' }
elseif ($capabilities.Count -and $capabilities -ne '0x00000001') { 'ngx-capability-failure' }
elseif ($exitCode -eq '0x0') { 'process-exited-without-dlss-frames' }
elseif ($exitCode -eq 'diagnostic_timeout') { 'diagnostic-timeout-without-dlss-frames' }
else { 'process-failed-before-dlss-frames' }
return [ordered]@{exitCode=$exitCode; session=$session; featureInitResults=$capabilities;
runSeconds=$RunSeconds; preset=$Preset; gameCrash=$GameCrash;
nativeLaunches=([regex]::Matches($Stderr, '\[d4r-launch\].*backend=native')).Count;
completedFrames=$frames.Count; outputValidationRequested=$ValidateOutput;
outputGpuChecks=$checks.Count; kernels=$kernels;
nonfiniteOutputs=@($checks | Where-Object { $_.Groups[2].Value -ne '0' -or $_.Groups[3].Value -ne '0' }).Count;
previousFrameOutputs=@($frames | Where-Object { $_.Groups[2].Value -ne '0' }).Count;
cpuImageCopyFrames=@($frames | Where-Object { $_.Groups[1].Value -ne '0' }).Count;
failures=([regex]::Matches($Stderr, 'D4R_[A-Z0-9_]*FAILURE\b')).Count}
}
+58
View File
@@ -0,0 +1,58 @@
# Read-only inventory before touching game files. It allocates no GPU memory
# and executes no kernels; successful discovery is not hardware validation.
function Invoke-D4RGpuPreflight([string]$PackageRoot, [string]$GameDirectory, [string]$Target, [string]$OutputDirectory) {
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$result=[ordered]@{passed=$false; target=$Target; gpuWorkExecuted=$false; failure=$null}
try {
$proxy=Join-Path $GameDirectory 'd3d12.dll'
if (Test-Path -LiteralPath $proxy) {
$item=Get-Item -LiteralPath $proxy
$result.localD3D12=@{path=$proxy; sha256=(Get-FileHash -LiteralPath $proxy).Hash; product=$item.VersionInfo.ProductName}
# Identify known Vulkan/Wine proxies by their own strings. Do not
# load, remove or replace a third-party game DLL.
if ($item.Length -le 64MB -and [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($proxy)) -match '(?i)vkd3d|wined3d') {
throw 'Local d3d12.dll identifies as vkd3d/Wine. Restore the game native D3D12 installation before using this Windows backend.'
}
}
$info=[Diagnostics.ProcessStartInfo]::new()
$info.FileName=Join-Path $PackageRoot 'd4r/d4r_gpu_inventory.exe'
$hip=Join-Path $PackageRoot 'd4r/hip'
foreach ($value in @($hip,$OutputDirectory)) { if ($value.Contains('"')) { throw 'Unsupported quote in inventory path.' } }
$info.Arguments='--hip-root "' + $hip + '" --output-dir "' + $OutputDirectory + '"'
$info.UseShellExecute=$false; $info.CreateNoWindow=$true
$info.EnvironmentVariables['D4R_DIAG_DIR']=$OutputDirectory
$info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
$process=[Diagnostics.Process]::new(); $process.StartInfo=$info
try {
if (!$process.Start()) { throw 'Cannot start GPU inventory.' }
$stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
$timedOut=!$process.WaitForExit(30000)
if ($timedOut) { $process.Kill(); $process.WaitForExit() }
$stdout.GetAwaiter().GetResult() | Set-Content (Join-Path $OutputDirectory 'gpu-inventory.stdout.log') -Encoding UTF8
$stderr.GetAwaiter().GetResult() | Set-Content (Join-Path $OutputDirectory 'gpu-inventory.stderr.log') -Encoding UTF8
$result.exitCode=$process.ExitCode
$result.exceptionOrExitHex='0x{0:X8}' -f [BitConverter]::ToUInt32([BitConverter]::GetBytes([int]$process.ExitCode),0)
if ($timedOut) { $result.timedOut=$true; throw 'HIP inventory timed out after 30 seconds.' }
if ($process.ExitCode) { throw "HIP inventory failed (exit $($process.ExitCode))." }
} finally { $process.Dispose() }
$inventory=Get-Content (Join-Path $OutputDirectory 'gpu-inventory.json') -Raw | ConvertFrom-Json
$result.inventory=$inventory
if ($inventory.compiledTarget -ne $Target) { throw "Inventory executable targets $($inventory.compiledTarget); package requires $Target." }
$matching=@($inventory.devices | Where-Object { $_.architecture -eq $Target -and $_.wavefrontSize -eq 32 })
if (!$matching.Count) {
$actual=@($inventory.devices | ForEach-Object { "$($_.architecture) ($($_.name))" }) -join ', '
throw "GPU target mismatch: detected $actual; package requires $Target. Use the package for the actual HIP architecture; do not rename code objects."
}
$result.passed=$true
Write-Host "D4R_PREFLIGHT target=$Target devices=$($matching.Count) gpu_work_executed=0"
} catch {
$result.failure=$_.Exception.Message
$result | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $OutputDirectory 'preflight.json') -Encoding UTF8
try { Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion,DriverDate | ConvertTo-Json |
Set-Content (Join-Path $OutputDirectory 'driver.json') -Encoding UTF8 } catch {}
$bundle=$OutputDirectory+'.zip'
Compress-Archive -Path (Join-Path $OutputDirectory '*') -DestinationPath $bundle -Force
throw "$($result.failure) Diagnostic bundle: $bundle"
}
$result | ConvertTo-Json -Depth 8 | Set-Content (Join-Path $OutputDirectory 'preflight.json') -Encoding UTF8
}
+38
View File
@@ -0,0 +1,38 @@
# Shared by the build, diagnostics, staging and game package scripts.
function Get-D4RGpuTargets {
$registry=Join-Path $PSScriptRoot 'gpu-targets.json'
if (!(Test-Path -LiteralPath $registry)) { $registry=Join-Path $PSScriptRoot '../../tools/windows/gpu-targets.json' }
$data=Get-Content -LiteralPath $registry -Raw | ConvertFrom-Json
if ($data.schema -ne 1) { throw 'Unsupported GPU target registry schema.' }
return $data.targets
}
function Get-D4RGpuTargetInfo([string]$Target) {
$info=@(Get-D4RGpuTargets | Where-Object { $_.architecture -eq $Target })
if ($info.Count -ne 1) { throw "Unsupported GPU target: $Target" }
return $info[0]
}
function Get-D4RGpuTarget([string]$Root, [string]$Requested) {
$configured=$null
$targetFile=Join-Path $Root 'gpu-target.json'
if (Test-Path -LiteralPath $targetFile) {
$configured=(Get-Content -LiteralPath $targetFile -Raw | ConvertFrom-Json).architecture
[void](Get-D4RGpuTargetInfo $configured)
}
$target=if ($Requested) { $Requested } elseif ($configured) { $configured } else { 'gfx1201' }
[void](Get-D4RGpuTargetInfo $target)
if (!$configured -and $target -ne 'gfx1201') { throw "A $target build requires gpu-target.json; rebuild with -GpuArch $target." }
if ($configured -and $target -ne $configured) { throw "Requested $target differs from package target $configured" }
return $target
}
function Assert-D4RCodeObjectTarget([string]$Path, [string]$Target) {
$info=Get-D4RGpuTargetInfo $Target
$reader=[IO.BinaryReader]::new([IO.File]::OpenRead($Path))
try { $header=$reader.ReadBytes(64) } finally { $reader.Dispose() }
if ($header.Length -ne 64 -or $header[0] -ne 127 -or $header[1] -ne 69 -or $header[2] -ne 76 -or $header[3] -ne 70 -or
$header[4] -ne 2 -or $header[5] -ne 1 -or $header[18] -ne 224 -or $header[19] -ne 0) {
throw "Invalid AMDGPU ELF64 code object: $Path"
}
# LLVM AMDGPU e_flags machine IDs; inspect, never patch or spoof them.
$expected=$info.elfMachine
if ($header[48] -ne $expected) { throw "Code object does not target ${Target}: $Path (ELF machine=$($header[48]))" }
}
+205
View File
@@ -0,0 +1,205 @@
[CmdletBinding()]
param(
[string]$PackageRoot = $PSScriptRoot,
[string]$CacheRoot = (Join-Path $env:LOCALAPPDATA 'd4r/cache'),
[string]$BackupRoot = (Join-Path $env:LOCALAPPDATA 'd4r/backups'),
[switch]$Yes
)
$ErrorActionPreference = 'Stop'
$source = [IO.Path]::GetFullPath($PackageRoot)
$runtime = if (Test-Path -LiteralPath (Join-Path $source 'd4r/d4r.ini')) {
Join-Path $source 'd4r'
} elseif (Test-Path -LiteralPath (Join-Path $source 'd4r.ini')) {
$source
} else {
throw "No d4r runtime found under $source. Extract the Windows release first."
}
$runtime = [IO.Path]::GetFullPath($runtime)
$CacheRoot = [IO.Path]::GetFullPath($CacheRoot)
$BackupRoot = [IO.Path]::GetFullPath($BackupRoot)
$gameRoot = if ($runtime -eq $source) { Split-Path -Parent $source } else { $source }
$gameRoot = [IO.Path]::GetFullPath($gameRoot)
$backupRoot = Join-Path $BackupRoot ('dlss-install-' + [DateTime]::UtcNow.ToString('yyyyMMdd-HHmmss') + '-' + [Guid]::NewGuid().ToString('N'))
foreach ($path in @($CacheRoot, $BackupRoot)) {
if ($path.Equals($gameRoot, [StringComparison]::OrdinalIgnoreCase) -or
$path.StartsWith($gameRoot.TrimEnd('\') + '\', [StringComparison]::OrdinalIgnoreCase)) {
throw "Cache and backups must stay outside the game directory: $path"
}
}
$dlssUrl = 'https://raw.githubusercontent.com/NVIDIA/DLSS/374959484e79a640feaba44c93ac8cfb0a03f5b5/lib/Windows_x86_64/rel/nvngx_dlss.dll'
$dlssHash = '3975567b8943c53acce397f2b72380092f84f162d00b0d2c7d08a1025c563983'
$dlssdUrl = 'https://raw.githubusercontent.com/NVIDIA/DLSS/374959484e79a640feaba44c93ac8cfb0a03f5b5/lib/Windows_x86_64/rel/nvngx_dlssd.dll'
$dlssdHash = '4bc7ea5fcb2f32cf86bc2cb072e8d2860914a0be511cbdcb2fc206c1d9d83b80'
$driverUrl = 'https://us.download.nvidia.com/Windows/617.14/617.14-desktop-win10-win11-64bit-international-dch-whql.exe'
$driverHash = '63d3da5ed52547bf3fd86204bb9ea1455947b24e2aa2519f359126f9a6efe13f'
$ngxHash = '66767018c36b3bab46398dade3adf173daa3730fda75965689ea848c9bc4e79b'
$sevenZipUrl = 'https://github.com/ip7z/7zip/releases/download/26.04/7zr.exe'
$sevenZipHash = '256feca8e274e5da655e2a284fabafd9f554365eb164862089dacd4e8276d282'
function Get-Sha256([string]$Path) {
$sha = [Security.Cryptography.SHA256]::Create()
$stream = [IO.File]::OpenRead($Path)
try { return [BitConverter]::ToString($sha.ComputeHash($stream)).Replace('-', '').ToLowerInvariant() }
finally { $stream.Dispose(); $sha.Dispose() }
}
$pinPath = Join-Path $runtime 'dll-pins.txt'
if (!(Test-Path -LiteralPath $pinPath -PathType Leaf)) { throw "Missing $pinPath. Use a current d4r Windows release." }
$pins = Get-Content -LiteralPath $pinPath -Raw
foreach ($required in @(@{kind='dlss'; hash=$dlssHash}, @{kind='dlssd'; hash=$dlssdHash}, @{kind='ngx'; hash=$ngxHash})) {
if ($pins -notmatch ('(?im)^\s*' + [regex]::Escape($required.kind) + '\s+' + [regex]::Escape($required.hash) + '\s+\S+\s+\S+\s*$')) {
throw "This release does not recognize NVIDIA $($required.kind) hash $($required.hash). Update the d4r package first."
}
}
if (!$Yes) {
$answer = Read-Host 'Download DLSS 310.9.1, Ray Reconstruction 310.9.1, and NVIDIA NGX core from driver 617.14 (~945 MiB)? [Y/n]'
if ($answer -match '^(?i)n') { Write-Host 'No files changed.'; exit 0 }
}
$tempRoot = [IO.Path]::GetFullPath([IO.Path]::GetTempPath())
$work = Join-Path $tempRoot ('d4r-dlss-install-' + [Guid]::NewGuid().ToString('N'))
$work = [IO.Path]::GetFullPath($work)
if (!$work.StartsWith($tempRoot.TrimEnd('\') + '\', [StringComparison]::OrdinalIgnoreCase) -or
(Split-Path -Leaf $work) -notmatch '^d4r-dlss-install-[a-f0-9]{32}$') {
throw "Temporary work path escaped the expected temp folder: $work"
}
New-Item -ItemType Directory -Force -Path $work | Out-Null
$cacheNvidia = Join-Path $CacheRoot 'nvidia'
$cacheTools = Join-Path $CacheRoot 'tools'
New-Item -ItemType Directory -Force -Path $cacheNvidia,$cacheTools | Out-Null
function Get-VerifiedFile([string]$Name, [string]$Url, [string]$ExpectedHash, [string]$CacheDirectory, [string]$WorkDirectory) {
$cached = Join-Path $CacheDirectory $Name
if (Test-Path -LiteralPath $cached -PathType Leaf) {
$hash = Get-Sha256 $cached
if ($hash -eq $ExpectedHash) { return $cached }
$quarantine = "$cached.bad-$([DateTime]::UtcNow.ToString('yyyyMMdd-HHmmss'))"
Move-Item -LiteralPath $cached -Destination $quarantine
Write-Warning "Moved invalid cache file to $quarantine"
}
$download = Join-Path $WorkDirectory $Name
Write-Host "Downloading $Name from its pinned official source..."
Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $download
$hash = Get-Sha256 $download
if ($hash -ne $ExpectedHash) { throw "SHA256 mismatch for $Name; no runtime files changed." }
$staged = "$cached.tmp-$([Guid]::NewGuid().ToString('N'))"
Copy-Item -LiteralPath $download -Destination $staged
Move-Item -LiteralPath $staged -Destination $cached
return $cached
}
$changed = [Collections.Generic.List[object]]::new()
try {
$dlssCached = Get-VerifiedFile 'nvngx_dlss.dll' $dlssUrl $dlssHash $cacheNvidia $work
$dlssdCached = Get-VerifiedFile 'nvngx_dlssd.dll' $dlssdUrl $dlssdHash $cacheNvidia $work
$ngxCache = Join-Path $cacheNvidia '_nvngx.dll'
$validCoreCache = (Test-Path -LiteralPath $ngxCache -PathType Leaf) -and
(Get-Sha256 $ngxCache) -eq $ngxHash
if ($validCoreCache -and (Get-Item -LiteralPath $ngxCache).VersionInfo.FileVersion -ne '32.0.16.1714') {
$validCoreCache = $false
}
if (!$validCoreCache) {
if (Test-Path -LiteralPath $ngxCache -PathType Leaf) {
$bad = "$ngxCache.bad-$([DateTime]::UtcNow.ToString('yyyyMMdd-HHmmss'))"
Move-Item -LiteralPath $ngxCache -Destination $bad
Write-Warning "Moved invalid cache file to $bad"
}
$driverPath = Join-Path $work 'nvidia-driver-617.14.exe'
Write-Host 'Downloading NVIDIA driver 617.14 (~945 MiB); installer will not run.'
Invoke-WebRequest -UseBasicParsing -Uri $driverUrl -OutFile $driverPath
$driverActual = Get-Sha256 $driverPath
if ($driverActual -ne $driverHash) { throw 'NVIDIA driver archive SHA256 mismatch; no runtime files changed.' }
$sevenZip = Get-VerifiedFile '7zr-26.04.exe' $sevenZipUrl $sevenZipHash $cacheTools $work
$extract = Join-Path $work 'ngx'
New-Item -ItemType Directory -Force -Path $extract | Out-Null
& $sevenZip e -y "-o$extract" $driverPath 'Display.Driver/_nvngx.dll' | Out-Host
if ($LASTEXITCODE -ne 0) { throw "7-Zip extraction failed: exit=$LASTEXITCODE" }
$extractedNgx = Join-Path $extract '_nvngx.dll'
if (!(Test-Path -LiteralPath $extractedNgx -PathType Leaf)) { throw 'NVIDIA driver archive has no Display.Driver/_nvngx.dll.' }
$actual = Get-Sha256 $extractedNgx
if ($actual -ne $ngxHash) { throw "Extracted NGX core SHA256 mismatch: $actual" }
$version = (Get-Item -LiteralPath $extractedNgx).VersionInfo.FileVersion
if ($version -ne '32.0.16.1714') { throw "Unexpected NGX core version $version; expected 32.0.16.1714." }
$stagedNgx = "$ngxCache.tmp-$([Guid]::NewGuid().ToString('N'))"
Copy-Item -LiteralPath $extractedNgx -Destination $stagedNgx
Move-Item -LiteralPath $stagedNgx -Destination $ngxCache
}
$assets = @(
@{ source=$dlssCached; relative='dlss/nvngx_dlss.dll'; hash=$dlssHash },
@{ source=$dlssdCached; relative='rr/nvngx_dlssd.dll'; hash=$dlssdHash },
@{ source=$ngxCache; relative='ngx/_nvngx.dll'; hash=$ngxHash }
)
$originals = [Collections.Generic.List[object]]::new()
foreach ($asset in $assets) {
$destination = Join-Path $runtime $asset.relative
if (Test-Path -LiteralPath $destination -PathType Container) { throw "DLL destination is a directory: $destination" }
$present = Test-Path -LiteralPath $destination -PathType Leaf
$previousHash = if ($present) { Get-Sha256 $destination } else { $null }
if ($previousHash -eq $asset.hash) { continue }
$backup = $null
if ($present) {
$backup = Join-Path $backupRoot $asset.relative
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $backup) | Out-Null
Copy-Item -LiteralPath $destination -Destination $backup
$backupHash = Get-Sha256 $backup
if ($backupHash -ne $previousHash) { throw "Backup hash mismatch for $destination; no runtime files changed." }
}
$originals.Add(@{path=$destination; existed=$present; sha256=$previousHash; backup=$backup; installHash=$asset.hash})
}
if ($originals.Count) {
New-Item -ItemType Directory -Force -Path $backupRoot | Out-Null
$changed = $originals
@{ createdUtc=[DateTime]::UtcNow.ToString('o'); files=$originals } |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $backupRoot 'backup-manifest.json') -Encoding UTF8
foreach ($entry in $originals) {
$asset = $assets | Where-Object { (Join-Path $runtime $_.relative) -eq $entry.path } | Select-Object -First 1
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $entry.path) | Out-Null
$stillPresent = Test-Path -LiteralPath $entry.path -PathType Leaf
if ($entry.existed) {
if (!$stillPresent -or (Get-Sha256 $entry.path) -ne $entry.sha256) {
throw "Destination changed after backup; refusing to replace $($entry.path)"
}
} elseif (Test-Path -LiteralPath $entry.path) {
throw "Destination appeared after validation; refusing to replace $($entry.path)"
}
$staged = "$($entry.path).install-$([Guid]::NewGuid().ToString('N'))"
Copy-Item -LiteralPath $asset.source -Destination $staged
Move-Item -LiteralPath $staged -Destination $entry.path -Force
}
Write-Host "Backups and original hashes: $backupRoot"
} else {
Write-Host 'All three NVIDIA DLLs already match their pinned hashes.'
}
Write-Host 'Installed NVIDIA DLSS 310.9.1, Ray Reconstruction 310.9.1, and NGX 32.0.16.1714.'
Write-Host 'Files remain local under the applicable NVIDIA licenses; no binaries are bundled into d4r releases.'
Write-Host 'This installer does not build local K/M/L or Ray Reconstruction model data.'
} catch {
for ($i = $changed.Count - 1; $i -ge 0; $i--) {
$entry = $changed[$i]
if (!(Test-Path -LiteralPath $entry.path)) { continue }
if ($entry.existed -and $entry.backup) {
$currentHash = Get-Sha256 $entry.path
if ($currentHash -ne $entry.installHash -and $currentHash -ne $entry.sha256) {
Write-Warning "Rollback left a file changed by another process: $($entry.path)"
continue
}
$rollback = "$($entry.path).rollback-$([Guid]::NewGuid().ToString('N'))"
Copy-Item -LiteralPath $entry.backup -Destination $rollback
Move-Item -LiteralPath $rollback -Destination $entry.path -Force
} elseif ((Get-Sha256 $entry.path) -eq $entry.installHash) {
Remove-Item -LiteralPath $entry.path
}
}
throw
} finally {
$resolvedWork = [IO.Path]::GetFullPath($work)
if (!$resolvedWork.StartsWith($tempRoot.TrimEnd('\') + '\', [StringComparison]::OrdinalIgnoreCase) -or
(Split-Path -Leaf $resolvedWork) -notmatch '^d4r-dlss-install-[a-f0-9]{32}$') {
throw "Refusing to remove a path outside the installer temp folder: $resolvedWork"
}
Remove-Item -LiteralPath $resolvedWork -Recurse -Force -ErrorAction SilentlyContinue
}
+158
View File
@@ -0,0 +1,158 @@
[CmdletBinding()]
param(
[string]$PackageRoot, [string]$DiagnosticRoot, [string]$OptiScalerRoot,
[string]$ZludaRoot, [string]$HipRoot, [string]$KernelKRoot, [string]$KernelMRoot,
[string]$GpuArch,
[string]$ArchivePath
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$defaults = @{PackageRoot='dist/windows-rdna4-game'; DiagnosticRoot='dist/windows-rdna4-command-list';
OptiScalerRoot='dist/optiscaler-windows-d4r'; ZludaRoot='dist/zluda-windows-final';
HipRoot='.tools/therock-10.2.0a20260929/_rocm_sdk_core'}
foreach ($name in $defaults.Keys) {
if (!(Get-Variable -Name $name -ValueOnly)) { Set-Variable -Name $name -Value (Join-Path $repo $defaults[$name]) }
}
$GpuArch=Get-D4RGpuTarget $DiagnosticRoot $GpuArch
if ($GpuArch -ne 'gfx1201' -and !$PSBoundParameters.ContainsKey('PackageRoot')) { $PackageRoot += "-$GpuArch" }
if (!$KernelKRoot) { $KernelKRoot=Join-Path $repo "build/native-k-$GpuArch" }
if (!$KernelMRoot) { $KernelMRoot=Join-Path $repo "build/native-m-$GpuArch" }
foreach ($directory in @($KernelKRoot,$KernelMRoot)) {
$info=Join-Path $directory 'build-info.json'
if ((Test-Path -LiteralPath $info) -and (Get-Content -LiteralPath $info -Raw | ConvertFrom-Json).architecture -ne $GpuArch) {
throw "Native kernel directory does not target ${GpuArch}: $directory"
}
}
$PackageRoot = [IO.Path]::GetFullPath($PackageRoot)
if (Test-Path -LiteralPath (Join-Path $PackageRoot 'gpu-target.json')) {
[void](Get-D4RGpuTarget $PackageRoot $GpuArch)
}
$sourceCommit=(& git -C $repo rev-parse HEAD).Trim()
$sourceDirty=[bool](& git -C $repo status --porcelain)
if ($ArchivePath -and $sourceDirty) { throw 'Commit source changes before creating the distributable archive.' }
New-Item -ItemType Directory -Force $PackageRoot | Out-Null
$stagedFiles = [Collections.Generic.List[string]]::new()
function Stage([string]$source, [string]$relative) {
if (!(Test-Path -LiteralPath $source -PathType Leaf)) { throw "Required file missing: $source" }
if ($source.EndsWith('.hsaco')) { Assert-D4RCodeObjectTarget $source $GpuArch }
$destination = Join-Path $PackageRoot $relative
New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null
Copy-Item -LiteralPath $source -Destination $destination -Force
$stagedFiles.Add($relative)
}
Stage (Join-Path $OptiScalerRoot 'OptiScaler.dll') 'OptiScaler.dll'
Stage (Join-Path $DiagnosticRoot 'bin/d4r_nvngx.dll') 'd4r/_nvngx.dll'
Stage (Join-Path $DiagnosticRoot "bin/pixel_convert_${GpuArch}.hsaco") "d4r/pixel_convert_${GpuArch}.hsaco"
Stage (Join-Path $DiagnosticRoot 'nvapi-compat/nvapi64.dll') 'd4r/nvapi/nvapi64.dll'
Stage (Join-Path $DiagnosticRoot 'nvapi-compat/nvapi64.dll') 'd4r/zluda/nvapi64.dll'
Stage (Join-Path $DiagnosticRoot 'bin/d4r_debug_launcher.exe') 'd4r/d4r_debug_launcher.exe'
Stage (Join-Path $DiagnosticRoot 'bin/d4r_gpu_inventory.exe') 'd4r/d4r_gpu_inventory.exe'
foreach ($file in @('nvcuda.dll','libc++.dll','libunwind.dll')) { Stage (Join-Path $ZludaRoot $file) "d4r/zluda/$file" }
Stage (Join-Path $ZludaRoot 'nvapi64.dll') 'd4r/nvapi/backend/nvapi64.dll'
foreach ($file in @('amdhip64_7.dll','amd_comgr.dll','hiprtc0717.dll','hiprtc-builtins0717.dll','rocm_kpack.dll','AMD.ROCM.Comgr.MANIFEST','.hipVersion')) {
Stage (Join-Path $HipRoot "bin/$file") "d4r/hip/bin/$file"
}
$entries = @{}
foreach ($directory in @($KernelKRoot, $KernelMRoot)) {
foreach ($line in Get-Content -LiteralPath (Join-Path $directory 'd4r-kernels.txt')) {
if (!$line.Trim() -or $line.StartsWith('#')) { continue }
if ($line -notmatch '^([A-Za-z0-9_]+) ([0-9a-f]{16})$') { throw "Invalid native manifest entry: $line" }
if ($entries.ContainsKey($Matches[1])) { throw "Duplicate native kernel: $($Matches[1])" }
$entries[$Matches[1]] = $line
Stage (Join-Path $directory ($Matches[1] + '.hsaco')) ('d4r/native/' + $Matches[1] + '.hsaco')
}
}
if ($entries.Count -ne 16) { throw "Expected 11 K and 5 M native objects; found $($entries.Count)" }
@("# Audited DLSS 310.9.1: K + M $GpuArch native kernels", '# Generated by package-windows-game.ps1') + @($entries.Values | Sort-Object) |
Set-Content -LiteralPath (Join-Path $PackageRoot 'd4r/native/d4r-kernels.txt') -Encoding ASCII
$stagedFiles.Add('d4r/native/d4r-kernels.txt')
Stage (Join-Path $repo 'scripts/windows/windows-game.ps1') 'windows-game.ps1'
Stage (Join-Path $repo 'scripts/windows/game-summary.ps1') 'game-summary.ps1'
Stage (Join-Path $repo 'scripts/windows/gpu-target.ps1') 'gpu-target.ps1'
Stage (Join-Path $repo 'scripts/windows/gpu-preflight.ps1') 'gpu-preflight.ps1'
Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'gpu-targets.json'
if (Test-Path -LiteralPath (Join-Path $DiagnosticRoot 'gpu-target.json')) {
Stage (Join-Path $DiagnosticRoot 'gpu-target.json') 'gpu-target.json'
} else {
# Builds predating target metadata were gfx1201 only. The resolver rejects
# any attempt to label such a build gfx1200.
@{schema=1; architecture=$GpuArch; wavefrontSize=32; validation='Legacy gfx1201 build; run the GPU diagnostics.'} |
ConvertTo-Json | Set-Content -LiteralPath (Join-Path $PackageRoot 'gpu-target.json') -Encoding UTF8
$stagedFiles.Add('gpu-target.json')
}
Stage (Join-Path $repo 'scripts/windows/capture-game-window.ps1') 'capture-game-window.ps1'
Stage (Join-Path $repo 'scripts/windows/send-game-key.ps1') 'send-game-key.ps1'
Stage (Join-Path $repo 'docs/windows-game.md') 'README.md'
Stage (Join-Path $repo 'docs/windows-performance.md') 'windows-performance.md'
Stage (Join-Path $repo 'docs/windows-gpu-support.md') 'windows-gpu-support.md'
Stage (Join-Path $repo 'docs/windows-rdna4-port.md') 'windows-rdna4-port.md'
Stage (Join-Path $repo 'packaging/windows/d4r.ini') 'd4r/d4r.ini'
Stage (Join-Path $repo 'tools/windows/dll-pins.txt') 'd4r/dll-pins.txt'
Stage (Join-Path $repo 'LICENSE') 'licenses/d4r.txt'
Stage (Join-Path $OptiScalerRoot 'GPL-3.0.txt') 'licenses/OptiScaler.txt'
Stage (Join-Path $repo 'external/ZLUDA/LICENSE-MIT') 'licenses/ZLUDA-MIT.txt'
Stage (Join-Path $repo 'external/ZLUDA/LICENSE-APACHE') 'licenses/ZLUDA-APACHE.txt'
Stage (Join-Path $repo 'external/ZLUDA/ext/llvm-project/LICENSE.TXT') 'licenses/LLVM.txt'
Stage (Join-Path $repo 'external/MinHook/LICENSE.txt') 'licenses/MinHook.txt'
Stage (Join-Path $HipRoot 'share/doc/amd_comgr/LICENSE.txt') 'licenses/amd_comgr.txt'
Stage (Join-Path $repo 'external/clr/LICENSE.md') 'licenses/HIP-CLR.txt'
foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/optiscaler') -Filter '*.patch') { Stage $patch.FullName ('source-patches/optiscaler/' + $patch.Name) }
foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda') -Filter '*.patch') { Stage $patch.FullName ('source-patches/zluda/' + $patch.Name) }
foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda-llvm') -Filter '*.patch') { Stage $patch.FullName ('source-patches/zluda-llvm/' + $patch.Name) }
$sourceArchive=Join-Path $repo 'build/d4r-windows-rdna4-source.zip'
New-Item -ItemType Directory -Force (Split-Path $sourceArchive) | Out-Null
& git -C $repo archive --format=zip --output $sourceArchive $sourceCommit
if ($LASTEXITCODE) { throw 'Cannot archive the committed d4r source.' }
Stage $sourceArchive 'source/d4r-windows-rdna4-source.zip'
$mBuildInfoPath=Join-Path $KernelMRoot 'build-info.json'
$nativeFp8M=$false; $tokenLanesM=$false
if (Test-Path -LiteralPath $mBuildInfoPath) {
$mBuildInfo=Get-Content -LiteralPath $mBuildInfoPath -Raw | ConvertFrom-Json
if ($mBuildInfo.architecture -ne $GpuArch -or $mBuildInfo.family -ne 'M') { throw "M build metadata does not match ${GpuArch}: $mBuildInfoPath" }
$nativeFp8M=[bool]$mBuildInfo.nativeFp8
$tokenLanesM=[bool]$mBuildInfo.tokenLanes
}
if ($nativeFp8M) {
if (!$tokenLanesM -or $GpuArch -notmatch '^gfx12') { throw 'Native FP8 M packages require the gfx12 token-lane build.' }
$marker=Join-Path $PackageRoot 'd4r/native/d4r-native-fp8.txt'
New-Item -ItemType Directory -Force (Split-Path $marker) | Out-Null
@('D4R_NATIVE_FP8 1',"architecture=$GpuArch",'family=M','tokenLanes=true') |
Set-Content -LiteralPath $marker -Encoding ASCII
$stagedFiles.Add('d4r/native/d4r-native-fp8.txt')
}
$metadata = [ordered]@{
architecture=$GpuArch; hardwareValidation=$(if ($GpuArch -eq 'gfx1201') { 'RX9070XT tested; other SKUs unverified' } else { 'compile-only; hardware unverified' }); nativeKernels=16; dlssSha256='3975567b8943c53acce397f2b72380092f84f162d00b0d2c7d08a1025c563983';
nativeFp8M=$nativeFp8M; tokenLanesM=$tokenLanesM;
d4rCommit=$sourceCommit;
d4rWorkingTreeDirty=$sourceDirty;
optiScaler=(Get-Content -LiteralPath (Join-Path $OptiScalerRoot 'build-info.json') -Raw | ConvertFrom-Json);
zludaBuild=(Get-Content -LiteralPath (Join-Path $ZludaRoot 'build-info.json') -Raw | ConvertFrom-Json);
hipRuntime='TheRock 10.2.0a20260929 / HIP 7.17.26386';
files=@($stagedFiles | ForEach-Object { Get-Item -LiteralPath (Join-Path $PackageRoot $_) } | ForEach-Object {
@{path=$_.FullName.Substring($PackageRoot.Length+1); sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash; version=$_.VersionInfo.FileVersion}
})
}
$metadata | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath (Join-Path $PackageRoot 'package.json') -Encoding UTF8
if (Get-ChildItem -LiteralPath $PackageRoot -Recurse -File | Where-Object { $_.Name -eq 'nvngx_dlss.dll' -or ($_.Name -eq '_nvngx.dll' -and $_.DirectoryName -ne (Join-Path $PackageRoot 'd4r')) }) {
throw 'Proprietary NVIDIA binaries must not be in the package.'
}
Write-Host "Windows game development package: $PackageRoot (NVIDIA DLLs excluded)"
if ($ArchivePath) {
$ArchivePath=[IO.Path]::GetFullPath($ArchivePath)
if ($ArchivePath.StartsWith($PackageRoot+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Place the ZIP outside the package directory.' }
Add-Type -AssemblyName System.IO.Compression,System.IO.Compression.FileSystem
New-Item -ItemType Directory -Force (Split-Path $ArchivePath) | Out-Null
$stream=[IO.File]::Open($ArchivePath,[IO.FileMode]::Create,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None)
$archive=$null
try {
$archive=[IO.Compression.ZipArchive]::new($stream,[IO.Compression.ZipArchiveMode]::Create)
# Never archive caches, results, private texture outputs or a local DLL
# merely because it happens to be somewhere under PackageRoot.
foreach ($relative in @($stagedFiles)+@('package.json')) {
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive,
(Join-Path $PackageRoot $relative),$relative.Replace('\','/'),[IO.Compression.CompressionLevel]::Optimal)
}
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
Write-Host "Public package archive: $ArchivePath"
}
@@ -0,0 +1,113 @@
[CmdletBinding()]
param(
[string]$GamePackagePrefix, [Parameter(Mandatory=$true)][string]$PackageRoot,
[string]$ArchivePath,
[string]$NvidiaDirectory, [string]$NvidiaLicensePath
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$GamePackagePrefix) { $GamePackagePrefix=Join-Path $repo 'dist/windows-gpu-coverage-game' }
$PackageRoot=[IO.Path]::GetFullPath($PackageRoot)
if (Test-Path -LiteralPath $PackageRoot) { throw 'Use a new output directory to avoid mixing releases.' }
$commit=(& git -C $repo rev-parse HEAD).Trim()
if ($ArchivePath -and [bool](& git -C $repo status --porcelain)) { throw 'Commit source changes before creating a public ZIP.' }
New-Item -ItemType Directory -Force $PackageRoot | Out-Null
$files=[Collections.Generic.List[object]]::new()
function Stage([string]$Source,[string]$Relative) {
$destination=Join-Path $PackageRoot $Relative
New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null
Copy-Item -LiteralPath $Source -Destination $destination
$item=Get-Item -LiteralPath $destination
$entry=@{path=$Relative.Replace('\','/'); sha256=(Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash; version=$item.VersionInfo.FileVersion}
$files.Add($entry)
return $entry
}
$targets=[ordered]@{}; $common=@(); $baseline=$null
foreach ($gpu in Get-D4RGpuTargets) {
$arch=$gpu.architecture; $source="$GamePackagePrefix-$arch"
$metadata=Get-Content -LiteralPath (Join-Path $source 'package.json') -Raw | ConvertFrom-Json
if ($metadata.architecture -ne $arch -or $metadata.d4rWorkingTreeDirty) { throw "Uncommitted or wrong-target input: $source" }
$targetFiles=@()
foreach ($file in $metadata.files) {
$relative=$file.path.Replace('\','/')
if ((Get-FileHash -LiteralPath (Join-Path $source $file.path) -Algorithm SHA256).Hash -ne $file.sha256) { throw "Input file changed: $source/$relative" }
if ($relative.EndsWith('.hsaco')) { Assert-D4RCodeObjectTarget (Join-Path $source $file.path) $arch }
if ($relative -eq 'gpu-target.json' -or $relative -eq 'd4r/_nvngx.dll' -or $relative -eq 'd4r/d4r_gpu_inventory.exe' -or $relative -eq 'd4r/d4r_debug_launcher.exe' -or $relative -eq 'd4r/nvapi/nvapi64.dll' -or
$relative.StartsWith('d4r/native/') -or $relative -like 'd4r/pixel_convert_*.hsaco') {
$entry=Stage (Join-Path $source $file.path) "files/targets/$arch/$relative"
$targetFiles+=@{path=$relative; sha256=$entry.sha256; version=$entry.version}
} elseif ($relative -eq 'OptiScaler.dll' -or $relative.StartsWith('d4r/') -or $relative.StartsWith('licenses/')) {
$publicPath=if ($relative.StartsWith('licenses/')) { $relative } else { "files/common/$relative" }
if (!$baseline) {
$entry=Stage (Join-Path $source $file.path) $publicPath
if (!$relative.StartsWith('licenses/')) { $common+=@{path=$relative; sha256=$entry.sha256; version=$entry.version} }
} elseif ((Get-FileHash -LiteralPath (Join-Path $PackageRoot $publicPath) -Algorithm SHA256).Hash -ne $file.sha256) {
throw "Shared runtime differs in $arch : $relative"
}
}
}
if (@($targetFiles | Where-Object { $_.path.EndsWith('.hsaco') }).Count -ne 17) { throw "Expected 17 code objects for $arch" }
$targets[$arch]=@{binarySourceCommit=$metadata.d4rCommit; hardwareValidation=$metadata.hardwareValidation;
nativeFp8M=[bool]$metadata.nativeFp8M; tokenLanesM=[bool]$metadata.tokenLanesM;
dlssSha256=$metadata.dlssSha256; files=$targetFiles}
if (!$baseline) { $baseline=$metadata }
if ($metadata.dlssSha256 -ne $baseline.dlssSha256 -or $metadata.zludaBuild.sourceCommit -ne $baseline.zludaBuild.sourceCommit) { throw 'Input packages do not use the same validated dependencies.' }
}
foreach ($name in @('windows-game.ps1','game-summary.ps1','gpu-target.ps1','gpu-preflight.ps1')) {
$entry=Stage (Join-Path $PSScriptRoot $name) "files/common/$name"
$common+=@{path=$name; sha256=$entry.sha256; version=$entry.version}
}
$entry=Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'files/common/gpu-targets.json'
$common+=@{path='gpu-targets.json'; sha256=$entry.sha256; version=$entry.version}
[void](Stage (Join-Path $PSScriptRoot 'quick-test.ps1') 'files/quick-test.ps1')
[void](Stage (Join-Path $repo 'docs/windows-quick-test.txt') 'READ-ME-FIRST.txt')
foreach ($launch in @(@{name='START-E.cmd'; arguments='-Preset 5'},@{name='START-K.cmd'; arguments='-Preset 11'},
@{name='START-L.cmd'; arguments='-Preset 12'},@{name='START-M.cmd'; arguments='-Preset 13'},
@{name='RESTORE-GAME.cmd'; arguments='-Action restore'})) {
$path=Join-Path $PackageRoot $launch.name
@('@echo off','cd /d "%~dp0"',('"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -STA -ExecutionPolicy Bypass -File "%~dp0files\quick-test.ps1" '+$launch.arguments),'pause') |
Set-Content -LiteralPath $path -Encoding ASCII
$files.Add(@{path=$launch.name; sha256=(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash; version=$null})
}
$ngxCoreSha256='66767018C36B3BAB46398DADE3ADF173DAA3730FDA75965689EA848C9BC4E79B'
$bundledNvidia=$null
if ($NvidiaDirectory) {
# Opt-in for local testing or a distributor with appropriate permission.
# A matching hash establishes binary identity, not redistribution rights.
if (!$NvidiaLicensePath -or !(Test-Path -LiteralPath $NvidiaLicensePath -PathType Leaf)) {
throw 'Bundled NVIDIA files require -NvidiaLicensePath with their applicable license. This option does not establish redistribution permission.'
}
$core=Join-Path $NvidiaDirectory '_nvngx.dll'
$dlss=Join-Path $NvidiaDirectory 'nvngx_dlss.dll'
if ((Get-FileHash -LiteralPath $core -Algorithm SHA256).Hash -ne $ngxCoreSha256 -or
(Get-FileHash -LiteralPath $dlss -Algorithm SHA256).Hash -ne $baseline.dlssSha256) {
throw 'Bundled NVIDIA files must match the validated original NGX and DLSS hashes.'
}
[void](Stage $core 'files/nvidia/_nvngx.dll')
[void](Stage $dlss 'files/nvidia/nvngx_dlss.dll')
[void](Stage $NvidiaLicensePath 'licenses/NVIDIA-RTX.txt')
$bundledNvidia=@{ngxCore='nvidia/_nvngx.dll'; dlssDll='nvidia/nvngx_dlss.dll'; license='licenses/NVIDIA-RTX.txt'}
} elseif ($NvidiaLicensePath) { throw '-NvidiaLicensePath requires -NvidiaDirectory.' }
$metadata=[ordered]@{schema=1; packageCommit=$commit; binarySourceCommit=$baseline.d4rCommit;
ngxCoreSha256=$ngxCoreSha256; bundledNvidia=$bundledNvidia;
dependencies=@{optiScalerSourceCommit=$baseline.optiScaler.sourceCommit; zludaSourceCommit=$baseline.zludaBuild.sourceCommit;
llvmSource=$baseline.zludaBuild.llvmSource; hipRuntime=$baseline.hipRuntime};
commonFiles=$common; targets=$targets; files=$files}
$metadata | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $PackageRoot 'files/package.json') -Encoding UTF8
if ($ArchivePath) {
$ArchivePath=[IO.Path]::GetFullPath($ArchivePath)
if ($ArchivePath.StartsWith($PackageRoot+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Place the ZIP outside the output directory.' }
New-Item -ItemType Directory -Force (Split-Path $ArchivePath) | Out-Null
Add-Type -AssemblyName System.IO.Compression,System.IO.Compression.FileSystem
$stream=[IO.File]::Open($ArchivePath,[IO.FileMode]::Create,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None)
$archive=$null
try {
$archive=[IO.Compression.ZipArchive]::new($stream,[IO.Compression.ZipArchiveMode]::Create)
foreach ($relative in @($files.path)+@('files/package.json')) {
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive,(Join-Path $PackageRoot $relative),$relative,[IO.Compression.CompressionLevel]::Optimal)
}
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
}
$nvidiaMode=if ($bundledNvidia) { 'bundled NVIDIA files; distributor must have appropriate permission' } else { 'user-supplied NVIDIA files' }
Write-Host "Quick-test package: $PackageRoot (11 targets, automatic GPU selection, $nvidiaMode)"
+108
View File
@@ -0,0 +1,108 @@
# Builds the Windows drag-in release: extract it into the game folder, copy
# the two NVIDIA DLLs, edit d4r\d4r.ini. Like the Linux release, no installer
# or launcher is involved. Inputs are the per-target game packages that
# package-windows-game.ps1 produces (the same inputs as the quick test).
[CmdletBinding()]
param(
[string]$GamePackagePrefix,
[Parameter(Mandatory=$true)][string]$LoaderDll,
[Parameter(Mandatory=$true)][string]$PackageRoot,
[string[]]$Architectures, # default: every target in gpu-targets.json; a subset makes a smaller release
[string]$ArchivePath
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$GamePackagePrefix) { $GamePackagePrefix=Join-Path $repo 'dist/windows-gpu-coverage-game' }
$PackageRoot=[IO.Path]::GetFullPath($PackageRoot)
if (Test-Path -LiteralPath $PackageRoot) { throw 'Use a new output directory to avoid mixing releases.' }
$git=Get-Command git -ErrorAction SilentlyContinue
$commit=if ($git) { (& git -C $repo rev-parse HEAD).Trim() } else { $null }
if ($ArchivePath -and (!$git -or [bool](& git -C $repo status --porcelain))) { throw 'A public ZIP needs git and committed sources.' }
New-Item -ItemType Directory -Force $PackageRoot | Out-Null
$files=[Collections.Generic.List[object]]::new()
function Stage([string]$Source,[string]$Relative) {
$destination=Join-Path $PackageRoot $Relative
if (Test-Path -LiteralPath $destination) { throw "Duplicate release path: $Relative" }
New-Item -ItemType Directory -Force (Split-Path $destination) | Out-Null
Copy-Item -LiteralPath $Source -Destination $destination
$item=Get-Item -LiteralPath $destination
$files.Add(@{path=$Relative.Replace('\','/'); sha256=(Get-FileHash -LiteralPath $destination -Algorithm SHA256).Hash; version=$item.VersionInfo.FileVersion})
}
$targets=[ordered]@{}; $baseline=$null; $commonStaged=$false; $inventoryStaged=$false
$selected=@(Get-D4RGpuTargets | Where-Object { !$Architectures -or $Architectures -contains $_.architecture })
if (!$selected.Count -or ($Architectures -and $selected.Count -ne @($Architectures | Select-Object -Unique).Count)) { throw "Unknown GPU target in -Architectures: $($Architectures -join ', ')" }
foreach ($gpu in $selected) {
$arch=$gpu.architecture; $source="$GamePackagePrefix-$arch"
$metadata=Get-Content -LiteralPath (Join-Path $source 'package.json') -Raw | ConvertFrom-Json
if ($metadata.architecture -ne $arch -or $metadata.d4rWorkingTreeDirty) { throw "Uncommitted or wrong-target input: $source" }
if (!$baseline) { $baseline=$metadata }
if ($metadata.dlssSha256 -ne $baseline.dlssSha256 -or $metadata.zludaBuild.sourceCommit -ne $baseline.zludaBuild.sourceCommit) { throw 'Input packages do not use the same validated dependencies.' }
$objects=0
foreach ($file in $metadata.files) {
$relative=$file.path.Replace('\','/'); $path=Join-Path $source $file.path
if ((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $file.sha256) { throw "Input file changed: $source/$relative" }
if ($relative.EndsWith('.hsaco')) { Assert-D4RCodeObjectTarget $path $arch; $objects++ }
# Per-target files get target-specific names so one folder serves every GPU.
# One GPU-query tool serves every target: it reports each device's real architecture.
if ($relative -eq 'd4r/d4r_gpu_inventory.exe') { if (!$inventoryStaged) { Stage $path 'd4r/d4r_gpu_inventory.exe'; $inventoryStaged=$true } }
elseif ($relative -eq 'd4r/_nvngx.dll') { Stage $path "d4r/_nvngx_$arch.dll" }
elseif ($relative -eq 'd4r/nvapi/nvapi64.dll') { Stage $path "d4r/nvapi/$arch/nvapi64.dll" }
elseif ($relative -like 'd4r/pixel_convert_*.hsaco') { Stage $path $relative }
elseif ($relative.StartsWith('d4r/native/')) { Stage $path ("d4r/native/$arch/" + $relative.Substring('d4r/native/'.Length)) }
elseif ($relative -eq 'd4r/nvapi/backend/nvapi64.dll' -or $relative -eq 'OptiScaler.dll' -or $relative.StartsWith('licenses/') -or
($relative.StartsWith('d4r/hip/') -or $relative.StartsWith('d4r/zluda/'))) {
$public=if ($relative -eq 'OptiScaler.dll') { 'dxgi.dll' } elseif ($relative.StartsWith('licenses/')) { "d4r/$relative" } else { $relative }
if (!$commonStaged) { Stage $path $public }
elseif ((Get-FileHash -LiteralPath (Join-Path $PackageRoot $public) -Algorithm SHA256).Hash -ne $file.sha256) { throw "Shared runtime differs in $arch : $relative" }
}
# Installer-only files (launcher, PowerShell installer, docs) are not part of a drag-in install.
}
if ($objects -ne 17) { throw "Expected 17 code objects for $arch" }
$commonStaged=$true
$targets[$arch]=@{binarySourceCommit=$metadata.d4rCommit; hardwareValidation=$metadata.hardwareValidation;
nativeFp8M=[bool]$metadata.nativeFp8M; tokenLanesM=[bool]$metadata.tokenLanesM}
}
$loader=(Get-Item -LiteralPath $LoaderDll).FullName
if ([IO.Path]::GetFileName($loader) -ne 'd4r_nvngx_loader.dll') { throw 'Pass the d4r_nvngx_loader.dll built by CMake.' }
Stage $loader 'd4r/_nvngx.dll'
Stage (Join-Path $repo 'packaging/windows/OptiScaler.ini') 'OptiScaler.ini'
Stage (Join-Path $repo 'packaging/windows/d4r.ini') 'd4r/d4r.ini'
Stage (Join-Path $repo 'tools/windows/dll-pins.txt') 'd4r/dll-pins.txt'
Stage (Join-Path $repo 'tools/windows/gpu-targets.json') 'd4r/gpu-targets.json'
if (!$inventoryStaged) { throw 'No d4r/d4r_gpu_inventory.exe in the inputs; d4r-check.ps1 needs it to query the GPU.' }
foreach ($optional in @(@{source='packaging/windows/WINDOWS_README.txt'; path='WINDOWS_README.txt'},
@{source='packaging/windows/install.bat'; path='install.bat'},
@{source='scripts/windows/install-dlss.ps1'; path='install-dlss.ps1'},
@{source='scripts/windows/d4r-check.ps1'; path='d4r/d4r-check.ps1'})) {
$path=Join-Path $repo $optional.source
if (Test-Path -LiteralPath $path) { Stage $path $optional.path }
}
# Shows players where the NGX core goes; a ZIP cannot carry an empty folder.
$placeholder=Join-Path $PackageRoot 'd4r/ngx/PUT _nvngx.dll HERE.txt'
New-Item -ItemType Directory -Force (Split-Path $placeholder) | Out-Null
"Copy NVIDIA's _nvngx.dll into this folder. See WINDOWS_README.txt." | Set-Content -LiteralPath $placeholder -Encoding ASCII
$files.Add(@{path='d4r/ngx/PUT _nvngx.dll HERE.txt'; sha256=(Get-FileHash -LiteralPath $placeholder -Algorithm SHA256).Hash; version=$null})
if (Get-ChildItem -LiteralPath $PackageRoot -Recurse -File | Where-Object { $_.Name -eq 'nvngx_dlss.dll' -or ($_.Name -eq '_nvngx.dll' -and $_.DirectoryName -ne (Join-Path $PackageRoot 'd4r')) }) {
throw 'Proprietary NVIDIA binaries must not be in the release.'
}
# Read by d4r-check.ps1: every shipped file's hash, so a damaged or mixed install is reported.
$manifest=[ordered]@{schema=1; kind='windows-drag-in'; packageCommit=$commit; binarySourceCommit=$baseline.d4rCommit;
dependencies=@{optiScalerSourceCommit=$baseline.optiScaler.sourceCommit; zludaSourceCommit=$baseline.zludaBuild.sourceCommit; hipRuntime=$baseline.hipRuntime};
targets=$targets; files=$files}
$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $PackageRoot 'd4r/package.json') -Encoding UTF8
if ($ArchivePath) {
$ArchivePath=[IO.Path]::GetFullPath($ArchivePath)
if ($ArchivePath.StartsWith($PackageRoot+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Place the ZIP outside the output directory.' }
New-Item -ItemType Directory -Force (Split-Path $ArchivePath) | Out-Null
Add-Type -AssemblyName System.IO.Compression,System.IO.Compression.FileSystem
$stream=[IO.File]::Open($ArchivePath,[IO.FileMode]::Create,[IO.FileAccess]::ReadWrite,[IO.FileShare]::None)
$archive=$null
try {
$archive=[IO.Compression.ZipArchive]::new($stream,[IO.Compression.ZipArchiveMode]::Create)
foreach ($relative in @($files.path)+@('d4r/package.json')) {
[void][IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive,(Join-Path $PackageRoot $relative),$relative,[IO.Compression.CompressionLevel]::Optimal)
}
} finally { if ($archive) { $archive.Dispose() }; $stream.Dispose() }
}
Write-Host "Windows drag-in release: $PackageRoot ($($targets.Count) GPU target(s): $($targets.Keys -join ', '); no NVIDIA DLLs)"
@@ -0,0 +1,34 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$LlvmSourceRoot)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$expected='ff4dc1f7c9e1c64d4d69e40f4ed30c2280a96dfd'
$actual=(& git -C $LlvmSourceRoot rev-parse HEAD).Trim()
if ($LASTEXITCODE -or $actual -ne $expected) { throw "Expected audited ZLUDA LLVM source $expected, found $actual; review the patch against this revision." }
$patches=@(Get-ChildItem (Join-Path $repo 'patches/zluda-llvm') -Filter *.patch | Sort-Object Name)
foreach ($patch in $patches) {
$oldPreference=$ErrorActionPreference
try {
$ErrorActionPreference='Continue'
& git -C $LlvmSourceRoot apply --reverse --check $patch.FullName 2>$null
$applied=($LASTEXITCODE -eq 0)
} finally { $ErrorActionPreference=$oldPreference }
if (!$applied) {
& git -C $LlvmSourceRoot apply --check $patch.FullName
if ($LASTEXITCODE) { throw "LLVM source patch conflicts: $($patch.Name)" }
& git -C $LlvmSourceRoot apply $patch.FullName
if ($LASTEXITCODE) { throw "LLVM source patch failed: $($patch.Name)" }
}
Write-Host "LLVM source patch present: $($patch.Name)"
}
# The pinned backport is the entire intended LLVM delta.
if ($patches.Count -ne 1) { throw 'Review combined LLVM source provenance before adding more patches.' }
$audit=Join-Path $repo ('build/llvm-source-audit-'+[Guid]::NewGuid().ToString('N')+'.patch')
New-Item -ItemType Directory -Force (Split-Path $audit) | Out-Null
try {
& git -C $LlvmSourceRoot diff --binary --output=$audit
if ($LASTEXITCODE) { throw 'Cannot audit LLVM source diff.' }
$actualDiff=[IO.File]::ReadAllText($audit).Replace("`r`n","`n").TrimEnd()
$expectedDiff=[IO.File]::ReadAllText($patches[0].FullName).Replace("`r`n","`n").TrimEnd()
if ($actualDiff -cne $expectedDiff) { throw 'LLVM source contains changes outside the exported audited patch.' }
} finally { if (Test-Path -LiteralPath $audit) { Remove-Item -LiteralPath $audit } }
+25
View File
@@ -0,0 +1,25 @@
[CmdletBinding()]
param([string]$SourceRoot)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$SourceRoot) { $SourceRoot = Join-Path $repo 'external/ZLUDA' }
$SourceRoot = [IO.Path]::GetFullPath($SourceRoot)
$base = 'ee2f25a180099fa42f36b2346732e1f2470a03ad'
if (!(Test-Path (Join-Path $SourceRoot 'Cargo.toml'))) { throw 'Clone upstream ZLUDA into external/ZLUDA first.' }
Push-Location $SourceRoot
try {
$revision = (& git rev-parse HEAD).Trim()
if ($revision -ne $base) { throw "Expected ZLUDA $base, found $revision; review patches against the new revision." }
$dirty = @(& git status --porcelain --untracked-files=no --ignore-submodules=all)
if ($dirty.Count) { throw 'ZLUDA source has tracked modifications. Keep this prepared checkout; do not reapply patches.' }
& git switch -c windows-rdna4
if ($LASTEXITCODE) { throw 'Could not create the local ZLUDA branch.' }
foreach ($patch in (Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda') -Filter '*.patch' | Sort-Object Name)) {
& git apply --check $patch.FullName
if ($LASTEXITCODE) { throw "Patch check failed: $($patch.Name)" }
& git apply --whitespace=nowarn $patch.FullName
if ($LASTEXITCODE) { throw "Patch failed: $($patch.Name)" }
Write-Host "Applied $($patch.Name)"
}
Write-Host "Prepared Windows ZLUDA source at $SourceRoot (base $base)"
} finally { Pop-Location }
+44
View File
@@ -0,0 +1,44 @@
[CmdletBinding()]
param(
[ValidateSet(5,11,12,13)][int]$Preset = 11,
[string]$ZludaRoot, [string]$PackageRoot, [string]$OutputDirectory,
[string]$NativeKernelDirectory,
[int]$Iterations = 4,
[switch]$Translated, [switch]$NativeFp8
)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if (!$PackageRoot) { $PackageRoot=Join-Path $repo 'dist/windows-rdna4-command-list' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/profile-' + $Preset + '-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$nativeDirectory=if ($NativeFp8) {
if ($GpuArch -notmatch '^gfx12' -or $Preset -notin @(12,13)) { throw '-NativeFp8 requires gfx12 and preset L/M.' }
if (!$NativeKernelDirectory) { $NativeKernelDirectory=Join-Path $repo 'build/native-m-fp8-token-lane-hwpack' }
$info=Get-Content -LiteralPath (Join-Path $NativeKernelDirectory 'build-info.json') -Raw | ConvertFrom-Json
if ($info.architecture -ne $GpuArch -or !$info.nativeFp8 -or !$info.tokenLanes) { throw 'NativeFp8 needs the matching gfx12 token-lane M kernel bundle.' }
[IO.Path]::GetFullPath($NativeKernelDirectory)
} elseif ($Translated -or $Preset -eq 5) { $null }
elseif ($Preset -eq 11) { Join-Path $repo "build/native-k-$GpuArch" }
else { Join-Path $repo "build/native-m-$GpuArch" }
$settings=@{D4R_ZLUDA_PROFILE='1'; D4R_PROFILE_STAGES='1'; D4R_VALIDATE_OUTPUT='1';
D4R_ZLUDA_PROFILE_DEFERRED=$null; D4R_ZLUDA_PROFILE_ALLOW_LEGACY=$null; D4R_ZLUDA_PROFILE_EVERY=$null;
D4R_ZLUDA_NATIVE_DIR=$nativeDirectory}
$settings['D4R_ZLUDA_WMMA_FP8_NATIVE']=if ($NativeFp8) { '1' } else { $null }
$old=@{}
try {
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
$arguments=@{RuntimeProfile='therock'; ZludaRoot=$ZludaRoot; PackageRoot=$PackageRoot; OutputDirectory=$OutputDirectory;
NgxCore=(Join-Path $repo '_nvngx.dll'); DlssDll=(Join-Path $repo 'nvngx_dlss.dll'); NgxMode='d3d12';
NgxAbi='project-legacy'; Preset=$Preset; NgxOnly=$true; RequireNativeNetwork=(!$Translated -and $Preset -ne 5); NativeFp8=$NativeFp8; CommandListBackend=$true;
CaptureExceptions=$true; EarlyIndirectProbe=$true; PixelProfile='depth-stencil'; BarrierMode='inherited-legacy';
Iterations=$Iterations; TimeoutSeconds=300; OptiScalerDll=(Join-Path $repo 'dist/optiscaler-windows-d4r/OptiScaler.dll')}
& (Join-Path $PSScriptRoot 'test-windows-rdna4.ps1') @arguments
if ($LASTEXITCODE) { throw 'Profiling workload failed; see diagnostic bundle.' }
$python=(Get-Command python.exe -ErrorAction Stop).Source
& $python (Join-Path $repo 'tools/windows/profile_report.py') $OutputDirectory --output (Join-Path $OutputDirectory 'profile.json')
if ($LASTEXITCODE) { throw 'No usable profile records.' }
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
+196
View File
@@ -0,0 +1,196 @@
[CmdletBinding()]
param(
[ValidateSet('run','install','restore')][string]$Action='run',
[ValidateSet(5,11,12,13)][int]$Preset=11,
[string]$GameExe, [string]$NgxCore, [string]$DlssDll,
[switch]$NativeFp8, [switch]$CaptureExceptions,
[ValidateRange(30,600)][int]$RunSeconds=180
)
$ErrorActionPreference='Stop'
$root=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
$work=Join-Path $root 'work'
$settingsPath=Join-Path $work 'settings.json'
New-Item -ItemType Directory -Force $work | Out-Null
$saved=$null
if (Test-Path -LiteralPath $settingsPath) {
try { $saved=Get-Content -LiteralPath $settingsPath -Raw | ConvertFrom-Json }
catch { Write-Host 'Saved choices could not be read. Select the files again.' }
}
function Select-LocalFile([string]$Title, [string]$FileName, [string]$Previous) {
if ($Previous -and (Test-Path -LiteralPath $Previous -PathType Leaf)) { return (Get-Item -LiteralPath $Previous).FullName }
Add-Type -AssemblyName System.Windows.Forms
$dialog=New-Object Windows.Forms.OpenFileDialog
try {
$dialog.Title=$Title; $dialog.FileName=$FileName
$dialog.Filter=if ($FileName -eq '*.exe') { 'Game executable (*.exe)|*.exe' } else { "$FileName|$FileName" }
if ($dialog.ShowDialog() -ne [Windows.Forms.DialogResult]::OK) { throw 'File selection cancelled. No test was launched.' }
return $dialog.FileName
} finally { $dialog.Dispose() }
}
function Copy-Payload([string]$Source, [string]$Destination, [string]$Relative) {
$path=[IO.Path]::GetFullPath((Join-Path $Destination $Relative))
if (!$path.StartsWith($Destination+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Invalid package path.' }
New-Item -ItemType Directory -Force (Split-Path $path) | Out-Null
Copy-Item -LiteralPath (Join-Path $Source $Relative) -Destination $path -Force
}
function Get-BundledNvidiaFile([string]$Relative) {
$directory=Join-Path $PSScriptRoot 'nvidia'
$path=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot $Relative))
if (!$path.StartsWith($directory+'\',[StringComparison]::OrdinalIgnoreCase) -or
!(Test-Path -LiteralPath $path -PathType Leaf)) { throw 'Invalid bundled NVIDIA file. Extract the complete package again.' }
return $path
}
if ($Action -eq 'restore') {
$GameExe=Select-LocalFile 'Select the SAME game executable used for the test' '*.exe' $(if ($GameExe) { $GameExe } elseif ($saved) { $saved.game })
& (Join-Path $PSScriptRoot 'common/windows-game.ps1') -Action restore -GameExe $GameExe
Write-Host 'RESTORED. Launch the game normally again.' -ForegroundColor Green
return
}
$output=Join-Path $root ('results/test-'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff'))
New-Item -ItemType Directory -Force $output | Out-Null
$status=[ordered]@{action=$Action; preset=$Preset; status='starting'; hardwareValidationCompleted=$false}
$selectedPackage=$null
try {
Write-Host 'd4r Windows quick test - keep this window open until you EXIT the game.'
Write-Host 'Checking package and detecting the GPU...'
$manifest=Get-Content -LiteralPath (Join-Path $PSScriptRoot 'package.json') -Raw | ConvertFrom-Json
foreach ($file in $manifest.files) {
$path=[IO.Path]::GetFullPath((Join-Path $root $file.path))
if (!$path.StartsWith($root+'\',[StringComparison]::OrdinalIgnoreCase) -or
(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $file.sha256) { throw "Package is incomplete or changed. Extract the ZIP again. File: $($file.path)" }
}
$status.packageCommit=$manifest.packageCommit
$inventoryDir=Join-Path $output 'gpu'
New-Item -ItemType Directory -Force $inventoryDir | Out-Null
$info=New-Object Diagnostics.ProcessStartInfo
$info.FileName=Join-Path $PSScriptRoot 'targets/gfx1201/d4r/d4r_gpu_inventory.exe'
$info.Arguments='--hip-root "'+(Join-Path $PSScriptRoot 'common/d4r/hip')+'" --output-dir "'+$inventoryDir+'"'
$info.UseShellExecute=$false; $info.CreateNoWindow=$true
$info.EnvironmentVariables['D4R_DIAG_DIR']=$inventoryDir
$info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
$process=New-Object Diagnostics.Process; $process.StartInfo=$info
try {
if (!$process.Start()) { throw 'GPU detection could not start.' }
$stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
$timedOut=!$process.WaitForExit(30000)
if ($timedOut) { $process.Kill(); $process.WaitForExit() }
$stdout.GetAwaiter().GetResult() | Set-Content (Join-Path $inventoryDir 'stdout.log') -Encoding UTF8
$stderr.GetAwaiter().GetResult() | Set-Content (Join-Path $inventoryDir 'stderr.log') -Encoding UTF8
$status.inventoryExit='0x{0:X8}' -f [BitConverter]::ToUInt32([BitConverter]::GetBytes([int]$process.ExitCode),0)
if ($timedOut -or $process.ExitCode) { throw 'HIP could not detect your GPU. The diagnostic ZIP contains the details.' }
} finally { $process.Dispose() }
$inventory=Get-Content -LiteralPath (Join-Path $inventoryDir 'gpu-inventory.json') -Raw | ConvertFrom-Json
$devices=@($inventory.devices | Where-Object { $_.buildEligible -and $_.wavefrontSize -eq 32 -and $manifest.targets.PSObject.Properties.Name -contains $_.architecture } | Sort-Object vramBytes -Descending)
if (!$devices.Count) { throw 'No supported RDNA3/RDNA4 HIP device was detected. See the GPU inventory in the diagnostic ZIP.' }
$device=$devices[0]
if (@($devices.architecture | Select-Object -Unique).Count -gt 1) {
for ($i=0; $i -lt $devices.Count; $i++) { Write-Host "$($i+1): $($devices[$i].name) ($($devices[$i].architecture))" }
$choice=Read-Host 'Select the GPU used by your game (press Enter for 1)'
if ($choice) {
$index=0
if (![int]::TryParse($choice,[ref]$index) -or $index -lt 1 -or $index -gt $devices.Count) { throw 'Invalid GPU selection.' }
$device=$devices[$index-1]
}
}
$arch=$device.architecture; $target=$manifest.targets.$arch
if ($NativeFp8 -and ($arch -notmatch '^gfx12' -or !$target.nativeFp8M -or $Preset -notin @(12,13))) {
throw '-NativeFp8 needs a gfx12 package containing the experimental native-FP8 M kernels and preset L or M.'
}
$status.gpu=$device; $status.binarySourceCommit=$target.binarySourceCommit
$status.nativeFp8=[bool]$NativeFp8; $status.tokenLanesM=[bool]$target.tokenLanesM
Write-Host "Detected: $($device.name) / $arch" -ForegroundColor Cyan
Write-Host 'Experimental build. This run is a correctness test, not an FPS benchmark.'
$previousGame=if ($saved) { $saved.game } else { $null }
if (!$GameExe -and $previousGame -and (Test-Path -LiteralPath $previousGame)) {
Write-Host "Remembered game: $previousGame"
$reuse=Read-Host 'Press Enter to use this game, or type C to choose another (restore the old game first)'
if ($reuse -match '^(?i)c$') { $previousGame=$null }
elseif ($reuse) { throw 'Invalid choice. Press Enter or type C on the next run.' }
}
$GameExe=Select-LocalFile 'Select the actual D3D12 game .exe (not Steam or a launcher)' '*.exe' $(if ($GameExe) { $GameExe } else { $previousGame })
$bundledCore=$null; $bundledDlss=$null
if ($manifest.bundledNvidia) {
$bundledCore=Get-BundledNvidiaFile $manifest.bundledNvidia.ngxCore
$bundledDlss=Get-BundledNvidiaFile $manifest.bundledNvidia.dlssDll
}
$status.nvidiaDllSource=@{core=$(if ($NgxCore) { 'explicit' } elseif ($bundledCore) { 'bundled' } else { 'user-supplied' });
dlss=$(if ($DlssDll) { 'explicit' } elseif ($bundledDlss) { 'bundled' } else { 'user-supplied' })}
if ($bundledCore -and !$NgxCore -and !$DlssDll) { Write-Host 'Using the validated NVIDIA DLL pair included by this package distributor.' }
$NgxCore=Select-LocalFile 'Select your ORIGINAL NVIDIA _nvngx.dll (32.0.16.1714)' '_nvngx.dll' $(if ($NgxCore) { $NgxCore } elseif ($bundledCore) { $bundledCore } elseif ($saved) { $saved.ngxCore })
$DlssDll=Select-LocalFile 'Select your NVIDIA nvngx_dlss.dll (310.9.1)' 'nvngx_dlss.dll' $(if ($DlssDll) { $DlssDll } elseif ($bundledDlss) { $bundledDlss } elseif ($saved) { $saved.dlssDll })
$status.game=$GameExe
$status.localDlls=@($NgxCore,$DlssDll | ForEach-Object { $item=Get-Item -LiteralPath $_; @{path=$item.FullName; version=$item.VersionInfo.FileVersion; sha256=(Get-FileHash -LiteralPath $_ -Algorithm SHA256).Hash} })
if ((Get-FileHash -LiteralPath $NgxCore -Algorithm SHA256).Hash -ne $manifest.ngxCoreSha256) {
throw 'Wrong _nvngx.dll. This test needs the original NVIDIA 32.0.16.1714 DLL, not the d4r shim. Select the correct file on the next run.'
}
if ((Get-FileHash -LiteralPath $DlssDll -Algorithm SHA256).Hash -ne $target.dlssSha256) {
throw 'Wrong nvngx_dlss.dll. This test needs exactly NVIDIA DLSS 310.9.1. Select the correct file on the next run.'
}
if ($GameExe.StartsWith($root+'\',[StringComparison]::OrdinalIgnoreCase)) { throw 'Select the installed GAME executable, outside this extracted package.' }
# Save only validated choices. Wrong DLLs are never remembered.
@{game=$GameExe; ngxCore=$NgxCore; dlssDll=$DlssDll; architecture=$arch} | ConvertTo-Json | Set-Content -LiteralPath $settingsPath -Encoding UTF8
$selectedPackage=Join-Path $work "package-$arch"
New-Item -ItemType Directory -Force $selectedPackage | Out-Null
$selectedFiles=@()
foreach ($file in $manifest.commonFiles) {
Copy-Payload (Join-Path $PSScriptRoot 'common') $selectedPackage $file.path
$selectedFiles+=$file
}
foreach ($file in $target.files) {
Copy-Payload (Join-Path $PSScriptRoot "targets/$arch") $selectedPackage $file.path
$selectedFiles+=$file
}
@{architecture=$arch; d4rCommit=$target.binarySourceCommit; packageCommit=$manifest.packageCommit;
dlssSha256=$target.dlssSha256; hardwareValidation=$target.hardwareValidation;
nativeFp8M=[bool]$target.nativeFp8M; tokenLanesM=[bool]$target.tokenLanesM; files=$selectedFiles} |
ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $selectedPackage 'package.json') -Encoding UTF8
Write-Host 'Original game files will be backed up. RESTORE-GAME.cmd reverses the installation.'
Write-Host 'In the game: select DLSS if available; otherwise select FSR/XeSS to let OptiScaler intercept it.'
Write-Host 'The first launch compiles shaders and can take several minutes. Then play for 30 seconds and EXIT the game normally.'
& (Join-Path $selectedPackage 'windows-game.ps1') -Action $Action -GameExe $GameExe -NgxCore $NgxCore -DlssDll $DlssDll `
-Preset $Preset -RunSeconds $RunSeconds -NativeFp8:$NativeFp8 -ValidateOutput -CaptureExceptions:$CaptureExceptions -OutputDirectory $output
if ($Action -eq 'install') { $status.status='installed-only' }
else {
$summary=Get-Content -LiteralPath (Join-Path $output 'summary.json') -Raw | ConvertFrom-Json
$status.gameSummary=$summary
$required=Get-Content -LiteralPath (Join-Path $selectedPackage 'd4r/native/d4r-kernels.txt') | Where-Object {
if ($Preset -eq 11) { $_ -match '^dltss_pwin_' } elseif ($Preset -in @(12,13)) { $_ -match '^rrlite_' }
} | ForEach-Object { $_.Split(' ')[0] }
$hits=@($summary.kernels | Where-Object { $_.backend -eq 'native' -and $_.launches -gt 0 } | ForEach-Object { $_.kernel })
$status.missingNativeKernels=@($required | Where-Object { $hits -notcontains $_ })
$status.translatedNativeKernels=@($summary.kernels | Where-Object { $_.backend -eq 'translated' -and $required -contains $_.kernel } | ForEach-Object { $_.kernel })
$requiredNativePath=($Preset -eq 5) -or ($summary.nativeLaunches -gt 0)
$expectedNativeCount=if ($Preset -eq 5) { 0 } elseif ($Preset -eq 11) { 11 } else { 5 }
$passed=$summary.exitCode -eq '0x0' -and $summary.completedFrames -gt 0 -and $requiredNativePath -and
$summary.outputGpuChecks -gt 0 -and $summary.failures -eq 0 -and $summary.nonfiniteOutputs -eq 0 -and
$summary.previousFrameOutputs -eq 0 -and $summary.cpuImageCopyFrames -eq 0 -and
@($required).Count -eq $expectedNativeCount -and
$status.missingNativeKernels.Count -eq 0 -and $status.translatedNativeKernels.Count -eq 0
$status.hardwareValidationCompleted=[bool]$passed
$status.status=if ($passed) { 'backend-checks-passed-image-still-needs-user-review' }
elseif ($summary.completedFrames -eq 0 -and $summary.exitCode -eq '0x0' -and $summary.failures -eq 0) { 'inconclusive-process-exited-without-dlss-frames' }
else { 'backend-checks-failed-or-no-dlss-frames' }
$status.session=$summary.session
if ($status.status -eq 'inconclusive-process-exited-without-dlss-frames') {
Write-Host 'The launched process exited without a DLSS frame. A Steam/launcher restart is not tracked by this test. Keep Steam open and select the actual game executable. Send the ZIP if it restarts again.' -ForegroundColor Yellow
}
Write-Host $(if ($passed) { 'Backend checks PASSED. Please also report whether the image looked correct.' } else { 'Test did not pass. Send the diagnostic ZIP; do not guess from the FPS.' }) -ForegroundColor $(if ($passed) { 'Green' } else { 'Yellow' })
}
} catch {
$status.status='failed'; $status.error=$_.Exception.Message
$_ | Out-String | Set-Content -LiteralPath (Join-Path $output 'error.txt') -Encoding UTF8
Write-Host "TEST STOPPED: $($status.error)" -ForegroundColor Red
} finally {
if ($selectedPackage) {
$preflights=Join-Path $selectedPackage 'results'
$latest=Get-ChildItem -LiteralPath $preflights -Directory -ErrorAction SilentlyContinue | Sort-Object Name -Descending | Select-Object -First 1
if ($latest) { Copy-Item -LiteralPath $latest.FullName -Destination (Join-Path $output 'preflight') -Recurse -Force }
}
try { Get-CimInstance Win32_VideoController | Select-Object Name,DriverVersion,DriverDate | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $output 'driver.json') -Encoding UTF8 } catch {}
$status | ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $output 'quick-test.json') -Encoding UTF8
Compress-Archive -LiteralPath $output -DestinationPath ($output+'.zip') -Force
Write-Host "SEND THIS ONE FILE: $output.zip" -ForegroundColor Cyan
Write-Host 'Also tell us: GPU model, game name, K or M, and whether the image was correct.'
Write-Host 'Close the game before running RESTORE-GAME.cmd.'
}
if ($status.status -eq 'failed' -or $status.status -eq 'backend-checks-failed-or-no-dlss-frames' -or $status.status.StartsWith('inconclusive-')) { exit 1 }
+32
View File
@@ -0,0 +1,32 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][int]$GameProcessId,
[ValidateSet('Enter','Escape','Up','Down','Tab','Space')][string]$Key='Enter')
$ErrorActionPreference='Stop'
$process=Get-Process -Id $GameProcessId -ErrorAction Stop
if ($process.ProcessName -eq 'GhostOfTsushima') {
$expected='C:\Program Files (x86)\Steam\steamapps\common\Ghost of Tsushima DIRECTOR''S CUT\GhostOfTsushima.exe'
if ($process.Path -ine $expected) { throw 'Ghost of Tsushima process path does not match the authorized Steam installation.' }
} elseif ($process.ProcessName -ne 'SHProto-Win64-Shipping') {
throw 'This helper only accepts the authorized Ghost of Tsushima or Silent Hill 2 diagnostic process.'
}
if (!('D4RGameKeys' -as [type])) {
Add-Type @'
using System;
using System.Runtime.InteropServices;
public static class D4RGameKeys {
[DllImport("user32.dll")] public static extern bool PostMessage(IntPtr window, uint message, IntPtr key, IntPtr flags);
[DllImport("user32.dll")] public static extern uint MapVirtualKey(uint code, uint kind);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
}
'@
}
$window=$process.MainWindowHandle
if ($window -eq [IntPtr]::Zero) { throw 'Game window missing on this desktop.' }
if ([D4RGameKeys]::GetForegroundWindow() -ne $window) { throw 'Target game is not foreground; key was not sent.' }
$codes=@{Enter=13; Escape=27; Up=38; Down=40; Tab=9; Space=32}
$code=$codes[$Key]; $scan=[D4RGameKeys]::MapVirtualKey($code,0)
$flags=[long](1 -bor ($scan -shl 16))
if ($Key -in @('Up','Down')) { $flags=$flags -bor 0x01000000 }
if (![D4RGameKeys]::PostMessage($window,0x100,[IntPtr]$code,[IntPtr]$flags)) { throw 'Game key-down post failed.' }
if (![D4RGameKeys]::PostMessage($window,0x101,[IntPtr]$code,[IntPtr]($flags -bor 0xc0000000L))) { throw 'Game key-up post failed.' }
Write-Host "Sent $Key only to diagnostic game PID $GameProcessId."
+50
View File
@@ -0,0 +1,50 @@
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$tools = Join-Path $repo '.tools'
$downloads = Join-Path $tools 'downloads'
New-Item -ItemType Directory -Force -Path $downloads | Out-Null
function Ensure-PinnedGitCheckout([string]$Path, [string]$Url, [string]$Commit) {
if (!(Test-Path -LiteralPath $Path)) {
git clone --no-checkout $Url $Path
if ($LASTEXITCODE) { throw "Git clone failed: $Url" }
}
git -C $Path fetch --depth 1 origin $Commit
if ($LASTEXITCODE) { throw "Pinned dependency fetch failed: $Url@$Commit" }
git -C $Path checkout --detach $Commit
if ($LASTEXITCODE) { throw "Pinned dependency checkout failed: $Url@$Commit" }
$actual = (git -C $Path rev-parse HEAD).Trim()
if ($actual -ne $Commit) { throw "Dependency revision mismatch: $Path ($actual)" }
}
$headers = Join-Path $tools 'Vulkan-Headers-v1.4.341'
Ensure-PinnedGitCheckout $headers 'https://github.com/KhronosGroup/Vulkan-Headers.git' 'b5c8f996196ba4aa6d8f97e52b5d3b6e70f7e4e2'
$volk = Join-Path $tools 'volk'
Ensure-PinnedGitCheckout $volk 'https://github.com/zeux/volk.git' '0dc3ce00bf98b9f0b6fe708ca0f7eb74e2830173'
$glslangDirectory = Join-Path $tools 'glslang-16.6.0'
$validator = Join-Path $glslangDirectory 'bin/glslangValidator.exe'
$archive = Join-Path $downloads 'glslang-16.6.0-windows-x86_64-release.zip'
$expectedHash = '82bf434e69b9bb4829de7e2b4bc2c5e7a7861e53d66cf75e5cc70f5f694a8d9b'
if (!(Test-Path -LiteralPath $validator)) {
if (!(Test-Path -LiteralPath $archive)) {
Invoke-WebRequest -UseBasicParsing `
-Uri 'https://github.com/KhronosGroup/glslang/releases/download/16.6.0/glslang-16.6.0-windows-x86_64-release.zip' `
-OutFile $archive
}
$actualHash = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant()
if ($actualHash -ne $expectedHash) { throw "glslang archive SHA256 mismatch: $actualHash" }
Expand-Archive -LiteralPath $archive -DestinationPath $glslangDirectory -Force
$releaseBinary = Join-Path $glslangDirectory 'bin/glslang.exe'
if (!(Test-Path -LiteralPath $releaseBinary)) { throw "glslang archive layout changed: $releaseBinary" }
Copy-Item -LiteralPath $releaseBinary -Destination $validator
}
if (!(Test-Path -LiteralPath $headers -PathType Container) -or
!(Test-Path -LiteralPath (Join-Path $headers 'include/vulkan/vulkan.h')) -or
!(Test-Path -LiteralPath (Join-Path $volk 'volk.c')) -or
!(Test-Path -LiteralPath $validator)) {
throw 'Native engine dependencies are incomplete.'
}
Write-Host "Native engine dependencies ready: Vulkan-Headers $((git -C $headers rev-parse --short HEAD).Trim()), Volk $((git -C $volk rev-parse --short HEAD).Trim()), glslang 16.6.0."
+48
View File
@@ -0,0 +1,48 @@
[CmdletBinding()]
param([string]$ToolRoot, [string]$DownloadRoot)
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ToolRoot) { $ToolRoot = Join-Path $repo '.tools/rust-1.98.1-gnu' }
if (!$DownloadRoot) { $DownloadRoot = Join-Path $repo '.tools/downloads' }
$ToolRoot = [IO.Path]::GetFullPath($ToolRoot)
$DownloadRoot = [IO.Path]::GetFullPath($DownloadRoot)
New-Item -ItemType Directory -Force $ToolRoot,$DownloadRoot | Out-Null
# Pinned official Rust 2026-09-03 manifest. The toolchain is local to this
# workspace; rustup, PATH changes and machine-wide installation are unnecessary.
$components = @(
@{Name='rustc'; Hash='f0e8e33973771acc4d2f87891b19d4f3f2d3827e2e7848c091d7c070bd63479c'},
@{Name='cargo'; Hash='4bd77f16bd2a26db6eacf9320414d3a792d9998cb5e9ac122280ba56126f2a44'},
@{Name='rust-std'; Hash='5bb599a541fcb9c0edc00e512570f60d2262623f1e2a19a44cce3a7a97208788'},
@{Name='rust-mingw'; Hash='75d898804789c12ca969365f0a86d85c3bca1fdb070f0be615ca513a986b2674'}
)
foreach ($component in $components) {
$package = "$($component.Name)-1.98.1-x86_64-pc-windows-gnu"
$archive = Join-Path $DownloadRoot "$package.tar.xz"
if (!(Test-Path $archive) -or (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash -ne $component.Hash) {
Write-Host "Downloading official Rust component $($component.Name)"
& curl.exe --fail --location --silent --show-error --connect-timeout 15 --max-time 300 --retry 2 `
"https://static.rust-lang.org/dist/2026-09-03/$package.tar.xz" --output $archive
if ($LASTEXITCODE) { throw "Download failed for $package (exit=$LASTEXITCODE)" }
}
if ((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash -ne $component.Hash) {
throw "Rust component SHA256 mismatch: $archive"
}
$extract = Join-Path $DownloadRoot $package
if (!(Test-Path (Join-Path $extract 'components'))) {
& tar.exe -xf $archive -C $DownloadRoot
if ($LASTEXITCODE) { throw "Extract failed: $archive" }
}
foreach ($entry in (Get-Content -LiteralPath (Join-Path $extract 'components'))) {
$payload = Join-Path $extract $entry
foreach ($directory in @('bin','lib','share','etc')) {
$source = Join-Path $payload $directory
if (Test-Path $source) { Copy-Item -LiteralPath $source -Destination $ToolRoot -Recurse -Force }
}
}
Write-Host "Verified and installed $package"
}
& (Join-Path $ToolRoot 'bin/rustc.exe') --version
if ($LASTEXITCODE) { throw 'Rust compiler failed to start' }
& (Join-Path $ToolRoot 'bin/cargo.exe') --version
if ($LASTEXITCODE) { throw 'Cargo failed to start' }
Write-Host "Local Rust toolchain: $ToolRoot"
+48
View File
@@ -0,0 +1,48 @@
[CmdletBinding()]
param([ValidateSet('stable', 'therock')][string]$RuntimeProfile = 'stable')
$ErrorActionPreference = 'Stop'
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$localTools = Join-Path $repo '.tools'
$downloadDirectory = Join-Path $localTools 'downloads'
New-Item -ItemType Directory -Force $downloadDirectory | Out-Null
function Get-VerifiedArchive([string]$Url, [string]$Name, [string]$Hash, [string]$Destination, [string]$Marker) {
if (Test-Path -LiteralPath $Marker) { Write-Host "Already present: $Marker"; return }
$archive = Join-Path $downloadDirectory $Name
if (!(Test-Path -LiteralPath $archive)) {
Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $archive
}
if ((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash -ne $Hash) {
throw "SHA256 mismatch: $archive (remove this download and retry)"
}
if ([IO.Path]::GetExtension($archive) -eq '.whl') {
python -c 'import sys,zipfile; zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2])' $archive $Destination
if ($LASTEXITCODE) { throw "Wheel extraction exit=$LASTEXITCODE" }
} else { Expand-Archive -LiteralPath $archive -DestinationPath $Destination -Force }
if (!(Test-Path -LiteralPath $Marker)) { throw "Archive layout changed: $Marker" }
}
Get-VerifiedArchive 'https://github.com/mstorsjo/llvm-mingw/releases/download/20260922/llvm-mingw-20260922-ucrt-x86_64.zip' `
'llvm-mingw.zip' 'e3ad77d117a4bea19a7a3b333341824d79a5a371004a10e25b8504e7b3047666' $localTools `
(Join-Path $localTools 'llvm-mingw-20260922-ucrt-x86_64/bin/x86_64-w64-mingw32-clang++.exe')
Get-VerifiedArchive 'https://github.com/vosen/ZLUDA/releases/download/v7-preview.11/zluda-windows-ee2f25a.zip' `
'zluda.zip' '7788c1ed43385e62f0cc5f4d1aead24c92b671c02f1d685f63182540dea16d74' (Join-Path $localTools 'zluda') `
(Join-Path $localTools 'zluda/zluda/nvcuda.dll')
if ($RuntimeProfile -eq 'therock') {
Get-VerifiedArchive 'https://nightly.repo.amd.com/rocm/core/whl-next/rocm-sdk-core/rocm_sdk_core-10.2.0a20260929-py3-none-win_amd64.whl' `
'rocm_sdk_core-10.2.0a20260929-py3-none-win_amd64.whl' `
'9623b97ca511eaa176905075a504393eca6fde594222af10b55e4fb1edfe5a25' `
(Join-Path $localTools 'therock-10.2.0a20260929') `
(Join-Path $localTools 'therock-10.2.0a20260929/_rocm_sdk_core/bin/amdhip64_7.dll')
}
if (!(Test-Path (Join-Path $localTools 'python/cmake/data/bin/cmake.exe')) -or
!(Test-Path (Join-Path $localTools 'python/bin/ninja.exe'))) {
python -m pip install --target (Join-Path $localTools 'python') cmake==3.31.6 ninja==1.11.1.4
if ($LASTEXITCODE) { throw "pip install exit=$LASTEXITCODE" }
}
if (!(Test-Path (Join-Path $localTools 'python/vendor/numpy/__init__.py'))) {
python -m pip install --disable-pip-version-check --only-binary=:all: `
--target (Join-Path $localTools 'python/vendor') numpy==2.4.6
if ($LASTEXITCODE) { throw "NumPy reference install exit=$LASTEXITCODE" }
}
& (Join-Path $PSScriptRoot 'setup-native-engine.ps1')
if ($LASTEXITCODE) { throw "Native engine dependency setup exit=$LASTEXITCODE" }
Write-Host 'Tools ready. Run scripts/windows/build-windows-rdna4.ps1 or scripts/windows/build-native-engine.ps1.'
+30
View File
@@ -0,0 +1,30 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [string]$GpuArch)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $GpuArch
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo "build/native-k-$GpuArch" }
if (![IO.Path]::IsPathRooted($DlssDll) -or !(Test-Path -LiteralPath $DlssDll)) {
throw 'Supply the absolute path to your local nvngx_dlss.dll.'
}
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
foreach ($object in Get-ChildItem -LiteralPath $OutputDirectory -Filter '*.hsaco') {
Assert-D4RCodeObjectTarget $object.FullName $GpuArch
}
$layers = @('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0')
foreach ($layer in $layers) {
$name = "dltss_pwin_${layer}_layer"
$source = Join-Path $PackageRoot "experimental/k/${name}_${GpuArch}.hsaco"
if (!(Test-Path -LiteralPath $source)) { throw "Native K module missing: $source" }
Assert-D4RCodeObjectTarget $source $GpuArch
Copy-Item -LiteralPath $source -Destination (Join-Path $OutputDirectory "$name.hsaco") -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $OutputDirectory $DlssDll
if ($LASTEXITCODE) { throw "Native manifest generation failed ($LASTEXITCODE)" }
@{architecture=$GpuArch; family='K'; dlssSha256=(Get-FileHash -LiteralPath $DlssDll -Algorithm SHA256).Hash;
validation='staged only; GPU execution and DLSS capture/reference validation required';
modules=@(Get-ChildItem -LiteralPath $OutputDirectory -Filter '*.hsaco' | Get-FileHash -Algorithm SHA256)} |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'build-info.json') -Encoding UTF8
Write-Host "Experimental native K directory: $OutputDirectory"
+30
View File
@@ -0,0 +1,30 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DlssDll, [string]$PackageRoot, [string]$OutputDirectory, [string]$GpuArch)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $GpuArch
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo "build/native-m-$GpuArch" }
if (![IO.Path]::IsPathRooted($DlssDll) -or !(Test-Path -LiteralPath $DlssDll)) {
throw 'Supply the absolute path to your local nvngx_dlss.dll.'
}
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
foreach ($object in Get-ChildItem -LiteralPath $OutputDirectory -Filter '*.hsaco') {
Assert-D4RCodeObjectTarget $object.FullName $GpuArch
}
foreach ($layer in @('enc1','enc2','enc3_tube','dec2','dec1')) {
$name = "rrlite_${layer}_4x4"
$source = Join-Path $PackageRoot "experimental/m/${name}_${GpuArch}.hsaco"
if (!(Test-Path -LiteralPath $source)) { throw "Native M module missing: $source" }
Assert-D4RCodeObjectTarget $source $GpuArch
Copy-Item -LiteralPath $source -Destination (Join-Path $OutputDirectory "$name.hsaco") -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $OutputDirectory $DlssDll
if ($LASTEXITCODE) { throw "Native manifest generation failed ($LASTEXITCODE)" }
@{architecture=$GpuArch; family='M'; numerics='SWIN_EXACT; SWIN_EXACT_PV; FP16 widening; native FP8 disabled';
dlssSha256=(Get-FileHash -LiteralPath $DlssDll -Algorithm SHA256).Hash;
validation='staged only; GPU execution and DLSS capture/reference validation required';
modules=@(Get-ChildItem -LiteralPath $OutputDirectory -Filter '*.hsaco' | Get-FileHash -Algorithm SHA256)} |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'build-info.json') -Encoding UTF8
Write-Host "Experimental native M directory: $OutputDirectory"
+84
View File
@@ -0,0 +1,84 @@
[CmdletBinding()]
param(
[string]$NgxCore, [string]$DlssDll, [string]$NativeRoot,
[string]$ZludaRoot, [string]$PackageRoot,
[string]$Resolution = '3840x2160',
[string]$InputResolution,
[switch]$ProfileGpuBoundary,
[switch]$ProfileKernelsDeferred,
[switch]$BatchInputCopies,
[ValidateSet('baseline','packed','unorm','depth-stencil')][string]$PixelProfile = 'depth-stencil',
[string]$OutputDirectory
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$NgxCore) { $NgxCore = Join-Path $repo '_nvngx.dll' }
if (!$DlssDll) { $DlssDll = Join-Path $repo 'nvngx_dlss.dll' }
if (!$ZludaRoot) { $ZludaRoot = Join-Path $repo 'dist/zluda-windows-api-profile' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-command-list' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$NativeRoot) { $NativeRoot = Join-Path $repo "build/native-k-$GpuArch" }
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/async-k-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
if ($Resolution -notmatch '^([0-9]+)x([0-9]+)$') { throw 'Resolution must be WIDTHxHEIGHT' }
$width=$Matches[1]; $height=$Matches[2]
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$settings = @{D4R_DIAG_BURST='1'; D4R_DIAG_RECREATE=$null; D4R_ASYNC_INTEROP=$null;
D4R_BATCH_INPUT_COPIES=$null;
D4R_ZLUDA_NATIVE_DIR=$NativeRoot; D4R_QUIET_API='1'; D4R_VALIDATE_OUTPUT='1';
D4R_PROFILE_STAGES='1'; D4R_ZLUDA_PROFILE=$null; D4R_ZLUDA_PROFILE_API=$null;
D4R_ZLUDA_PROFILE_DEFERRED=$(if ($ProfileKernelsDeferred) { '1' } else { $null });
D4R_ZLUDA_PROFILE_ALLOW_LEGACY=$(if ($ProfileKernelsDeferred) { '1' } else { $null });
D4R_ZLUDA_PROFILE_EVERY=$(if ($ProfileKernelsDeferred) { '1' } else { $null });
D4R_PROFILE_GPU_BOUNDARY=$(if ($ProfileGpuBoundary) { '1' } else { $null });
ZLUDA_CACHE_DIR=(Join-Path $repo 'build/zluda-cache-windows');
PYTHONPATH=(Join-Path $repo '.tools/python/vendor')}
$old=@{}
try {
foreach ($key in $settings.Keys) {
$old[$key]=[Environment]::GetEnvironmentVariable($key,'Process')
[Environment]::SetEnvironmentVariable($key,$settings[$key],'Process')
}
foreach ($mode in @('burst','recreate')) {
[Environment]::SetEnvironmentVariable('D4R_DIAG_RECREATE', $(if ($mode -eq 'recreate') { '1' } else { $null }), 'Process')
foreach ($variant in @('sync','async')) {
[Environment]::SetEnvironmentVariable('D4R_ASYNC_INTEROP', $(if ($variant -eq 'async') { '1' } else { $null }), 'Process')
[Environment]::SetEnvironmentVariable('D4R_BATCH_INPUT_COPIES', $(if ($BatchInputCopies -and $variant -eq 'async') { '1' } else { $null }), 'Process')
$output=Join-Path $OutputDirectory "$variant-$mode"
$arguments=@{RuntimeProfile='therock'; ZludaRoot=$ZludaRoot; PackageRoot=$PackageRoot;
NgxCore=$NgxCore; DlssDll=$DlssDll; NgxOnly=$true; NgxMode='d3d12'; NgxAbi='project-legacy';
Preset=11; NgxCreateFlags=11; NgxOutputResolution=$Resolution; RequireNativeNetwork=$true;
NgxInputResolution=$InputResolution;
CommandListBackend=$true; EarlyIndirectProbe=$true; PixelProfile=$PixelProfile;
BarrierMode='inherited-legacy'; Iterations=3; CaptureExceptions=$true; TimeoutSeconds=600;
OptiScalerDll=(Join-Path $repo 'dist/optiscaler-windows-d4r/OptiScaler.dll'); OutputDirectory=$output}
& (Join-Path $PSScriptRoot 'test-windows-rdna4.ps1') @arguments
if ($LASTEXITCODE) { throw "Failed $variant-$mode; logs: $output" }
if ($ProfileKernelsDeferred) {
$stderr=Get-Content -LiteralPath (Join-Path $output 'd3d12-evaluate-preset-11.stderr.log') -Raw
if ($stderr -match '(?m)^D4R_KERNEL_PROFILE .*serializing=1') { throw 'Unexpected serializing kernel profiler.' }
foreach ($layer in @('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0')) {
$pattern='(?m)^D4R_KERNEL_PROFILE(?:_INVALID)? kernel="dltss_pwin_' + $layer + '_layer" backend=native phase=main '
$events=[regex]::Matches($stderr,$pattern)
if ($events.Count -ne 3) { throw "Expected three collected $layer events for $variant-$mode, found $($events.Count)." }
}
}
if ($ProfileGpuBoundary -and $variant -eq 'async') {
$stdout=Get-Content -LiteralPath (Join-Path $output 'd3d12-evaluate-preset-11.stdout.log') -Raw
$timings=[regex]::Matches($stdout, '(?m)^D4R_GPU_BOUNDARY [^\r\n]*diagnostics_cpu_bytes=32 serializing=0\r?$')
if ($timings.Count -ne 3) { throw "Expected three completed GPU timing records for $variant-$mode, found $($timings.Count)." }
}
}
& python.exe (Join-Path $repo 'tools/windows/frame_compare.py') --reference (Join-Path $OutputDirectory "sync-$mode") --actual (Join-Path $OutputDirectory "async-$mode") --width $width --height $height --exact |
Tee-Object -FilePath (Join-Path $OutputDirectory "$mode-comparison.log")
if ($LASTEXITCODE) { throw "Async $mode output mismatch" }
}
@{passed=$true; architecture=$GpuArch; preset=11; resolution=$Resolution;
inputResolution=$InputResolution;
modes=@('burst','recreate'); framesPerMode=3; exactRgb=$true; gpuBoundaryTiming=[bool]$ProfileGpuBoundary;
deferredKernelTiming=[bool]$ProfileKernelsDeferred; batchInputs=[bool]$BatchInputCopies; pixelProfile=$PixelProfile} |
ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'validation.json') -Encoding UTF8
Write-Host "PASS asynchronous K burst/recreate: $OutputDirectory"
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
+52
View File
@@ -0,0 +1,52 @@
param(
[int]$Iterations = 32,
[switch]$NoHooks,
[switch]$SmallSeed,
[switch]$DebugLayer,
[switch]$Warp,
[switch]$NoHip,
[ValidateSet('basic','indirect','indirect-root-reset','initial-pso')][string]$Mode = 'indirect',
[string]$OutputDirectory = 'test-results/d3d12-command-development'
)
$ErrorActionPreference = 'Stop'
$repo = (Resolve-Path "$PSScriptRoot/../..").Path
Push-Location $repo
$names = @('D4R_COMMAND_PROBE_NO_HOOKS','D4R_COMMAND_PROBE_SMALL_SEED','D4R_COMMAND_DEBUG_SDK','D4R_DIAG_DIR','D4R_COMMAND_PROBE_WARP','D4R_COMMAND_PROBE_NO_HIP')
$saved = @{}
foreach ($name in $names) { $saved[$name] = [Environment]::GetEnvironmentVariable($name,'Process') }
try {
if ($Iterations -lt 1 -or $Iterations -gt 1024) { throw 'Iterations must be 1..1024' }
$cmake = "$repo/.tools/python/cmake/data/bin/cmake.exe"
$build = "$repo/build/windows-rdna4-therock"
$hip = "$repo/.tools/therock-10.2.0a20260929/_rocm_sdk_core"
$output = [IO.Path]::GetFullPath((Join-Path $repo $OutputDirectory))
New-Item -ItemType Directory -Force -Path $output | Out-Null
$target = 'd4r_d3d12_command_probe'
if ($DebugLayer) {
$sdk = "$repo/.tools/agility-1.619.5"
if (!(Test-Path "$sdk/build/native/bin/x64/d3d12SDKLayers.dll")) { throw 'Unpack Microsoft.Direct3D.D3D12 1.619.5 into .tools/agility-1.619.5 for this optional debug probe' }
& $cmake -S . -B $build "-DD4R_AGILITY_ROOT=$sdk" > "$output/configure.log"
if ($LASTEXITCODE) { throw 'Debug probe configuration failed' }
$target = 'd4r_d3d12_command_debug_probe'
}
& $cmake --build $build --target d4r_nvngx_windows $target > "$output/build.log"
if ($LASTEXITCODE) { throw "Build failed: $output/build.log" }
[Environment]::SetEnvironmentVariable($names[0], $(if ($NoHooks) { '1' } else { $null }), 'Process')
[Environment]::SetEnvironmentVariable($names[1], $(if ($SmallSeed) { '1' } else { $null }), 'Process')
[Environment]::SetEnvironmentVariable($names[2], $(if ($DebugLayer) { '1' } else { $null }), 'Process')
[Environment]::SetEnvironmentVariable($names[3], $output, 'Process')
[Environment]::SetEnvironmentVariable($names[4], $(if ($Warp) { '1' } else { $null }), 'Process')
[Environment]::SetEnvironmentVariable($names[5], $(if ($NoHip -or $Warp) { '1' } else { $null }), 'Process')
# PowerShell 5 treats native stderr as ErrorRecord: retain it without
# converting it into a terminating exception, then check the process code.
$ErrorActionPreference = 'Continue'
& "$build/$target.exe" --hip-root $hip --module "$build/d4r_nvngx.dll" --interop-mode $Mode --iterations $Iterations > "$output/stdout.log" 2> "$output/stderr.log"
$code = $LASTEXITCODE
$ErrorActionPreference = 'Stop'
Get-Content "$output/stdout.log", "$output/stderr.log" | Select-String 'D3D12_VALIDATION|DRED|DEVICE_REMOVED|PROBE_GPU|DIFFERENT|FAIL|PASS|installed'
Write-Host "D3D12 command diagnostic logs: $output"
if ($code) { throw "D3D12 probe exit=$code" }
} finally {
foreach ($name in $names) { [Environment]::SetEnvironmentVariable($name,$saved[$name],'Process') }
Pop-Location
}
+123
View File
@@ -0,0 +1,123 @@
# d4r-check.ps1 against fixture installs. No GPU, no NVIDIA binaries: the packaging test's
# synthetic release is the install, a fake inventory file stands in for the GPU query, and
# fixture text files stand in for the NVIDIA DLLs (pinned in a fixture dll-pins.txt).
[CmdletBinding()]
param([string]$OutputDirectory)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/d4r-check/'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
& (Join-Path $PSScriptRoot 'test-windows-release-package.ps1') -OutputDirectory (Join-Path $OutputDirectory 'package') | Out-Null
$release=Join-Path $OutputDirectory 'package/release'
$check=Join-Path $repo 'scripts/windows/d4r-check.ps1'
$powershell="$env:SystemRoot/System32/WindowsPowerShell/v1.0/powershell.exe"
$results=@()
function Sha([string]$path) { (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash }
function Set-ManifestHash([string]$game,[string]$relative) {
$path=Join-Path $game 'd4r/package.json'
$manifest=Get-Content -LiteralPath $path -Raw | ConvertFrom-Json
foreach ($entry in $manifest.files) { if ($entry.path -eq $relative) { $entry.sha256=Sha (Join-Path $game ($relative -replace '/','\')) } }
$manifest | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $path -Encoding UTF8
}
function New-Install([string]$name) {
$game=Join-Path $OutputDirectory "cases/$name"
New-Item -ItemType Directory -Force (Split-Path $game) | Out-Null
Copy-Item -LiteralPath $release -Destination $game -Recurse
Set-Content -LiteralPath (Join-Path $game 'Game.exe') 'fixture' -Encoding ASCII
New-Item -ItemType Directory -Force (Join-Path $game 'd4r/dlss') | Out-Null
Set-Content -LiteralPath (Join-Path $game 'd4r/dlss/nvngx_dlss.dll') 'fixture dlss' -Encoding ASCII
Set-Content -LiteralPath (Join-Path $game 'd4r/ngx/_nvngx.dll') 'fixture core' -Encoding ASCII
$unrelated=('B'*64)
@('# fixture pins',
"dlss $(Sha (Join-Path $game 'd4r/dlss/nvngx_dlss.dll')) 310.9.1 validated",
"dlss $unrelated 310.7.0 unvalidated",
"ngx $(Sha (Join-Path $game 'd4r/ngx/_nvngx.dll')) 32.0.16.1714 validated") |
Set-Content -LiteralPath (Join-Path $game 'd4r/dll-pins.txt') -Encoding ASCII
Set-ManifestHash $game 'd4r/dll-pins.txt'
return $game
}
function Write-Inventory([string]$name,[string]$arch,[string]$gpu='AMD Radeon RX 7700 XT') {
$path=Join-Path $OutputDirectory "inventory-$name.json"
@{devices=@(@{name=$gpu; architecture=$arch; wavefrontSize=32})} | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $path -Encoding UTF8
return $path
}
function Run-Check([string]$game,[string]$inventory,[string[]]$More=@()) {
$ErrorActionPreference='Continue' # native stderr must not become a terminating error
$text=& $powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $game 'd4r/d4r-check.ps1') -GameFolder $game -InventoryFile $inventory @More 2>&1 | Out-String
return @{exit=$LASTEXITCODE; text=$text}
}
function Expect([string]$case,$run,[int]$exit,[string[]]$patterns) {
if ($run.exit -ne $exit) { throw "$case : exit $($run.exit), expected $exit`n$($run.text)" }
foreach ($pattern in $patterns) { if ($run.text -notmatch $pattern) { throw "$case : output lacks /$pattern/`n$($run.text)" } }
$script:results+=@{case=$case; passed=$true; gpuKernelsExecuted=$false}
}
# 1. Healthy install.
$game=New-Install 'healthy'; $inv=Write-Inventory 'a' 'gfx1101'
Expect 'healthy-install' (Run-Check $game $inv) 0 @('ok\s+d4r\\dlss\\nvngx_dlss\.dll \(nvngx_dlss\.dll 310\.9\.1, tested on Windows\)','ok\s+d4r\\ngx\\_nvngx\.dll',
'ok\s+GPU AMD Radeon RX 7700 XT \(gfx1101\): build present, 16 native kernels','ok\s+all 17 GPU code objects are built for gfx1101',
'ok\s+no vkd3d/Wine d3d12\.dll','ok\s+d4r\.ini is valid \(model K\)','compile-tested','Everything d4r needs is in place')
# 2. NVIDIA DLL problems, each with the fix.
$game=New-Install 'dll-missing'; Remove-Item -LiteralPath (Join-Path $game 'd4r/dlss/nvngx_dlss.dll')
Expect 'dll-missing' (Run-Check $game $inv) 1 @("MISSING\s+d4r\\dlss\\nvngx_dlss\.dll: copy NVIDIA's nvngx_dlss\.dll here \(version 310\.9\.1 or 310\.7\.0","1 thing\(s\) to fix")
$game=New-Install 'dll-wrong'; Set-Content -LiteralPath (Join-Path $game 'd4r/dlss/nvngx_dlss.dll') 'some other version' -Encoding ASCII
Expect 'dll-wrong-version' (Run-Check $game $inv) 1 @('MISSING\s+d4r\\dlss\\nvngx_dlss\.dll is version \S+, which d4r does not accept\. d4r on Windows needs exactly 310\.9\.1 or 310\.7\.0')
$game=New-Install 'dll-less-tested'; Set-Content -LiteralPath (Join-Path $game 'd4r/dlss/nvngx_dlss.dll') 'fixture dlss 310.7' -Encoding ASCII
@('dlss '+(Sha (Join-Path $game 'd4r/dlss/nvngx_dlss.dll'))+' 310.7.0 unvalidated','ngx '+(Sha (Join-Path $game 'd4r/ngx/_nvngx.dll'))+' 32.0.16.1714 validated') | Set-Content -LiteralPath (Join-Path $game 'd4r/dll-pins.txt') -Encoding ASCII
Set-ManifestHash $game 'd4r/dll-pins.txt'
Expect 'dll-less-tested-accepted' (Run-Check $game $inv) 0 @('ok\s+d4r\\dlss\\nvngx_dlss\.dll \(nvngx_dlss\.dll 310\.7\.0\)','note\s+nvngx_dlss\.dll 310\.7\.0 is accepted but has had less Windows testing')
# 3. Leftovers, edited files, a replaced dxgi.dll, and a broken OptiScaler.ini.
$game=New-Install 'vkd3d'; Set-Content -LiteralPath (Join-Path $game 'd3d12.dll') 'vkd3d-proton fixture' -Encoding ASCII
Expect 'vkd3d-proxy' (Run-Check $game $inv) 1 @('MISSING\s+d3d12\.dll in the game folder is vkd3d-proton/Wine')
$game=New-Install 'dxgi-replaced'; Set-Content -LiteralPath (Join-Path $game 'dxgi.dll') 'another dxgi' -Encoding ASCII
Expect 'foreign-dxgi' (Run-Check $game $inv) 0 @('note\s+dxgi\.dll is not the one that came with d4r')
$game=New-Install 'opti-path'; (Get-Content -LiteralPath (Join-Path $game 'OptiScaler.ini')) -replace '^NvngxPath=.*$','NvngxPath=nowhere' | Set-Content -LiteralPath (Join-Path $game 'OptiScaler.ini') -Encoding ASCII
Expect 'optiscaler-ini-path' (Run-Check $game $inv) 1 @('MISSING\s+OptiScaler\.ini NvngxPath = nowhere does not hold _nvngx\.dll')
# 4. d4r.ini mistakes are notes with what will happen instead.
$game=New-Install 'ini'; Set-Content -LiteralPath (Join-Path $game 'd4r/d4r.ini') "[DLSS]`nModel = E`nShowWatermark = sometimes`n[Latency]`nFrameAge = 1`n[Debug]`nLog = loud`n" -Encoding ASCII
Expect 'ini-mistakes' (Run-Check $game $inv) 0 @("note\s+d4r\.ini: \[DLSS\] Model 'E' is not available on Windows",'must be true or false, not ''sometimes''','\[Latency\] FrameAge is not a Windows setting','Log must be normal or verbose')
# 5. GPU cases.
$game=New-Install 'gpu-no-build'; Remove-Item -LiteralPath (Join-Path $game 'd4r/_nvngx_gfx1103.dll')
Expect 'gpu-without-build' (Run-Check $game (Write-Inventory 'b' 'gfx1103' 'AMD Radeon 780M')) 1 @('MISSING\s+GPU AMD Radeon 780M \(gfx1103\): this release has no complete build for it \(missing: d4r\\_nvngx_gfx1103\.dll\)')
$game=New-Install 'gpu-rdna2'
Expect 'gpu-unsupported' (Run-Check $game (Write-Inventory 'c' 'gfx1030' 'AMD Radeon RX 6800')) 1 @('MISSING\s+no supported RDNA3/RDNA4 GPU found by the AMD runtime\. It sees: AMD Radeon RX 6800 \(gfx1030\)')
$game=New-Install 'gpu-wrong-object'
$other=@(Get-ChildItem -LiteralPath (Join-Path $game 'd4r/native/gfx1100') -Filter '*.hsaco')[0].FullName
Copy-Item -LiteralPath $other -Destination (Join-Path $game 'd4r/native/gfx1101/kernel3.hsaco') -Force
Expect 'code-object-for-another-gpu' (Run-Check $game $inv) 1 @('MISSING\s+kernel3\.hsaco is not built for gfx1101','differs from the release')
# 6. What the last game start said, and the bug-report ZIP.
$game=New-Install 'log-failure'
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: DLSS disabled: Wrong nvngx_dlss.dll: you have version 1.2.3.4" -Encoding ASCII
Expect 'log-reports-failure' (Run-Check $game $inv) 1 @('MISSING\s+last game start: DLSS disabled: Wrong nvngx_dlss\.dll')
$game=New-Install 'log-ok'
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: player mode, model=K validate=0 async=0 log=normal, architecture=gfx1101" -Encoding ASCII
Expect 'log-reports-ok' (Run-Check $game $inv) 0 @('ok\s+last game start: player mode, model=K')
$game=New-Install 'report'; $reportDir=Join-Path $OutputDirectory 'reports'; New-Item -ItemType Directory -Force $reportDir | Out-Null
Set-Content -LiteralPath (Join-Path $game 'd4r/d4r_nvngx.log') "d4r: DLSS disabled: test failure" -Encoding ASCII
$run=Run-Check $game $inv @('-Report','-ReportDirectory',$reportDir)
$zip=@(Get-ChildItem -LiteralPath $reportDir -Filter 'd4r-report-*.zip')
if ($zip.Count -ne 1) { throw "Expected one report ZIP.`n$($run.text)" }
Add-Type -AssemblyName System.IO.Compression.FileSystem
$archive=[IO.Compression.ZipFile]::OpenRead($zip[0].FullName)
try { $names=@($archive.Entries | ForEach-Object { $_.Name }) } finally { $archive.Dispose() }
foreach ($required in @('check.txt','d4r_nvngx.log','d4r.ini','OptiScaler.ini','files.sha256.txt','gpu-inventory.json')) { if ($names -notcontains $required) { throw "Report lacks $required (has: $($names -join ', '))" } }
if ($names -contains 'nvngx_dlss.dll' -or $names -contains '_nvngx.dll') { throw 'The report must never contain NVIDIA DLLs.' }
if ($run.text -notmatch 'Bug report written') { throw 'Report location was not printed.' }
$results+=@{case='bug-report-zip'; passed=$true; entries=$names}
# 7. No d4r folder at all.
$empty=Join-Path $OutputDirectory 'cases/empty'; New-Item -ItemType Directory -Force $empty | Out-Null
$ErrorActionPreference='Continue'
$text=& $powershell -NoProfile -ExecutionPolicy Bypass -File $check -GameFolder $empty 2>&1 | Out-String
$exitEmpty=$LASTEXITCODE; $ErrorActionPreference='Stop'
if ($exitEmpty -ne 1 -or $text -notmatch 'no d4r folder here') { throw "A folder without d4r must be reported.`n$text" }
$results+=@{case='no-d4r-folder'; passed=$true}
$results | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "PASS D4R_CHECK cases=$($results.Count) Report: $OutputDirectory"
@@ -0,0 +1,103 @@
[CmdletBinding()]
param([string]$ZludaRoot, [string]$PackageRoot, [string]$HipRoot, [string]$OutputDirectory)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ZludaRoot) { $ZludaRoot = Join-Path $repo 'dist/zluda-windows-deferred-profile' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-command-list' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/deferred-profile-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$settings = @{
D4R_ZLUDA_PROFILE=$null; D4R_ZLUDA_PROFILE_DEFERRED='1'; D4R_ZLUDA_PROFILE_EVERY='1';
D4R_ZLUDA_PROFILE_ALLOW_LEGACY=$null;
D4R_DIAG_NONBLOCKING_STREAM='1'; D4R_DIAG_QUEUE_PTX=$null;
D4R_DIAG_DIR=$OutputDirectory;
ZLUDA_CACHE_DIR=(Join-Path $repo 'build/zluda-cache-windows');
PATH=((Join-Path $HipRoot 'bin') + ';' + $ZludaRoot + ';' + $env:PATH)
}
$old=@{}; $cases=@()
function RunProbe([string[]]$Arguments, [string]$Stdout, [string]$Stderr) {
$info=[Diagnostics.ProcessStartInfo]::new()
$info.FileName=Join-Path $PackageRoot 'bin/d4r_cuda_driver_probe.exe'
$info.Arguments=$Arguments -join ' '
$info.UseShellExecute=$false; $info.CreateNoWindow=$true
$info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
$p=[Diagnostics.Process]::new(); $p.StartInfo=$info
$outFile=$null; $errFile=$null; $outTask=$null; $errTask=$null
try {
if (!$p.Start()) { throw 'Could not launch the CUDA diagnostic.' }
$outFile=[IO.File]::Open($Stdout,[IO.FileMode]::Create,[IO.FileAccess]::Write,[IO.FileShare]::Read)
$errFile=[IO.File]::Open($Stderr,[IO.FileMode]::Create,[IO.FileAccess]::Write,[IO.FileShare]::Read)
$outTask=$p.StandardOutput.BaseStream.CopyToAsync($outFile)
$errTask=$p.StandardError.BaseStream.CopyToAsync($errFile)
$timer=[Diagnostics.Stopwatch]::StartNew()
while (!$p.WaitForExit(1000)) {
if ($timer.Elapsed.TotalSeconds -ge 120) { throw "CUDA diagnostic timed out; logs: $OutputDirectory" }
}
$p.WaitForExit()
[void]$outTask.GetAwaiter().GetResult(); [void]$errTask.GetAwaiter().GetResult()
return $p.ExitCode
} finally {
if (!$p.HasExited) { $p.Kill(); $p.WaitForExit() }
if ($outTask) { try { [void]$outTask.GetAwaiter().GetResult() } catch {} }
if ($errTask) { try { [void]$errTask.GetAwaiter().GetResult() } catch {} }
if ($outFile) { $outFile.Dispose() }; if ($errFile) { $errFile.Dispose() }
$p.Dispose()
}
}
try {
foreach ($key in $settings.Keys) {
$old[$key]=[Environment]::GetEnvironmentVariable($key,'Process')
[Environment]::SetEnvironmentVariable($key,$settings[$key],'Process')
}
foreach ($context in @('primary','created')) {
foreach ($queued in @($false,$true)) {
$name="$context-$(if ($queued) { 'queued' } else { 'single' })"
[Environment]::SetEnvironmentVariable('D4R_DIAG_QUEUE_PTX', $(if ($queued) { '1' } else { $null }), 'Process')
$iterations=129
$stdout=Join-Path $OutputDirectory "$name.stdout.log"
$stderr=Join-Path $OutputDirectory "$name.stderr.log"
# Native Windows argument parsing: quote absolute paths explicitly.
$arguments=@('--hip-root', ('"' + $HipRoot + '"'), '--cuda-dll', ('"' + (Join-Path $ZludaRoot 'nvcuda.dll') + '"'),
'--context', $context, '--iterations', "$iterations")
$exitCode=RunProbe $arguments $stdout $stderr
if ($exitCode) { throw "$name failed ($exitCode); logs: $OutputDirectory" }
$out=Get-Content -LiteralPath $stdout -Raw
$err=Get-Content -LiteralPath $stderr -Raw
if ($out -notmatch "PASS CUDA architecture=$GpuArch" -or $out -notmatch 'guard_verified=1') { throw "$name did not verify PTX output" }
$records=[regex]::Matches($err, '(?m)^D4R_KERNEL_PROFILE kernel="d4r_ptx_pattern" [^\r\n]*serializing=0 deferred=1 [^\r\n]+')
$invalid=[regex]::Matches($err, '(?m)^D4R_KERNEL_PROFILE_INVALID kernel="d4r_ptx_pattern" [^\r\n]*reason=invalid_elapsed_time serializing=0 deferred=1 [^\r\n]+')
if ($records.Count + $invalid.Count -ne $iterations -or $err -match 'serializing=1|D4R_KERNEL_PROFILE_SKIPPED') {
throw "$name expected $iterations collected deferred records, found $($records.Count) valid / $($invalid.Count) invalid"
}
foreach ($record in $records) {
if ($record.Value -notmatch 'gpu_ms=([0-9.]+)') {
throw "$name contains an invalid GPU time"
}
$gpuMs=[double]::Parse($Matches[1], [Globalization.CultureInfo]::InvariantCulture)
if ([double]::IsNaN($gpuMs) -or [double]::IsInfinity($gpuMs)) { throw "$name contains an invalid GPU time" }
}
$cases += @{context=$context; queued=$queued; launches=$iterations; collected=($records.Count+$invalid.Count);
validTimings=$records.Count; invalidTimings=$invalid.Count; exitCode=$exitCode}
Write-Host "PASS ${name}: $($records.Count) valid / $($invalid.Count) invalid deferred timings; exact PTX output and guards"
}
}
# Legacy default-stream timing markers would add stream dependencies.
[Environment]::SetEnvironmentVariable('D4R_DIAG_NONBLOCKING_STREAM',$null,'Process')
[Environment]::SetEnvironmentVariable('D4R_DIAG_QUEUE_PTX',$null,'Process')
$stdout=Join-Path $OutputDirectory 'default-stream.stdout.log'; $stderr=Join-Path $OutputDirectory 'default-stream.stderr.log'
$arguments=@('--hip-root', ('"' + $HipRoot + '"'), '--cuda-dll', ('"' + (Join-Path $ZludaRoot 'nvcuda.dll') + '"'), '--iterations', '3')
$exitCode=RunProbe $arguments $stdout $stderr
$out=Get-Content -LiteralPath $stdout -Raw; $err=Get-Content -LiteralPath $stderr -Raw
if ($exitCode -or $out -notmatch "PASS CUDA architecture=$GpuArch" -or
$err -notmatch 'reason=legacy_default_stream' -or $err -match '(?m)^D4R_KERNEL_PROFILE ') {
throw 'Default-stream diagnostics did not safely skip timing events.'
}
@{passed=$true; architecture=$GpuArch; cases=$cases; defaultStreamSkipped=$true; addedCompletionWaits=0} |
ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'validation.json') -Encoding UTF8
Write-Host "PASS deferred kernel profiling: $OutputDirectory"
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
+44
View File
@@ -0,0 +1,44 @@
[CmdletBinding()]
param([string]$LogRoot, [string]$OutputDirectory)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'game-summary.ps1')
$cases=@(
@{name='empty-streams-debugger-refused'; preset=11; stdout=''; stderr=''; debugger='EXIT code=0xdeadc0de'; session='process-failed-before-dlss-frames'},
@{name='launcher-exit'; preset=11; stdout=''; stderr=''; debugger='EXIT code=0x0'; session='process-exited-without-dlss-frames'},
@{name='feature-not-found'; preset=11; stdout='D4R_CAPABILITIES available=0 feature_init=0xbad00004 needs_driver=0'; stderr='D4R_WINDOWS_FAILURE unavailable'; debugger='EXIT code=0xc0000409'; session='ngx-feature-not-found'},
@{name='complete-frame-k'; preset=11; native=1; kernel='dltss_pwin_enc0_layer'; stdout="D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms=12.4`nD4R_OUTPUT_VALIDATION elements=3 nan=0 inf=0 diagnostics_cpu_bytes=8";
stderr='[d4r-launch] kernel="dltss_pwin_enc0_layer" backend=native'; debugger='EXIT code=0x0'; session='completed-dlss-frames'},
@{name='complete-frame-e'; preset=5; native=0; kernel=$null; stdout="D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms=14.2`nD4R_OUTPUT_VALIDATION elements=3 nan=0 inf=0 diagnostics_cpu_bytes=8";
stderr=''; debugger='EXIT code=0x0'; session='completed-dlss-frames'},
@{name='complete-frame-l'; preset=12; native=1; kernel='rrlite_enc1_4x4'; stdout="D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms=18.4`nD4R_OUTPUT_VALIDATION elements=3 nan=0 inf=0 diagnostics_cpu_bytes=8";
stderr='[d4r-launch] kernel="rrlite_enc1_4x4" backend=native'; debugger='EXIT code=0x0'; session='completed-dlss-frames'},
@{name='truncated-frame'; preset=13; stdout='D4R_FRAME cpu_frame_copies=0 frame_age=0 interop_ngx_ms='; stderr=''; debugger=''; session='diagnostic-timeout-without-dlss-frames'}
)
$results=@()
foreach ($case in $cases) {
$summary=Get-D4RGameSummary -Stdout $case.stdout -Stderr $case.stderr -Debugger $case.debugger -Preset $case.preset
if ($summary.session -ne $case.session) { throw "Wrong session classification: $($case.name)" }
if ($case.name -like 'complete-frame-*') {
$kernelCount=if ($case.kernel) { @($summary.kernels | Where-Object kernel -eq $case.kernel).Count } else { 0 }
if ($summary.completedFrames -ne 1 -or $summary.outputGpuChecks -ne 1 -or $summary.nativeLaunches -ne $case.native -or
$kernelCount -ne $case.native -or $summary.preset -ne $case.preset -or
$summary.nonfiniteOutputs -or $summary.previousFrameOutputs -or $summary.cpuImageCopyFrames) { throw 'Complete frame counters are wrong.' }
} elseif ($summary.completedFrames -ne 0) { throw 'A failed or incomplete run was counted as a frame.' }
$results+=@{case=$case.name; passed=$true; summary=$summary}
}
if ($LogRoot) {
foreach ($entry in @{ 'acbf-k'='process-failed-before-dlss-frames'; 'cyberpunk-k'='ngx-feature-not-found';
'cyberpunk-m'='ngx-feature-not-found'; 'sm2-k'='process-exited-without-dlss-frames' }.GetEnumerator()) {
$dir=Get-ChildItem -LiteralPath (Join-Path $LogRoot $entry.Key) -Directory | Select-Object -First 1
$summary=Get-D4RGameSummary -Stdout ([IO.File]::ReadAllText((Join-Path $dir.FullName 'd4r.stdout.log'))) `
-Stderr ([IO.File]::ReadAllText((Join-Path $dir.FullName 'd4r.stderr.log'))) `
-Debugger ([IO.File]::ReadAllText((Join-Path $dir.FullName 'debugger.log')))
if ($summary.session -ne $entry.Value -or $summary.completedFrames -ne 0 -or $summary.nativeLaunches -ne 0) { throw "Unexpected classification for actual report $($entry.Key)" }
$results+=@{case='issue-10-'+$entry.Key; passed=$true; summary=$summary}
}
}
if ($OutputDirectory) {
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$results | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary-parser.json') -Encoding UTF8
}
Write-Host "PASS GAME_SUMMARY cases=$($results.Count)"
@@ -0,0 +1,23 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$PackageRoot, [Parameter(Mandatory=$true)][string]$CodeObject)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$target=Get-D4RGpuTarget $PackageRoot $null
$other=if ($target -eq 'gfx1201') { 'gfx1200' } else { 'gfx1201' }
function Expect-Rejection([scriptblock]$Action) {
$rejected=$false
try { & $Action | Out-Null } catch { $rejected=$true }
if (!$rejected) { throw 'GPU target contract accepted incompatible input.' }
}
if ((Get-D4RGpuTarget $PackageRoot $target) -ne $target) { throw 'Incorrect package target.' }
Assert-D4RCodeObjectTarget $CodeObject $target
Expect-Rejection { Get-D4RGpuTarget $PackageRoot $other }
Expect-Rejection { Get-D4RGpuTarget $PackageRoot 'gfx1250' }
Expect-Rejection { Assert-D4RCodeObjectTarget $CodeObject $other }
Expect-Rejection { Assert-D4RCodeObjectTarget (Join-Path $PackageRoot 'gpu-target.json') $target }
# Old packages had no target metadata and were gfx1201 only.
$legacy=Join-Path $PackageRoot '__no-target-metadata__'
if (Test-Path -LiteralPath (Join-Path $legacy 'gpu-target.json')) { throw 'Unexpected legacy test fixture.' }
if ((Get-D4RGpuTarget $legacy $null) -ne 'gfx1201') { throw 'Legacy target changed.' }
Expect-Rejection { Get-D4RGpuTarget $legacy 'gfx1200' }
Write-Host "PASS GPU_TARGET_SCRIPT target=$target rejected=5 hardware_executed=0"
+54
View File
@@ -0,0 +1,54 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$CaptureDirectory, [string]$HipRoot,
[string]$PackageRoot, [string]$OutputDirectory, [int]$Windows = 12,
[Parameter(Mandatory=$true)][string]$DlssDll, [int]$PtxWindows = 2)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/k-real-reference-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$previousPython = $env:PYTHONPATH
$previousDiag = $env:D4R_DIAG_DIR
$env:PYTHONPATH = "$(Join-Path $repo '.tools/python/vendor');$previousPython"
$summary = [ordered]@{utc=[DateTime]::UtcNow.ToString('o'); captureDirectory=$CaptureDirectory; layers=@(); passed=$false}
try {
foreach ($layer in @('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0')) {
$name = "dltss_pwin_${layer}_layer"
$captures = @(Get-ChildItem -LiteralPath $CaptureDirectory -Directory | Where-Object Name -Match ("^replay-[0-9]+-" + $name + '$'))
if (!$captures.Count) { throw "Missing actual K capture: $name" }
$capture = $captures | Sort-Object Name | Select-Object -First 1
$folder = Join-Path $OutputDirectory $layer
$output = Join-Path $folder 'output'
New-Item -ItemType Directory -Force $folder | Out-Null
$env:D4R_DIAG_DIR = $folder
& (Join-Path $PackageRoot 'bin/d4r_native_replay_probe.exe') --hip-root $HipRoot `
--module (Join-Path $PackageRoot "experimental/k/${name}_${GpuArch}.hsaco") `
--fixture-dir $capture.FullName --output-dir $output --iterations 1 `
> (Join-Path $folder 'gpu.stdout.log') 2> (Join-Path $folder 'gpu.stderr.log')
if ($LASTEXITCODE) { throw "K $layer actual GPU replay failed: $folder" }
& python (Join-Path $PackageRoot 'k_replay_validate.py') validate --layer $layer `
--fixture-dir $capture.FullName --output-dir $output --windows $Windows --real-capture `
> (Join-Path $folder 'reference.stdout.log') 2> (Join-Path $folder 'reference.stderr.log')
if ($LASTEXITCODE) { throw "K $layer mismatch; stopping before the next layer: $folder" }
Get-Content -LiteralPath (Join-Path $folder 'reference.stdout.log') | Write-Host
$ptxValidator = Join-Path $PackageRoot 'k_ptx_validate.py'
if (!(Test-Path -LiteralPath $ptxValidator)) { $ptxValidator = Join-Path $repo 'tools/windows/k_ptx_validate.py' }
& python -u $ptxValidator --layer $layer `
--capture-dir $capture.FullName --native-dir $output --dlss-dll $DlssDll `
--output-dir (Join-Path $folder 'private-ptx') --windows $PtxWindows `
> (Join-Path $folder 'ptx-reference.stdout.log') 2> (Join-Path $folder 'ptx-reference.stderr.log')
if ($LASTEXITCODE) { throw "K $layer independent PTX mismatch; stopping: $folder" }
Get-Content -LiteralPath (Join-Path $folder 'ptx-reference.stdout.log') | Write-Host
$summary.layers += @{layer=$layer; passed=$true}
}
$summary.passed = $true
} catch { $summary.error=$_.Exception.Message; Write-Warning $summary.error }
finally {
$env:PYTHONPATH = $previousPython; $env:D4R_DIAG_DIR = $previousDiag
$summary | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "Private real-weight replay results: $OutputDirectory (do not redistribute captures/allocations)"
}
if (!$summary.passed) { exit 1 }
+55
View File
@@ -0,0 +1,55 @@
[CmdletBinding()]
param(
[string]$HipRoot,
[string]$PackageRoot,
[string]$OutputDirectory,
[string[]]$Layers = @('enc0','enc1','enc2','enc3','enc4','dec5','dec4','dec3','dec2','dec1','dec0'),
[int]$Iterations = 32
)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/k-replay-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$previousPython = $env:PYTHONPATH
$previousDiag = $env:D4R_DIAG_DIR
$env:PYTHONPATH = "$(Join-Path $repo '.tools/python/vendor');$previousPython"
$summary = [ordered]@{utc=[DateTime]::UtcNow.ToString('o'); hipRoot=$HipRoot; architecture=$GpuArch; layers=@(); passed=$false}
try {
if ($Iterations -lt 1 -or $Iterations -gt 10000) { throw 'Iterations must be 1..10000' }
foreach ($layer in $Layers) {
if ($layer -notmatch '^(enc[0-4]|dec[0-5])$') { throw "Invalid K layer $layer" }
$folder = Join-Path $OutputDirectory $layer
$fixture = Join-Path $folder 'fixture'
$output = Join-Path $folder 'output'
New-Item -ItemType Directory -Force $folder | Out-Null
$env:D4R_DIAG_DIR = $folder
& python (Join-Path $PackageRoot 'k_replay_validate.py') generate --layer $layer --fixture-dir $fixture `
> (Join-Path $folder 'fixture.stdout.log') 2> (Join-Path $folder 'fixture.stderr.log')
if ($LASTEXITCODE) { throw "K $layer fixture generation failed; see $folder" }
& (Join-Path $PackageRoot 'bin/d4r_native_replay_probe.exe') --hip-root $HipRoot `
--module (Join-Path $PackageRoot "experimental/k/dltss_pwin_${layer}_layer_${GpuArch}.hsaco") `
--fixture-dir $fixture --output-dir $output --iterations $Iterations `
> (Join-Path $folder 'gpu.stdout.log') 2> (Join-Path $folder 'gpu.stderr.log')
if ($LASTEXITCODE) { throw "K $layer GPU replay failed; see $folder" }
& python (Join-Path $PackageRoot 'k_replay_validate.py') validate --layer $layer --fixture-dir $fixture --output-dir $output `
> (Join-Path $folder 'reference.stdout.log') 2> (Join-Path $folder 'reference.stderr.log')
if ($LASTEXITCODE) { throw "K $layer reference mismatch; stopping before the next layer. See $folder" }
Get-Content -LiteralPath (Join-Path $folder 'reference.stdout.log') | Write-Host
$summary.layers += @{layer=$layer; passed=$true; iterations=$Iterations}
}
$summary.passed = $true
} catch {
$summary.error = $_.Exception.Message
Write-Warning $summary.error
} finally {
$env:PYTHONPATH = $previousPython
$env:D4R_DIAG_DIR = $previousDiag
$summary | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath "$OutputDirectory.zip" -Force
Write-Host "K replay bundle: $OutputDirectory.zip"
}
if (!$summary.passed) { exit 1 }
+51
View File
@@ -0,0 +1,51 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$CaptureDirectory, [string]$HipRoot,
[string]$PackageRoot, [string]$OutputDirectory, [int]$Blocks = 12,
[Parameter(Mandatory=$true)][string]$DlssDll, [int]$PtxBlocks = 2)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/m-real-reference-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$previousPython=$env:PYTHONPATH; $previousDiag=$env:D4R_DIAG_DIR
$env:PYTHONPATH = "$(Join-Path $repo '.tools/python/vendor');$previousPython"
$summary = [ordered]@{utc=[DateTime]::UtcNow.ToString('o'); captureDirectory=$CaptureDirectory; layers=@(); passed=$false}
try {
foreach ($layer in @('enc1','enc2','enc3_tube','dec2','dec1')) {
$name = "rrlite_${layer}_4x4"
$captures = @(Get-ChildItem -LiteralPath $CaptureDirectory -Directory | Where-Object Name -Match ("^replay-[0-9]+-" + $name + '$'))
if (!$captures.Count) { throw "Missing actual M capture: $name" }
$capture = $captures | Sort-Object Name | Select-Object -First 1
$folder = Join-Path $OutputDirectory $layer
$output = Join-Path $folder 'output'
New-Item -ItemType Directory -Force $folder | Out-Null
$env:D4R_DIAG_DIR = $folder
& (Join-Path $PackageRoot 'bin/d4r_native_replay_probe.exe') --hip-root $HipRoot `
--module (Join-Path $PackageRoot "experimental/m/${name}_${GpuArch}.hsaco") `
--fixture-dir $capture.FullName --output-dir $output --iterations 1 `
> (Join-Path $folder 'gpu.stdout.log') 2> (Join-Path $folder 'gpu.stderr.log')
if ($LASTEXITCODE) { throw "M $layer actual GPU replay failed: $folder" }
& python (Join-Path $PackageRoot 'm_replay_validate.py') validate --layer $layer `
--fixture-dir $capture.FullName --output-dir $output --blocks $Blocks --real-capture `
> (Join-Path $folder 'reference.stdout.log') 2> (Join-Path $folder 'reference.stderr.log')
if ($LASTEXITCODE) { throw "M $layer mismatch; stopping before the next layer: $folder" }
Get-Content -LiteralPath (Join-Path $folder 'reference.stdout.log') | Write-Host
& python -u (Join-Path $PackageRoot 'm_ptx_validate.py') --layer $layer `
--capture-dir $capture.FullName --native-dir $output --dlss-dll $DlssDll `
--output-dir (Join-Path $folder 'private-ptx') --blocks $PtxBlocks `
> (Join-Path $folder 'ptx-reference.stdout.log') 2> (Join-Path $folder 'ptx-reference.stderr.log')
if ($LASTEXITCODE) { throw "M $layer independent PTX mismatch; stopping: $folder" }
Get-Content -LiteralPath (Join-Path $folder 'ptx-reference.stdout.log') | Write-Host
$summary.layers += @{layer=$layer; passed=$true}
}
$summary.passed=$true
} catch { $summary.error=$_.Exception.Message; Write-Warning $summary.error }
finally {
$env:PYTHONPATH=$previousPython; $env:D4R_DIAG_DIR=$previousDiag
$summary | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "Private real-weight replay results: $OutputDirectory (do not redistribute captures/allocations)"
}
if (!$summary.passed) { exit 1 }
+47
View File
@@ -0,0 +1,47 @@
[CmdletBinding()]
param([string]$HipRoot, [string]$PackageRoot, [string]$OutputDirectory,
[string[]]$Layers = @('enc1','enc2','enc3_tube','dec2','dec1'),
[ValidateRange(1,10000)][int]$Iterations = 32)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/m-replay-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$previousPython = $env:PYTHONPATH
$previousDiag = $env:D4R_DIAG_DIR
$env:PYTHONPATH = "$(Join-Path $repo '.tools/python/vendor');$previousPython"
$summary = [ordered]@{utc=[DateTime]::UtcNow.ToString('o'); hipRoot=$HipRoot; architecture=$GpuArch; layers=@(); passed=$false}
try {
foreach ($layer in $Layers) {
if ($layer -notmatch '^(enc[12]|enc3_tube|dec[12])$') { throw "Invalid M layer $layer" }
$folder = Join-Path $OutputDirectory $layer
$fixture = Join-Path $folder 'fixture'
$output = Join-Path $folder 'output'
New-Item -ItemType Directory -Force $folder | Out-Null
$env:D4R_DIAG_DIR = $folder
& python (Join-Path $PackageRoot 'm_replay_validate.py') generate --layer $layer --fixture-dir $fixture `
> (Join-Path $folder 'fixture.stdout.log') 2> (Join-Path $folder 'fixture.stderr.log')
if ($LASTEXITCODE) { throw "M $layer fixture generation failed: $folder" }
& (Join-Path $PackageRoot 'bin/d4r_native_replay_probe.exe') --hip-root $HipRoot `
--module (Join-Path $PackageRoot "experimental/m/rrlite_${layer}_4x4_${GpuArch}.hsaco") `
--fixture-dir $fixture --output-dir $output --iterations $Iterations `
> (Join-Path $folder 'gpu.stdout.log') 2> (Join-Path $folder 'gpu.stderr.log')
if ($LASTEXITCODE) { throw "M $layer GPU replay failed: $folder" }
& python (Join-Path $PackageRoot 'm_replay_validate.py') validate --layer $layer --fixture-dir $fixture --output-dir $output `
> (Join-Path $folder 'reference.stdout.log') 2> (Join-Path $folder 'reference.stderr.log')
if ($LASTEXITCODE) { throw "M $layer reference mismatch; stopping before the next layer: $folder" }
Get-Content -LiteralPath (Join-Path $folder 'reference.stdout.log') | Write-Host
$summary.layers += @{layer=$layer; passed=$true; iterations=$Iterations}
}
$summary.passed = $true
} catch { $summary.error=$_.Exception.Message; Write-Warning $summary.error }
finally {
$env:PYTHONPATH=$previousPython; $env:D4R_DIAG_DIR=$previousDiag
$summary | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Compress-Archive -LiteralPath $OutputDirectory -DestinationPath "$OutputDirectory.zip" -Force
Write-Host "M replay bundle: $OutputDirectory.zip"
}
if (!$summary.passed) { exit 1 }
+28
View File
@@ -0,0 +1,28 @@
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$CaptureDirectory,
[Parameter(Mandatory=$true)][string]$BaselineValidation,
[string]$ModuleDirectory, [string]$HipRoot, [string]$OutputDirectory, [switch]$Benchmark)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ModuleDirectory) { $ModuleDirectory=Join-Path $repo 'build/native-m-fp8-experimental' }
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo 'test-results/m-native-fp8-replay' }
$previousPython=$env:PYTHONPATH
try {
$env:PYTHONPATH="$(Join-Path $repo '.tools/python/vendor');$previousPython"
$metadata=Get-Content -LiteralPath (Join-Path $ModuleDirectory 'build-info.json') -Raw | ConvertFrom-Json
if ($metadata.hardwarePacking) {
& python -u (Join-Path $repo 'tools/windows/fp8_pack_validate.py') `
--probe (Join-Path $repo 'dist/windows-rdna4-command-list/bin/d4r_native_replay_probe.exe') `
--module (Join-Path $ModuleDirectory 'packing-probe/fp8_pack_probe.hsaco') `
--hip-root $HipRoot --output-dir (Join-Path $OutputDirectory 'packing-check')
if ($LASTEXITCODE) { throw 'Hardware packing does not preserve every finite FP8 encoding; stopping before network replay.' }
}
$benchmarkArguments=@()
if ($Benchmark) { $benchmarkArguments=@('--benchmark-control-dir',(Join-Path $repo 'build/native-m-gfx1201')) }
& python -u (Join-Path $repo 'tools/windows/m_native_replay_compare.py') `
--capture-dir $CaptureDirectory --module-dir $ModuleDirectory --hip-root $HipRoot `
--probe (Join-Path $repo 'dist/windows-rdna4-command-list/bin/d4r_native_replay_probe.exe') `
--baseline-validation $BaselineValidation --output-dir $OutputDirectory @benchmarkArguments
if ($LASTEXITCODE) { throw "Experimental FP8 validation failed; baseline unchanged. Logs: $OutputDirectory" }
} finally { $env:PYTHONPATH=$previousPython }
+52
View File
@@ -0,0 +1,52 @@
[CmdletBinding()]
param([string]$HipRoot, [string]$PackageRoot, [string]$ZludaRoot, [string]$OutputDirectory)
$ErrorActionPreference = 'Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$HipRoot) { $HipRoot = Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$PackageRoot) { $PackageRoot = Join-Path $repo 'dist/windows-rdna4-therock' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$ZludaRoot) { $ZludaRoot = Join-Path $repo 'dist/zluda-windows-final' }
if (!$OutputDirectory) { $OutputDirectory = Join-Path $repo ('test-results/native-identity-' + (Get-Date -Format 'yyyyMMdd-HHmmss')) }
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$previous = @{D4R_ZLUDA_NATIVE_DIR=$env:D4R_ZLUDA_NATIVE_DIR; D4R_ZLUDA_VERBOSE=$env:D4R_ZLUDA_VERBOSE; D4R_DIAG_DIR=$env:D4R_DIAG_DIR}
function Invoke-NativeProbe([string]$Name) {
$info = New-Object Diagnostics.ProcessStartInfo
$info.FileName = Join-Path $PackageRoot 'bin/d4r_cuda_driver_probe.exe'
$info.Arguments = '--hip-root "' + $HipRoot + '" --cuda-dll "' + (Join-Path $ZludaRoot 'nvcuda.dll') + '" --iterations 32'
$info.UseShellExecute=$false; $info.CreateNoWindow=$true; $info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
$process = New-Object Diagnostics.Process
$process.StartInfo=$info
if (!$process.Start()) { throw 'Cannot start native override probe' }
$stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
if (!$process.WaitForExit(120000)) { $process.Kill(); $process.WaitForExit(); throw 'Native override test timed out' }
[IO.File]::WriteAllText((Join-Path $OutputDirectory "$Name.stdout.log"),$stdout.GetAwaiter().GetResult())
[IO.File]::WriteAllText((Join-Path $OutputDirectory "$Name.stderr.log"),$stderr.GetAwaiter().GetResult())
$code=$process.ExitCode; $process.Dispose()
return $code
}
try {
$env:D4R_ZLUDA_VERBOSE = '1'; $env:D4R_DIAG_DIR = $OutputDirectory
$bad = Join-Path $OutputDirectory 'wrong-identity'
$good = Join-Path $OutputDirectory 'matching-identity'
New-Item -ItemType Directory -Force $bad,$good | Out-Null
foreach ($directory in @($bad,$good)) {
Copy-Item -LiteralPath (Join-Path $PackageRoot "bin/probe_${GpuArch}.hsaco") -Destination (Join-Path $directory 'd4r_ptx_pattern.hsaco') -Force
}
'd4r_ptx_pattern 0000000000000000' | Set-Content -LiteralPath (Join-Path $bad 'd4r-kernels.txt') -Encoding ASCII
$env:D4R_ZLUDA_NATIVE_DIR = $bad
if (Invoke-NativeProbe 'wrong') { throw 'Wrong identity must use the correct translated fallback' }
if (!(Select-String -LiteralPath (Join-Path $OutputDirectory 'wrong.stderr.log') -Pattern 'reason=ptx_identity.*fallback=translated' -Quiet)) {
throw 'Wrong identity was not explicitly rejected'
}
$identity = Select-String -LiteralPath (Join-Path $OutputDirectory 'wrong.stdout.log') -Pattern 'fnv1a64=([0-9a-f]{16})'
if (!$identity) { throw 'PTX probe did not report its identity' }
"d4r_ptx_pattern $($identity.Matches[0].Groups[1].Value)" | Set-Content -LiteralPath (Join-Path $good 'd4r-kernels.txt') -Encoding ASCII
$env:D4R_ZLUDA_NATIVE_DIR = $good
if (Invoke-NativeProbe 'matching') { throw 'Matching native override produced incorrect output' }
$hits = @(Select-String -LiteralPath (Join-Path $OutputDirectory 'matching.stderr.log') -Pattern '\[d4r-launch\].*backend=native')
if ($hits.Count -ne 32) { throw "Expected 32 native launches, got $($hits.Count)" }
Write-Host 'PASS NATIVE_IDENTITY wrong_hash=fallback matching_hash=native launches=32'
} finally {
foreach ($name in $previous.Keys) { [Environment]::SetEnvironmentVariable($name,$previous[$name],'Process') }
}
+94
View File
@@ -0,0 +1,94 @@
[CmdletBinding()]
param([string]$TextureRoot, [string]$ControlTextureRoot, [string]$CommonTextureRoot, [string]$ZludaRoot, [string]$PackageRoot,
[string]$OutputDirectory, [int]$Iterations=8, [string]$OutputResolution='512x288', [string]$InputResolution,
[switch]$CandidateFirst,
[ValidateSet('output','input')][string]$KernelStage='output')
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$PackageRoot) { $PackageRoot=Join-Path $repo 'dist/windows-rdna4-command-list' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$TextureRoot) { $TextureRoot=Join-Path $repo "build/private-textures-$GpuArch" }
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo 'test-results/k-native-texture-reference' }
if ($OutputResolution -notmatch '^([0-9]+)x([0-9]+)$') { throw 'OutputResolution must be WIDTHxHEIGHT.' }
$outputWidth=[int]$Matches[1]; $outputHeight=[int]$Matches[2]
$combined=Join-Path $OutputDirectory 'private-native'
New-Item -ItemType Directory -Force $combined | Out-Null
foreach ($directory in @((Join-Path $repo "build/native-k-$GpuArch"),$CommonTextureRoot,$TextureRoot) | Where-Object { $_ }) {
Get-ChildItem -LiteralPath $directory -Filter '*.hsaco' | Copy-Item -Destination $combined -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $combined (Join-Path $repo 'nvngx_dlss.dll')
if ($LASTEXITCODE) { throw 'Combined private manifest failed.' }
$controlNative=Join-Path $repo "build/native-k-$GpuArch"
if ($ControlTextureRoot -or $CommonTextureRoot) {
$controlNative=Join-Path $OutputDirectory 'control-private-native'
New-Item -ItemType Directory -Force $controlNative | Out-Null
foreach ($directory in @((Join-Path $repo "build/native-k-$GpuArch"),$CommonTextureRoot,$ControlTextureRoot) | Where-Object { $_ }) {
Get-ChildItem -LiteralPath $directory -Filter '*.hsaco' | Copy-Item -Destination $controlNative -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $controlNative (Join-Path $repo 'nvngx_dlss.dll')
if ($LASTEXITCODE) { throw 'Control private manifest failed.' }
}
$settings=@{D4R_VALIDATE_OUTPUT='1'; D4R_PROFILE_STAGES='1'; D4R_ZLUDA_PROFILE='1'; D4R_QUIET_API='1';
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0';
D4R_ZLUDA_WMMA_F16_REFERENCE='1'; D4R_ZLUDA_PROFILE_DEFERRED=$null;
ZLUDA_CACHE_DIR=(Join-Path $repo 'build/zluda-cache-windows'); PYTHONPATH=(Join-Path $repo '.tools/python/vendor');
D4R_ZLUDA_NATIVE_DIR=$null}
$old=@{}
$stagedObjects=@{}
foreach ($stage in @(@{name='control'; root=$controlNative},@{name='candidate'; root=$combined})) {
$stagedObjects[$stage.name]=@{}
foreach ($object in Get-ChildItem -LiteralPath $stage.root -Filter '*.hsaco') {
Assert-D4RCodeObjectTarget $object.FullName $GpuArch
$stagedObjects[$stage.name][$object.Name]=(Get-FileHash -LiteralPath $object.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
}
try {
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
foreach ($flags in @(0,11)) {
$variant=if ($flags -eq 11) { 'depthinv_mvlo_hdr' } else { 'depthreg_mvhi_ldr' }
$suffix=if ($KernelStage -eq 'output') { '_max_v2_rel' } else { '_v2_rel' }
$kernel="hiluma_engine_${KernelStage}_${variant}${suffix}"
$order=if ($CandidateFirst) { @('candidate','control') } else { @('control','candidate') }
foreach ($mode in $order) {
$env:D4R_ZLUDA_NATIVE_DIR=if ($mode -eq 'control') { $controlNative } else { $combined }
$expectedBackend=if (Test-Path -LiteralPath (Join-Path $env:D4R_ZLUDA_NATIVE_DIR ($kernel + '.hsaco'))) { 'native' } else { 'translated' }
if ($mode -eq 'candidate' -and $expectedBackend -ne 'native') { throw "Missing candidate object: $kernel" }
$arguments=@{RuntimeProfile='therock'; ZludaRoot=$ZludaRoot;
PackageRoot=$PackageRoot; NgxCore=(Join-Path $repo '_nvngx.dll');
DlssDll=(Join-Path $repo 'nvngx_dlss.dll'); NgxMode='d3d12'; NgxAbi='project-legacy'; Preset=11;
NgxCreateFlags=$flags; NgxOutputResolution=$OutputResolution; NgxOnly=$true; RequireNativeNetwork=$true; CommandListBackend=$true;
NgxInputResolution=$InputResolution;
PixelProfile='depth-stencil'; BarrierMode='inherited-legacy'; CaptureExceptions=$true; EarlyIndirectProbe=$true;
Iterations=$Iterations; TimeoutSeconds=300; OptiScalerDll=(Join-Path $repo 'dist/optiscaler-windows-d4r/OptiScaler.dll');
OutputDirectory=(Join-Path $OutputDirectory "$mode-$flags")}
& (Join-Path $PSScriptRoot 'test-windows-rdna4.ps1') @arguments
if ($LASTEXITCODE) { throw "Texture $mode flags=$flags workload failed." }
& python (Join-Path $repo 'tools/windows/profile_report.py') $arguments.OutputDirectory --output (Join-Path $arguments.OutputDirectory 'profile.json')
if ($LASTEXITCODE) { throw 'Texture profile report failed.' }
$profile=Get-Content -LiteralPath (Join-Path $arguments.OutputDirectory 'profile.json') -Raw | ConvertFrom-Json
$samples=@($profile.kernels | Where-Object { $_.kernel -eq $kernel -and $_.backend -eq $expectedBackend -and $_.phase -eq 'main' -and $_.serializing })
if ($samples.Count -ne 1 -or $samples[0].gpuMs.samples -ne $Iterations) {
throw "Missing valid serializing $KernelStage-kernel timings ($expectedBackend) for $mode flags=$flags; retain this run as correctness evidence only."
}
}
$control=Join-Path $OutputDirectory "control-$flags"; $candidate=Join-Path $OutputDirectory "candidate-$flags"
$stderr=Get-Content -LiteralPath (Join-Path $candidate 'd3d12-evaluate-preset-11.stderr.log') -Raw
$hits=[regex]::Matches($stderr, ('\[d4r-launch\] kernel="' + $kernel + '" backend=native')).Count
if ($hits -ne $Iterations) { throw "Texture override was not executed on every frame: $kernel hits=$hits" }
& python (Join-Path $repo 'tools/windows/frame_compare.py') --reference $control --actual $candidate --width $outputWidth --height $outputHeight --exact
if ($LASTEXITCODE) { throw "Texture flags=$flags full-frame RGB mismatch; preserve baseline." }
}
@{passed=$true; architecture=$GpuArch; framesPerVariant=$Iterations; outputResolution=$OutputResolution; createFlags=@(0,11); strictRgb=$true;
inputResolution=$InputResolution;
serializingProfile=$true; candidateFirst=[bool]$CandidateFirst; kernelStage=$KernelStage;
controlTextureRoot=$ControlTextureRoot; commonTextureRoot=$CommonTextureRoot;
stagedObjects=$stagedObjects;
manifestSha256=(Get-FileHash -LiteralPath (Join-Path $TextureRoot 'd4r-kernels.txt') -Algorithm SHA256).Hash.ToLowerInvariant();
privateNvidiaDerivedCode=$true; source=(Get-Content -LiteralPath (Join-Path $TextureRoot 'build-info.json') -Raw | ConvertFrom-Json)} |
ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $TextureRoot 'validation.json') -Encoding UTF8
Write-Host "PASS: both private K $KernelStage variants executed and matched every RGB component. $OutputDirectory"
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
+160
View File
@@ -0,0 +1,160 @@
# Reproduce numeric NGX feature discovery without launching or modifying a game.
# The private NVIDIA DLL staging directory is deleted; reports contain logs only.
[CmdletBinding()]
param([Parameter(Mandatory=$true)][string]$DiagnosticRoot,
[Parameter(Mandatory=$true)][string]$HipRoot,
[Parameter(Mandatory=$true)][string]$ZludaRoot,
[Parameter(Mandatory=$true)][string]$NativeRoot,
[Parameter(Mandatory=$true)][string]$OptiScalerDll,
[Parameter(Mandatory=$true)][string]$NgxCore,
[Parameter(Mandatory=$true)][string]$DlssDll,
[Parameter(Mandatory=$true)][string]$OutputDirectory,
[UInt64]$ApplicationId=100152211)
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
foreach ($name in @('DiagnosticRoot','HipRoot','ZludaRoot','NativeRoot','OptiScalerDll','NgxCore','DlssDll')) {
Set-Variable -Name $name -Value ((Get-Item -LiteralPath (Get-Variable -Name $name -ValueOnly)).FullName)
}
$arch=Get-D4RGpuTarget $DiagnosticRoot
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$runtime=Join-Path ([IO.Path]::GetTempPath()) ('d4r-feature-layout-'+[Guid]::NewGuid().ToString('N'))
$settings=@{HIP_PATH=$HipRoot; PATH="$HipRoot\bin;$ZludaRoot;$env:PATH";
D4R_NVAPI_BACKEND=(Join-Path $ZludaRoot 'nvapi64.dll'); ZLUDA_CUDA_LIB=(Join-Path $ZludaRoot 'nvcuda.dll');
D4R_ZLUDA_NATIVE_DIR=$NativeRoot; D4R_ZLUDA_VERBOSE='1';
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_F16_REFERENCE='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0';
D4R_VALIDATE_OUTPUT='1'; D4R_DIAG_DIR=$null; ZLUDA_LOG_DIR=$null; D4R_FORMAT_MODULE=$null;
D4R_ASYNC_INTEROP=$null; D4R_BATCH_INPUT_COPIES=$null; D4R_D3D12_COMMAND_BACKEND=$null}
$old=@{}; $results=@()
try {
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
foreach ($dir in @('app','d4r','d4r/vendor','d4r/dlss')) { New-Item -ItemType Directory -Force (Join-Path $runtime $dir) | Out-Null }
$exe=Join-Path $runtime 'app/d4r_d3d12_dlss_probe.exe'
$shim=Join-Path $runtime 'd4r/_nvngx.dll'
$core=Join-Path $runtime 'd4r/ngx/_nvngx.dll'
$feature=Join-Path $runtime 'd4r/vendor/nvngx_dlss.dll'
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot 'bin/d4r_d3d12_dlss_probe.exe') -Destination $exe
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot 'bin/d4r_nvngx.dll') -Destination $shim
Copy-Item -LiteralPath (Join-Path $DiagnosticRoot "bin/pixel_convert_${arch}.hsaco") -Destination (Split-Path $shim)
Copy-Item -LiteralPath $NgxCore -Destination $core
Copy-Item -LiteralPath $DlssDll -Destination $feature
$opti=Join-Path $runtime 'app/OptiScaler.dll'
Copy-Item -LiteralPath $OptiScalerDll -Destination $opti
$cases=@(@{name='vendor-only-negative'; preset=11; frontend='d4r'; expectedExit=4},
@{name='optiscaler-vendor-only-negative'; preset=11; frontend='optiscaler'; expectedExit=4},
@{name='caller-dll-k'; preset=11; frontend='d4r'; expectedExit=0},
@{name='optiscaler-caller-k'; preset=11; frontend='optiscaler'; expectedExit=0},
@{name='optiscaler-caller-m'; preset=13; frontend='optiscaler'; expectedExit=0})
foreach ($case in $cases) {
$out=Join-Path $OutputDirectory $case.name
New-Item -ItemType Directory -Force $out | Out-Null
if ($case.expectedExit -eq 0) {
$feature=Join-Path $runtime 'd4r/dlss/nvngx_dlss.dll'
if (!(Test-Path -LiteralPath $feature)) { Copy-Item -LiteralPath $DlssDll -Destination $feature }
}
$env:D4R_DIAG_DIR=$out; $env:ZLUDA_LOG_DIR=Join-Path $out 'zluda-trace'
$env:D4R_FORMAT_MODULE=Join-Path $runtime "d4r/pixel_convert_${arch}.hsaco"
$module=if ($case.frontend -eq 'optiscaler') { $opti } else { $shim }
if ($case.frontend -eq 'optiscaler') {
@"
[Upscalers]
Dx12Upscaler=dlss
[FrameGen]
Enabled=false
FGInput=nofg
FGOutput=nofg
[DLSS]
Enabled=true
AllowExternalBackend=true
RenderPresetOverride=true
RenderPresetForAll=$($case.preset)
UseGenericAppIdWithDlss=false
[Libraries]
NvngxPath=$(Split-Path $shim)
NvngxDlssPath=$(Split-Path $feature)
NvngxFeaturePath=$(Split-Path $feature)
[Hotfix]
RestoreComputeSignature=false
RestoreGraphicSignature=false
ExtendedStateRestore=false
[Log]
LogToFile=true
LogLevel=0
[Menu]
DisableSplash=true
"@ | Set-Content -LiteralPath (Join-Path $runtime 'app/OptiScaler.ini') -Encoding UTF8
}
$arguments=@('--hip-root',$HipRoot,'--cuda-dll',(Join-Path $ZludaRoot 'nvcuda.dll'),
'--module',$module,'--ngx-core',$core,'--dlss-dll',$feature,
'--nvapi-dll',(Join-Path $DiagnosticRoot 'nvapi-compat/nvapi64.dll'),
'--ngx-app-id',"$ApplicationId",'--ngx-abi','driver','--ngx-frontend',$case.frontend,
'--interop-mode','command-list','--iterations','3','--preset',"$($case.preset)")
$info=New-Object Diagnostics.ProcessStartInfo
# Capture harness faults outside OptiScaler's loader hooks. Games use
# the no-debug launcher by default; this developer reproducer is separate.
$arguments=@('--output-directory',$out,'--',$exe)+$arguments
$info.FileName=Join-Path $DiagnosticRoot 'bin/d4r_debug_launcher.exe'; $info.WorkingDirectory=Split-Path $exe
$info.Arguments=(@($arguments | ForEach-Object { if ($_.Contains('"')) { throw 'Unsupported quote in test path.' }; '"'+$_+'"' }) -join ' ')
$info.UseShellExecute=$false; $info.CreateNoWindow=$true; $info.RedirectStandardOutput=$true; $info.RedirectStandardError=$true
foreach ($key in $settings.Keys) { if (![Environment]::GetEnvironmentVariable($key,'Process')) { $info.EnvironmentVariables.Remove($key) } }
$process=New-Object Diagnostics.Process; $process.StartInfo=$info
try {
[void]$process.Start(); $stdout=$process.StandardOutput.ReadToEndAsync(); $stderr=$process.StandardError.ReadToEndAsync()
if (!$process.WaitForExit(240000)) { $process.Kill(); $process.WaitForExit(); throw "NGX layout test timed out: $($case.name)" }
$log=$stdout.GetAwaiter().GetResult(); $errorLog=$stderr.GetAwaiter().GetResult()
[IO.File]::WriteAllText((Join-Path $out 'stdout.log'),$log)
[IO.File]::WriteAllText((Join-Path $out 'stderr.log'),$errorLog)
if ($process.ExitCode -ne $case.expectedExit) { throw "Unexpected exit $($process.ExitCode): $($case.name), see $out" }
if ($case.expectedExit) {
if ($log -notmatch 'D4R_CAPABILITIES available=0 feature_init=0xbad00004' -or $log -match 'D4R_FRAME ') { throw 'Old vendor-only layout did not reproduce FeatureNotFound.' }
if ($case.frontend -eq 'optiscaler' -and $errorLog -notmatch 'FAIL D3D12_DLSS D3D12 Init NGX=') { throw 'OptiScaler swallowed the numeric backend initialization failure.' }
} else {
if ($log -notmatch 'D4R_CAPABILITIES available=1 feature_init=0x00000001 needs_driver=0' -or
([regex]::Matches($log,'D3D12_OUTPUT preset=\d+ frame=\d+ finite=1')).Count -ne 3 -or
([regex]::Matches($log,'D4R_OUTPUT_VALIDATION elements=\d+ nan=0 inf=0 diagnostics_cpu_bytes=8')).Count -ne 3 -or
$log -notmatch 'PASS D3D12_DLSS .*fast_path_cpu_copies=0 frame_age=0' -or $errorLog -match 'D4R_WINDOWS_FAILURE') { throw 'Corrected feature layout did not complete finite zero-copy frames.' }
$required=@(Get-Content -LiteralPath (Join-Path $NativeRoot 'd4r-kernels.txt') | Where-Object {
if ($case.preset -eq 11) { $_ -match '^dltss_pwin_' } else { $_ -match '^rrlite_' }
} | ForEach-Object { $_.Split(' ')[0] })
if ($required.Count -ne $(if ($case.preset -eq 11) { 11 } else { 5 })) { throw 'Incomplete native manifest.' }
foreach ($kernel in $required) {
if ($errorLog -notmatch ('\[d4r-launch\] kernel="'+[regex]::Escape($kernel)+'" backend=native') -or
$errorLog -match ('\[d4r-launch\] kernel="'+[regex]::Escape($kernel)+'" backend=translated')) { throw "Missing native network execution: $kernel" }
}
if ($case.frontend -eq 'd4r' -and $log -notmatch 'D3D12_REQUIREMENTS warp_supported=0 enumeration_success=1') { throw 'WARP adapter enumeration regression failed.' }
}
$results+=@{case=$case.name; passed=$true; expectedExit=$case.expectedExit; application=$ApplicationId; preset=$case.preset; architecture=$arch}
Write-Host "PASS NGX_FEATURE_LAYOUT $($case.name)"
} finally {
if ($case.frontend -eq 'optiscaler') {
Get-ChildItem -LiteralPath (Split-Path $exe) -Filter '*.log' -File | ForEach-Object {
Copy-Item -LiteralPath $_.FullName -Destination $out -Force
}
}
$process.Dispose()
}
}
for ($frame=0; $frame -lt 3; $frame++) {
$direct=[IO.File]::ReadAllBytes((Join-Path $OutputDirectory "caller-dll-k/output-$frame.rgba16f"))
$frontend=[IO.File]::ReadAllBytes((Join-Path $OutputDirectory "optiscaler-caller-k/output-$frame.rgba16f"))
if ($direct.Length -ne $frontend.Length -or $direct.Length -ne 512*288*8) { throw 'RGB comparison dimensions differ.' }
for ($pixel=0; $pixel -lt $direct.Length; $pixel+=8) {
if (([BitConverter]::ToUInt64($direct,$pixel) -band [UInt64]0xffffffffffff) -ne
([BitConverter]::ToUInt64($frontend,$pixel) -band [UInt64]0xffffffffffff)) { throw "K frontend RGB mismatch: frame=$frame offset=$pixel" }
}
}
$results+=@{case='k-direct-optiscaler-rgb'; passed=$true; frames=3; rgbByteExact=$true; maxAbsoluteError=0; maxRelativeError=0}
Write-Host 'PASS NGX_FEATURE_LAYOUT k_direct_optiscaler_rgb exact=1 max_abs=0 max_rel=0'
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
$results | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'feature-layout.json') -Encoding UTF8
$resolved=[IO.Path]::GetFullPath($runtime)
$temp=[IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\')+'\'
if (!$resolved.StartsWith($temp,[StringComparison]::OrdinalIgnoreCase) -or [IO.Path]::GetFileName($resolved) -notmatch '^d4r-feature-layout-[0-9a-f]{32}$') { throw 'Refusing cleanup outside private NGX staging.' }
if (Test-Path -LiteralPath $resolved) {
foreach ($attempt in 1..10) {
try { Remove-Item -LiteralPath $resolved -Recurse -Force; break }
catch { if ($attempt -eq 10) { throw }; Start-Sleep -Milliseconds 300 }
}
}
}
+92
View File
@@ -0,0 +1,92 @@
# Drag-in player mode checks. Builds with the vendored llvm-mingw; needs no
# NVIDIA DLLs and launches no GPU kernels. The loader case enumerates HIP
# devices and is skipped (reported, not passed) without a supported AMD GPU.
[CmdletBinding()]
param(
[string]$CompilerRoot, [string]$HipRoot, [string]$OutputDirectory
)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$CompilerRoot) { $CompilerRoot=Join-Path $repo '.tools/llvm-mingw-20260922-ucrt-x86_64' }
if (!$HipRoot) { $HipRoot=Join-Path $repo '.tools/therock-10.2.0a20260929/_rocm_sdk_core' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/player-config/'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
$cxx=Join-Path $CompilerRoot 'bin/x86_64-w64-mingw32-clang++.exe'
if (!(Test-Path -LiteralPath $cxx)) { throw "llvm-mingw not found: $cxx" }
if (!(Test-Path -LiteralPath (Join-Path $HipRoot 'include/hip/hip_runtime_api.h'))) { throw "HIP headers not found under $HipRoot" }
# Same generated target table as CMakeLists.txt.
$targets=(Get-Content -LiteralPath (Join-Path $repo 'tools/windows/gpu-targets.json') -Raw | ConvertFrom-Json).targets
$generated=Join-Path $OutputDirectory 'generated'
New-Item -ItemType Directory -Force $generated | Out-Null
$entries=($targets | ForEach-Object { " GpuTarget{`"$($_.architecture)`", $($_.elfMachine), $($_.isaMajor), `"$($_.family)`"}," }) -join "`n"
@('#pragma once','#include <array>','namespace d4r::diag {',
'struct GpuTarget { const char* architecture; unsigned elf_machine; unsigned isa_major; const char* family; };',
"inline constexpr std::array<GpuTarget, $($targets.Count)> gpu_targets = {{",$entries,'}};','}') |
Set-Content -LiteralPath (Join-Path $generated 'gpu_targets.generated.h') -Encoding ASCII
$common=@('-std=c++17','-O1','-static','-DWIN32_LEAN_AND_MEAN','-DNOMINMAX','-D__HIP_PLATFORM_AMD__','-DD4R_TARGET_ARCH="gfx1201"',
'-I',$generated,'-I',(Join-Path $repo 'tools/windows'),'-I',(Join-Path $repo 'tools'),'-I',(Join-Path $HipRoot 'include'))
# Windows PowerShell turns native stderr into terminating errors under Stop;
# judge native tools by exit code and keep their output in the log.
function Invoke-Native([string]$Log,[string]$Exe,[string[]]$Arguments) {
$ErrorActionPreference='Continue'
& $Exe @Arguments *> $Log
return $LASTEXITCODE
}
function Build([string]$Name,[string[]]$Arguments) {
$log=Join-Path $OutputDirectory "build-$Name.log"
# PowerShell 5 / Legacy native passing strips embedded quotes. PowerShell
# 7's Standard/Windows passing preserves them and must not double-escape.
if ($PSVersionTable.PSVersion.Major -le 5 -or $PSNativeCommandArgumentPassing -eq 'Legacy') {
$Arguments=@($Arguments | ForEach-Object { $_.Replace('"','\"') })
}
if (Invoke-Native $log $cxx $Arguments) { throw "Build failed: $Name; see $log" }
}
$results=@()
# 1. d4r.ini validation and DLL pin decisions (the shim's own header).
$probe=Join-Path $OutputDirectory 'player_config_probe.exe'
Build 'player-config' ($common+@('-municode',(Join-Path $repo 'tools/windows/player_config_probe.cpp'),'-o',$probe,'-lversion','-ldbghelp','-lbcrypt'))
if (Invoke-Native (Join-Path $OutputDirectory 'player-config.log') $probe @((Join-Path $OutputDirectory 'pins-fixture'))) { throw "player_config_probe failed; see $(Join-Path $OutputDirectory 'player-config.log')" }
$results+=@{case='d4r-ini-and-dll-pins'; passed=$true}
# 2. Loader: GPU-free marker, LUID-based target selection, forwarding, and a
# clear failure when the folder has no build for the detected GPU.
$folder=Join-Path $OutputDirectory 'game/d4r'
New-Item -ItemType Directory -Force (Join-Path $folder 'hip/bin') | Out-Null
Build 'loader' ($common+@('-shared',(Join-Path $repo 'tools/windows/d4r_nvngx_loader.cpp'),'-o',(Join-Path $folder '_nvngx.dll'),'-lversion','-ldbghelp'))
$harness=Join-Path $OutputDirectory 'loader_selection_probe.exe'
Build 'harness' @('-municode','-static',(Join-Path $repo 'tools/windows/loader_selection_probe.cpp'),'-o',$harness,'-ldxgi','-ldxguid')
$stub=Join-Path $OutputDirectory 'stub.cpp'
@('#define API extern "C" __declspec(dllexport)',
'struct Req { unsigned FeatureSupported, MinHWArchitecture; char MinOSVersion[255]; };',
'API unsigned NVSDK_NGX_D3D12_GetFeatureRequirements(void*, const void*, Req* r) { r->FeatureSupported = 0; r->MinHWArchitecture = 0x5101; return 1; }') |
Set-Content -LiteralPath $stub -Encoding ASCII
$stubDll=Join-Path $OutputDirectory 'stub.dll'
Build 'stub' @('-shared','-static',$stub,'-o',$stubDll)
foreach ($name in @('amdhip64_7.dll','amd_comgr.dll','rocm_kpack.dll')) {
$source=Join-Path $HipRoot "bin/$name"
if (Test-Path -LiteralPath $source) { Copy-Item -LiteralPath $source -Destination (Join-Path $folder 'hip/bin') }
}
$log=Join-Path $OutputDirectory 'loader-without-builds.log'
[void](Invoke-Native $log $harness @((Join-Path $folder '_nvngx.dll')))
$text=Get-Content -LiteralPath $log -Raw
if ($text -notmatch 'MARKER version=1 hip_loaded=0') { throw "Discovery marker loaded HIP or failed; see $log" }
if ($text -match 'supported=0') { throw "An adapter was reported supported without any target build; see $log" }
$gpuLog=Join-Path $folder 'd4r_nvngx.log'
$detected=$null
if (Test-Path -LiteralPath $gpuLog) { $detected=[regex]::Match((Get-Content -LiteralPath $gpuLog -Raw),'no build for your GPU \((gfx[0-9a-f]+)\)').Groups[1].Value }
if (!$detected) {
$results+=@{case='loader-selection'; passed=$null; skipped='no supported AMD HIP device detected'}
Write-Host 'SKIP loader selection: no supported AMD HIP device detected on this machine.' -ForegroundColor Yellow
} else {
if ((Get-Content -LiteralPath $gpuLog -Raw) -notmatch 'It supports: none \(the d4r folder is incomplete') { throw "Unclear unsupported-GPU message; see $gpuLog" }
Copy-Item -LiteralPath $stubDll -Destination (Join-Path $folder "_nvngx_$detected.dll")
$log=Join-Path $OutputDirectory 'loader-with-build.log'
[void](Invoke-Native $log $harness @((Join-Path $folder '_nvngx.dll')))
if ((Get-Content -LiteralPath $log -Raw) -notmatch 'vendor=0x1002 status=0x1 supported=0 marker=0x5101') { throw "AMD adapter was not forwarded to _nvngx_$detected.dll; see $log" }
$results+=@{case='loader-selection'; passed=$true; architecture=$detected; gpuKernelsExecuted=$false}
}
$results | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "PASS PLAYER_CONFIG cases=$(@($results | Where-Object { $_.passed }).Count) skipped=$(@($results | Where-Object { $_.skipped }).Count) Report: $OutputDirectory"
+96
View File
@@ -0,0 +1,96 @@
[CmdletBinding()]
param([string]$TextureRoot, [string]$ControlTextureRoot, [string]$CommonTextureRoot, [string]$ZludaRoot, [string]$PackageRoot,
[string]$OutputDirectory, [int]$Iterations=8, [string]$OutputResolution='512x288', [string]$InputResolution,
[switch]$CandidateFirst,
[ValidateSet('output','input')][string]$KernelStage='output')
$ErrorActionPreference='Stop'
. (Join-Path $PSScriptRoot 'gpu-target.ps1')
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$PackageRoot) { $PackageRoot=Join-Path $repo 'dist/windows-rdna4-command-list' }
$GpuArch=Get-D4RGpuTarget $PackageRoot $null
if (!$TextureRoot) { $TextureRoot=Join-Path $repo "build/private-textures-$GpuArch" }
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-final' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo 'test-results/k-native-texture-reference' }
if ($OutputResolution -notmatch '^([0-9]+)x([0-9]+)$') { throw 'OutputResolution must be WIDTHxHEIGHT.' }
$outputWidth=[int]$Matches[1]; $outputHeight=[int]$Matches[2]
$combined=Join-Path $OutputDirectory 'private-native'
New-Item -ItemType Directory -Force $combined | Out-Null
foreach ($directory in @((Join-Path $repo "build/native-k-$GpuArch"),$CommonTextureRoot,$TextureRoot) | Where-Object { $_ }) {
Get-ChildItem -LiteralPath $directory -Filter '*.hsaco' | Copy-Item -Destination $combined -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $combined (Join-Path $repo 'nvngx_dlss.dll')
if ($LASTEXITCODE) { throw 'Combined private manifest failed.' }
$controlNative=Join-Path $repo "build/native-k-$GpuArch"
if ($ControlTextureRoot -or $CommonTextureRoot) {
$controlNative=Join-Path $OutputDirectory 'control-private-native'
New-Item -ItemType Directory -Force $controlNative | Out-Null
foreach ($directory in @((Join-Path $repo "build/native-k-$GpuArch"),$CommonTextureRoot,$ControlTextureRoot) | Where-Object { $_ }) {
Get-ChildItem -LiteralPath $directory -Filter '*.hsaco' | Copy-Item -Destination $controlNative -Force
}
& python (Join-Path $repo 'kernels/tools/kernel_manifest.py') $controlNative (Join-Path $repo 'nvngx_dlss.dll')
if ($LASTEXITCODE) { throw 'Control private manifest failed.' }
}
$settings=@{D4R_VALIDATE_OUTPUT='1'; D4R_PROFILE_STAGES='1'; D4R_ZLUDA_PROFILE='1'; D4R_QUIET_API='1';
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0';
D4R_ZLUDA_WMMA_F16_REFERENCE='1'; D4R_ZLUDA_PROFILE_DEFERRED=$null;
ZLUDA_CACHE_DIR=(Join-Path $repo 'build/zluda-cache-windows'); PYTHONPATH=(Join-Path $repo '.tools/python/vendor');
D4R_ZLUDA_NATIVE_DIR=$null}
$old=@{}
$stagedObjects=@{}
foreach ($stage in @(@{name='control'; root=$controlNative},@{name='candidate'; root=$combined})) {
$stagedObjects[$stage.name]=@{}
foreach ($object in Get-ChildItem -LiteralPath $stage.root -Filter '*.hsaco') {
Assert-D4RCodeObjectTarget $object.FullName $GpuArch
$stagedObjects[$stage.name][$object.Name]=(Get-FileHash -LiteralPath $object.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
}
try {
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
foreach ($flags in @(11)) {
$variant=if ($flags -eq 11) { 'depthinv_mvlo_hdr' } else { 'depthreg_mvhi_ldr' }
$suffix=if ($KernelStage -eq 'output') { '_max_v2_rel' } else { '_v2_rel' }
$kernel="hiluma_engine_${KernelStage}_${variant}${suffix}"
$order=if ($CandidateFirst) { @('candidate','control') } else { @('control','candidate') }
foreach ($mode in $order) {
$env:D4R_ZLUDA_NATIVE_DIR=if ($mode -eq 'control') { $controlNative } else { $combined }
$expectedBackend=if (Test-Path -LiteralPath (Join-Path $env:D4R_ZLUDA_NATIVE_DIR ($kernel + '.hsaco'))) { 'native' } else { 'translated' }
if ($mode -eq 'candidate' -and $expectedBackend -ne 'native') { throw "Missing candidate object: $kernel" }
$arguments=@{RuntimeProfile='therock'; ZludaRoot=$ZludaRoot;
PackageRoot=$PackageRoot; NgxCore=(Join-Path $repo '_nvngx.dll');
DlssDll=(Join-Path $repo 'nvngx_dlss.dll'); NgxMode='d3d12'; NgxAbi='project-legacy'; Preset=11;
NgxCreateFlags=$flags; NgxOutputResolution=$OutputResolution; NgxOnly=$true; RequireNativeNetwork=$true; CommandListBackend=$true;
NgxInputResolution=$InputResolution;
PixelProfile='depth-stencil'; BarrierMode='inherited-legacy'; CaptureExceptions=$true; EarlyIndirectProbe=$true;
Iterations=$Iterations; TimeoutSeconds=1200; OptiScalerDll=(Join-Path $repo 'dist/optiscaler-windows-d4r/OptiScaler.dll');
OutputDirectory=(Join-Path $OutputDirectory "$mode-$flags")}
& (Join-Path $PSScriptRoot 'test-windows-rdna4.ps1') @arguments
if ($LASTEXITCODE) { throw "Texture $mode flags=$flags workload failed." }
& python (Join-Path $repo 'tools/windows/profile_report.py') $arguments.OutputDirectory --output (Join-Path $arguments.OutputDirectory 'profile.json')
if ($LASTEXITCODE) { throw 'Texture profile report failed.' }
$profile=Get-Content -LiteralPath (Join-Path $arguments.OutputDirectory 'profile.json') -Raw | ConvertFrom-Json
$samples=@($profile.kernels | Where-Object { $_.kernel -eq $kernel -and $_.backend -eq $expectedBackend -and $_.phase -eq 'main' -and $_.serializing })
if ($samples.Count -ne 1 -or $samples[0].gpuMs.samples -ne $Iterations) {
throw "Missing valid serializing $KernelStage-kernel timings ($expectedBackend) for $mode flags=$flags; retain this run as correctness evidence only."
}
}
$control=Join-Path $OutputDirectory "control-$flags"; $candidate=Join-Path $OutputDirectory "candidate-$flags"
$stderr=Get-Content -LiteralPath (Join-Path $candidate 'd3d12-evaluate-preset-11.stderr.log') -Raw
$hits=[regex]::Matches($stderr, ('\[d4r-launch\] kernel="' + $kernel + '" backend=native')).Count
if ($hits -ne $Iterations) { throw "Texture override was not executed on every frame: $kernel hits=$hits" }
& python (Join-Path $repo 'tools/windows/frame_compare.py') --reference $control --actual $candidate --width $outputWidth --height $outputHeight --exact
if ($LASTEXITCODE) { throw "Texture flags=$flags full-frame RGB mismatch; preserve baseline." }
}
@{passed=$true; architecture=$GpuArch; framesPerVariant=$Iterations; outputResolution=$OutputResolution; createFlags=@(0,11); strictRgb=$true;
inputResolution=$InputResolution;
serializingProfile=$true; candidateFirst=[bool]$CandidateFirst; kernelStage=$KernelStage;
controlTextureRoot=$ControlTextureRoot; commonTextureRoot=$CommonTextureRoot;
stagedObjects=$stagedObjects;
manifestSha256=(Get-FileHash -LiteralPath (Join-Path $TextureRoot 'd4r-kernels.txt') -Algorithm SHA256).Hash.ToLowerInvariant();
privateNvidiaDerivedCode=$true; source=(Get-Content -LiteralPath (Join-Path $TextureRoot 'build-info.json') -Raw | ConvertFrom-Json)} |
ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $TextureRoot 'validation.json') -Encoding UTF8
Write-Host "PASS: both private K $KernelStage variants executed and matched every RGB component. $OutputDirectory"
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
@@ -0,0 +1,82 @@
# Offline installer fixture. Uses locally supplied NVIDIA DLLs and never writes to a game folder.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$NgxCore,
[Parameter(Mandatory=$true)][string]$DlssDll,
[Parameter(Mandatory=$true)][string]$DlssdDll,
[string]$OutputDirectory
)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/windows-dlss-installer/'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
if (Test-Path -LiteralPath $OutputDirectory) { throw "Use a new output directory: $OutputDirectory" }
$NgxCore=(Get-Item -LiteralPath $NgxCore -ErrorAction Stop).FullName
$DlssDll=(Get-Item -LiteralPath $DlssDll -ErrorAction Stop).FullName
$DlssdDll=(Get-Item -LiteralPath $DlssdDll -ErrorAction Stop).FullName
$expected=@{
'_nvngx.dll'='66767018c36b3bab46398dade3adf173daa3730fda75965689ea848c9bc4e79b'
'nvngx_dlss.dll'='3975567b8943c53acce397f2b72380092f84f162d00b0d2c7d08a1025c563983'
'nvngx_dlssd.dll'='4bc7ea5fcb2f32cf86bc2cb072e8d2860914a0be511cbdcb2fc206c1d9d83b80'
}
$inputs=@{'_nvngx.dll'=$NgxCore;'nvngx_dlss.dll'=$DlssDll;'nvngx_dlssd.dll'=$DlssdDll}
foreach($name in $inputs.Keys) {
if ((Get-FileHash -LiteralPath $inputs[$name] -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expected[$name]) {
throw "Wrong local NVIDIA DLL for installer fixture: $name"
}
}
$package=Join-Path $OutputDirectory 'package'
$runtime=Join-Path $package 'd4r'
$cache=Join-Path $OutputDirectory 'cache'
$backupRoot=Join-Path $OutputDirectory 'backups'
$nvidiaCache=Join-Path $cache 'nvidia'
New-Item -ItemType Directory -Force (Join-Path $runtime 'ngx'),(Join-Path $runtime 'dlss'),(Join-Path $runtime 'rr'),$nvidiaCache | Out-Null
Copy-Item -LiteralPath (Join-Path $repo 'packaging/windows/d4r.ini') -Destination (Join-Path $runtime 'd4r.ini')
Copy-Item -LiteralPath (Join-Path $repo 'tools/windows/dll-pins.txt') -Destination (Join-Path $runtime 'dll-pins.txt')
$targets=@(
@{source=$DlssDll; name='nvngx_dlss.dll'; relative='dlss/nvngx_dlss.dll'},
@{source=$DlssdDll; name='nvngx_dlssd.dll'; relative='rr/nvngx_dlssd.dll'},
@{source=$NgxCore; name='_nvngx.dll'; relative='ngx/_nvngx.dll'}
)
$originals=@{}
foreach($target in $targets) {
$path=Join-Path $runtime $target.relative
$original="fixture original $($target.name)"
Set-Content -LiteralPath $path $original -Encoding ASCII
$originals[$target.relative]=(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash
Copy-Item -LiteralPath $target.source -Destination (Join-Path $nvidiaCache $target.name)
}
$installer=Join-Path $PSScriptRoot 'install-dlss.ps1'
$powershell=Join-Path $env:SystemRoot 'System32/WindowsPowerShell/v1.0/powershell.exe'
function Invoke-Installer([string]$name) {
$log=Join-Path $OutputDirectory "$name.log"
& $powershell -NoProfile -ExecutionPolicy Bypass -File $installer -PackageRoot $package -CacheRoot $cache -BackupRoot $backupRoot -Yes *> $log
if ($LASTEXITCODE) { throw "Installer fixture failed ($name); see $log" }
return Get-Content -LiteralPath $log -Raw
}
$first=Invoke-Installer 'install'
foreach($target in $targets) {
$path=Join-Path $runtime $target.relative
if ((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant() -ne $expected[$target.name]) {
throw "Installed hash mismatch: $($target.relative)"
}
}
$manifests=@(Get-ChildItem -LiteralPath $backupRoot -Recurse -Filter 'backup-manifest.json' -File)
if ($manifests.Count -ne 1) { throw "Expected one outside backup manifest, found $($manifests.Count)" }
$manifest=Get-Content -LiteralPath $manifests[0].FullName -Raw | ConvertFrom-Json
if (@($manifest.files).Count -ne 3) { throw 'Expected three backed-up originals.' }
foreach($entry in $manifest.files) {
if (!$entry.backup -or !(Test-Path -LiteralPath $entry.backup) -or $entry.sha256 -ne $originals[$entry.path.Substring($runtime.Length+1).Replace('\','/')]) {
throw "Backup path or original hash mismatch: $($entry.path)"
}
if ((Get-FileHash -LiteralPath $entry.backup -Algorithm SHA256).Hash -ne $entry.sha256) { throw "Backup bytes changed: $($entry.backup)" }
}
$second=Invoke-Installer 'rerun'
if ($second -notmatch 'All three NVIDIA DLLs already match their pinned hashes\.' -or
@(Get-ChildItem -LiteralPath $backupRoot -Recurse -Filter 'backup-manifest.json' -File).Count -ne 1) {
throw 'Installer rerun was not idempotent.'
}
@{passed=$true;files=3;outsideBackups=3;idempotent=$true;archiveDownloaded=$false;driverRun=$false} |
ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "PASS WINDOWS_DLSS_INSTALLER files=3 backups=3 idempotent=1 Report: $OutputDirectory"
+145
View File
@@ -0,0 +1,145 @@
# Isolated installer checks; never starts a real game or launches GPU kernels.
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)][string]$PackageRoot,
[Parameter(Mandatory=$true)][string]$NgxCore,
[Parameter(Mandatory=$true)][string]$DlssDll,
[string]$OutputDirectory
)
$ErrorActionPreference='Stop'
if ($PSVersionTable.PSVersion.Major -ge 6) {
# The fixture uses the .NET Framework C# compiler; the shipped launcher
# also runs Windows PowerShell 5. PowerShell 7 cannot emit an EXE via Add-Type.
$arguments=@('-NoProfile','-STA','-ExecutionPolicy','Bypass','-File',$PSCommandPath,
'-PackageRoot',$PackageRoot,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll)
if ($OutputDirectory) { $arguments+=@('-OutputDirectory',$OutputDirectory) }
& "$env:SystemRoot/System32/WindowsPowerShell/v1.0/powershell.exe" @arguments
exit $LASTEXITCODE
}
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$PackageRoot=(Get-Item -LiteralPath $PackageRoot).FullName
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/windows-quick-test/'+(Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$OutputDirectory=[IO.Path]::GetFullPath($OutputDirectory)
New-Item -ItemType Directory -Force $OutputDirectory | Out-Null
function Invoke-Child([string]$Name,[string[]]$Arguments,[int]$ExpectedExit=0) {
$log=Join-Path $OutputDirectory "$Name.log"
& "$env:SystemRoot/System32/WindowsPowerShell/v1.0/powershell.exe" -NoProfile -STA -ExecutionPolicy Bypass `
-File (Join-Path $PackageRoot 'files/quick-test.ps1') @Arguments *> $log
if ($LASTEXITCODE -ne $ExpectedExit) { throw "Unexpected exit $LASTEXITCODE for $Name; see $log" }
}
function Fixture([string]$Name) {
$dir=Join-Path $OutputDirectory $Name
New-Item -ItemType Directory -Force $dir | Out-Null
$exe=Join-Path $dir 'Fixture.exe'
Set-Content -LiteralPath $exe 'installer fixture; do not execute' -Encoding ASCII
return $exe
}
$results=@()
$exe=Fixture ('space GPU '+[char]0x03a9+' test')
$game=Split-Path $exe
$before=@{}
foreach ($name in @('dxgi.dll','OptiScaler.ini','nvngx_dlss.dll')) {
Set-Content -LiteralPath (Join-Path $game $name) "original $name" -Encoding ASCII
$before[$name]=(Get-FileHash -LiteralPath (Join-Path $game $name)).Hash
}
Invoke-Child 'install' @('-Action','install','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll)
if ((Get-FileHash -LiteralPath (Join-Path $game 'd4r/dlss/nvngx_dlss.dll')).Hash -ne (Get-FileHash -LiteralPath $DlssDll).Hash) {
throw 'Numeric NGX driver SR feature DLL was not staged in its isolated search directory.'
}
if ((Get-FileHash -LiteralPath (Join-Path $game 'd4r/ngx/_nvngx.dll')).Hash -ne (Get-FileHash -LiteralPath $NgxCore).Hash) {
throw 'NGX core was not staged at the player-mode path d4r/ngx/_nvngx.dll.'
}
if (!(Test-Path -LiteralPath (Join-Path $game 'd4r/d4r.ini'))) {
throw 'd4r.ini was not staged; Steam player mode cannot configure its runtime paths.'
}
if (!(Test-Path -LiteralPath (Join-Path $game 'd4r/dll-pins.txt'))) {
throw 'dll-pins.txt was not staged; Steam player mode cannot verify its NVIDIA DLLs.'
}
if (!(Test-Path -LiteralPath (Join-Path $game 'd4r/nvapi/backend/nvapi64.dll'))) {
throw 'Raw ZLUDA NVAPI backend is missing from d4r/nvapi/backend.'
}
if ((Get-FileHash -LiteralPath (Join-Path $game 'nvngx_dlss.dll')).Hash -ne $before['nvngx_dlss.dll']) { throw 'Original application DLSS DLL was changed.' }
$saved=Get-Content -LiteralPath (Join-Path $PackageRoot 'work/settings.json') -Raw | ConvertFrom-Json
if ($saved.game -ne $exe -or $saved.architecture -ne 'gfx1201') { throw 'GPU detection or remembered selection failed on this RX9070XT fixture.' }
# Restore uses remembered game selection and needs neither HIP nor NVIDIA DLLs.
Invoke-Child 'restore' @('-Action','restore')
foreach ($name in $before.Keys) { if ((Get-FileHash -LiteralPath (Join-Path $game $name)).Hash -ne $before[$name]) { throw 'Original game bytes not restored.' } }
if (Test-Path -LiteralPath (Join-Path $game 'd4r')) { throw 'Runtime directory remains after restore.' }
$results+=@{case='auto-gfx1201-install-remember-restore'; passed=$true; gpuKernelsExecuted=$false}
$manifest=Get-Content -LiteralPath (Join-Path $PackageRoot 'files/package.json') -Raw | ConvertFrom-Json
if ($manifest.bundledNvidia) {
# Bundled originals take precedence over stale remembered shim selections;
# explicit overrides still go through the existing strict negative gates.
$exe=Fixture 'bundled auto selection'
$saved.ngxCore=Join-Path $PackageRoot 'files/targets/gfx1201/d4r/_nvngx.dll'
$saved.dlssDll=$saved.ngxCore
$saved | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $PackageRoot 'work/settings.json') -Encoding UTF8
Invoke-Child 'bundled-install' @('-Action','install','-GameExe',$exe)
$game=Split-Path $exe
foreach ($pair in @(@{path='d4r/ngx/_nvngx.dll'; expected=$NgxCore},@{path='d4r/dlss/nvngx_dlss.dll'; expected=$DlssDll})) {
if ((Get-FileHash -LiteralPath (Join-Path $game $pair.path)).Hash -ne (Get-FileHash -LiteralPath $pair.expected).Hash) { throw 'Bundled original DLL selection failed.' }
}
$report=Get-ChildItem -LiteralPath (Join-Path $PackageRoot 'results') -Directory | Sort-Object Name -Descending | Select-Object -First 1
$status=Get-Content -LiteralPath (Join-Path $report.FullName 'quick-test.json') -Raw | ConvertFrom-Json
if ($status.nvidiaDllSource.core -ne 'bundled' -or $status.nvidiaDllSource.dlss -ne 'bundled') { throw 'Bundled DLL provenance is missing.' }
Invoke-Child 'bundled-restore' @('-Action','restore','-GameExe',$exe)
if (Test-Path -LiteralPath (Join-Path $game 'd4r')) { throw 'Bundled runtime directory remains after restore.' }
$results+=@{case='bundled-auto-selection-ignores-stale-choices'; passed=$true; gpuKernelsExecuted=$false}
$core=Join-Path (Join-Path $PackageRoot 'files') $manifest.bundledNvidia.ngxCore
$original=[IO.File]::ReadAllBytes($core)
try {
[IO.File]::AppendAllText($core,'tampered bundled fixture')
$exe=Fixture 'tampered bundled core'
Invoke-Child 'tampered-bundled-core' @('-Action','install','-GameExe',$exe) 1
$game=Split-Path $exe
if ((Test-Path -LiteralPath (Join-Path $game '.d4r-backup')) -or (Test-Path -LiteralPath (Join-Path $game 'dxgi.dll'))) { throw 'Tampered bundled DLL changed game files.' }
$results+=@{case='tampered-bundled-core'; passed=$true; rejectedBeforeGameChanges=$true; gpuKernelsExecuted=$false}
} finally { [IO.File]::WriteAllBytes($core,$original) }
}
# A harmless child refuses attached debuggers and produces an empty stderr.
# The default launcher must allow it to exit and must report no DLSS session.
$exe=Join-Path (Join-Path $OutputDirectory 'launcher-fixture') 'Fixture.exe'
New-Item -ItemType Directory -Force (Split-Path $exe) | Out-Null
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public static class D4RLauncherFixture {
[DllImport("kernel32.dll")] private static extern bool IsDebuggerPresent();
public static int Main(string[] args) { return IsDebuggerPresent() ? 91 : 0; }
}
'@ -OutputAssembly $exe -OutputType ConsoleApplication
Invoke-Child 'run-no-debug' @('-Action','run','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll) 1
$report=Get-ChildItem -LiteralPath (Join-Path $PackageRoot 'results') -Directory | Sort-Object Name -Descending | Select-Object -First 1
$status=Get-Content -LiteralPath (Join-Path $report.FullName 'quick-test.json') -Raw | ConvertFrom-Json
$environment=Get-Content -LiteralPath (Join-Path $report.FullName 'environment.json') -Raw | ConvertFrom-Json
if ($environment.attachedDebugger -or $status.hardwareValidationCompleted -or
$status.status -ne 'inconclusive-process-exited-without-dlss-frames' -or $status.gameSummary.exitCode -ne '0x0' -or
(Get-Item -LiteralPath (Join-Path $report.FullName 'd4r.stderr.log')).Length -ne 0) {
throw 'Default launch attaches a debugger, mishandles empty stderr or falsely validates a launcher exit.'
}
Invoke-Child 'restore-launcher-fixture' @('-Action','restore','-GameExe',$exe)
$results+=@{case='run-no-debug-empty-stderr-no-false-pass'; passed=$true; gpuKernelsExecuted=$false}
foreach ($case in @('wrong-core','wrong-dlss','vkd3d')) {
$exe=Fixture $case; $game=Split-Path $exe
$core=if ($case -eq 'wrong-core') { Join-Path $PackageRoot 'files/targets/gfx1201/d4r/_nvngx.dll' } else { $NgxCore }
$dlss=if ($case -eq 'wrong-dlss') { $NgxCore } else { $DlssDll }
if ($case -eq 'vkd3d') { Set-Content -LiteralPath (Join-Path $game 'd3d12.dll') 'vkd3d-proton fixture; do not load' -Encoding ASCII }
Invoke-Child $case @('-Action','install','-GameExe',$exe,'-NgxCore',$core,'-DlssDll',$dlss) 1
if ((Test-Path -LiteralPath (Join-Path $game '.d4r-backup')) -or (Test-Path -LiteralPath (Join-Path $game 'dxgi.dll'))) { throw "$case changed game files before rejection." }
$message=Get-Content -LiteralPath (Join-Path $OutputDirectory "$case.log") -Raw
$match=[regex]::Match($message,'SEND THIS ONE FILE: (.+\.zip)')
if (!$match.Success -or !(Test-Path -LiteralPath $match.Groups[1].Value.Trim())) { throw "$case did not produce its single report ZIP." }
$results+=@{case=$case; passed=$true; rejectedBeforeGameChanges=$true; gpuKernelsExecuted=$false}
}
$readme=Join-Path $PackageRoot 'READ-ME-FIRST.txt'
$original=[IO.File]::ReadAllBytes($readme)
try {
Add-Content -LiteralPath $readme 'tampered fixture'
$exe=Fixture 'tampered-package'
Invoke-Child 'tampered-package' @('-Action','install','-GameExe',$exe,'-NgxCore',$NgxCore,'-DlssDll',$DlssDll) 1
$game=Split-Path $exe
if ((Test-Path -LiteralPath (Join-Path $game '.d4r-backup')) -or (Test-Path -LiteralPath (Join-Path $game 'dxgi.dll'))) { throw 'Tampered package changed game files.' }
$results+=@{case='tampered-package'; passed=$true; rejectedBeforeGameChanges=$true; gpuKernelsExecuted=$false}
} finally { [IO.File]::WriteAllBytes($readme,$original) }
$results | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $OutputDirectory 'summary.json') -Encoding UTF8
Write-Host "PASS QUICK_TEST_FIXTURES cases=$($results.Count) real_game_untouched=1 Report: $OutputDirectory"
Loaded 100 of 430 files, more files were not shown because too many files have changed in this diff. Show more