Expand Windows GPU support, add native FSR RR, and improve SR interop

Add a native D3D12 FSR Ray Regeneration route for gfx1200/gfx1201,
using the game's device and queue with embedded HLSL guide preparation
and output composition. Preserve the vkd3d compatibility route for
RDNA3 and expose explicit route overrides and diagnostics.

Improve Windows runtime compatibility:
- Retry rejected application-ID initialization with a project identity.
- Defer expensive RR backend creation until feature creation.
- Recover from transient submission failures without disabling later frames.
- Add shared-buffer export fallbacks through explicit heaps and a private
  device on the same adapter.
- Safely evict old RR descriptor sets when input views change.
- Treat requested RR presets as hints when a configured model is available.
- Expand SR/RR input formats and handle diffuse/specular hit distances,
  packed normals, depth-stencil resources, and unused FSR guides.

Reduce SR overhead by batching output downloads and format conversion
under one completion wait. Optimize strict M enc2/tube attention with
bounded FP32 accumulation and the original FP64 fallback for ambiguous
rounding cases.

Extend RDNA4 tooling with gfx1200/gfx1201 native FP8 RR model builds,
capability checks, architecture-aware deployment, and experimental K/M
kernel paths. Require matching model and runtime arithmetic families.

Add optional embedded FSR shader optimizations keyed by shader hash and
exact original SPIR-V contents. Preserve reflected metadata and record
optimizer provenance, artifact hashes, and cache identity.

Simplify Windows installation with automatic backend dependency downloads,
download progress and ETA, backed-up absolute OptiScaler library paths,
and recovery from interrupted RR model builds.

Add build-kernels.bat and a kernels-only build matrix for all eleven
registered RDNA targets, with code-object target validation and SHA256
manifests. Expand conversion probes, numerical stress tests, temporal
benchmark tooling, installer/deployment tests, and setup documentation.

Document synthetic regression and timing results, experimental build
options, and remaining RDNA4 hardware validation requirements.
This commit is contained in:
ayo committed 2026-10-17 07:40:34 -04:00
1 parent a617c818de
commit ac4ee6c225
67 files changed
+3147 -326

No files matched your search

+107 -3
View File
@@ -16,6 +16,7 @@ import hashlib
import json
import os
import shutil
import struct
import subprocess
import sys
from pathlib import Path
@@ -44,11 +45,98 @@ def git(args, cwd, log, identity=False):
run(prefix + list(args), cwd=cwd, log=log)
def generate_shader_overrides(source, output, shader_dump, optimizer, hashes, log, variants=()):
"""Embed local, measured optimizations only when the original translation matches exactly."""
if not hashes:
(source / 'libs/vkd3d-shader/d4r_shader_overrides.h').write_text(
'/* Generated by tools/windows/build_fsr_payload.py. No local overrides selected. */\n'
'static bool d4r_shader_replace_builtin(vkd3d_shader_hash_t hash, const void *original,\n'
' size_t original_size, const void **data, size_t *size)\n{\n'
' (void)hash; (void)original; (void)original_size; (void)data; (void)size;\n'
' return false;\n}\n')
return {}
if shader_dump is None or optimizer is None:
raise ValueError('--optimize-shader requires --shader-dump and --spirv-opt')
records = {}
arrays = []
entries = []
inputs = output / 'shader-sources'
inputs.mkdir()
for shader_hash, variant in ((h, v) for h in sorted(set(hashes)) for v in range(1 + len(variants))):
if len(shader_hash) != 16 or any(c not in '0123456789abcdef' for c in shader_hash):
raise ValueError('shader hash must contain 16 lowercase hexadecimal digits')
original = ([shader_dump] + list(variants))[variant] / (shader_hash + '.spv')
variant_inputs = inputs if variant == 0 else inputs / ('variant-' + str(variant))
variant_inputs.mkdir(exist_ok=True)
symbol = shader_hash if variant == 0 else shader_hash + '_' + str(variant)
optimized = variant_inputs / (shader_hash + '.optimized.spv')
run([optimizer, '--target-env=vulkan1.3', '-O', original, '-o', optimized], log=log)
validator = optimizer.with_name('spirv-val.exe')
run([validator, '--target-env', 'vulkan1.3', optimized], log=log)
shutil.copy2(original, variant_inputs / original.name)
for kind, path in (('original', original), ('optimized', optimized)):
data = path.read_bytes()
if len(data) % 4 or data[:4] != b'\x03\x02\x23\x07':
raise ValueError('invalid SPIR-V: ' + str(path))
words = struct.unpack('<%dI' % (len(data) // 4), data)
rows = [', '.join('0x%08xu' % word for word in words[i:i + 8]) for i in range(0, len(words), 8)]
arrays.append('static const uint32_t d4r_%s_%s[] = {\n%s\n};\n' %
(kind, symbol, ',\n'.join(rows)))
entries.append(' {0x%sULL, d4r_original_%s, sizeof(d4r_original_%s), '
'd4r_optimized_%s, sizeof(d4r_optimized_%s)},' % (shader_hash, symbol, symbol, symbol, symbol))
records[symbol] = {'originalSha256': sha(original), 'optimizedSha256': sha(optimized)}
header = '''/* Local shader optimizations. Generated by tools/windows/build_fsr_payload.py. */
''' + ''.join(arrays) + '''
static const struct d4r_shader_override {
vkd3d_shader_hash_t hash;
const void *original;
size_t original_size;
const void *optimized;
size_t optimized_size;
} d4r_shader_overrides[] = {
''' + '\n'.join(entries) + '''
};
static bool d4r_shader_replace_builtin(vkd3d_shader_hash_t hash, const void *original,
size_t original_size, const void **data, size_t *size)
{
char disabled[2];
unsigned int i;
if (vkd3d_get_env_var("D4R_FSR_DISABLE_BUILTIN_SHADERS", disabled, sizeof(disabled)))
return false;
for (i = 0; i < ARRAY_SIZE(d4r_shader_overrides); ++i)
{
const struct d4r_shader_override *entry = &d4r_shader_overrides[i];
void *buffer;
if (entry->hash != hash || entry->original_size != original_size ||
memcmp(entry->original, original, original_size))
continue;
if (!(buffer = vkd3d_malloc(entry->optimized_size)))
return false;
memcpy(buffer, entry->optimized, entry->optimized_size);
*data = buffer;
*size = entry->optimized_size;
INFO("d4r: using validated local optimization for shader %016"PRIx64".\\n", hash);
return true;
}
return false;
}
'''
(source / 'libs/vkd3d-shader/d4r_shader_overrides.h').write_text(header)
(inputs / 'd4r_shader_overrides.h').write_text(header)
records['optimizerSha256'] = sha(optimizer)
(inputs / 'manifest.json').write_text(json.dumps(records, indent=2) + '\n')
return records
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--output', required=True, type=lambda p: Path(p).resolve())
parser.add_argument('--source', type=lambda p: Path(p).resolve(),
help='reuse an existing vkd3d-proton clone (must be a checkout of the pinned commit); default: fresh clone under --output/_work')
parser.add_argument('--shader-dump', type=lambda p: Path(p).resolve(), help='original SPIR-V from this translator/device')
parser.add_argument('--shader-variant', action='append', default=[], type=lambda p: Path(p).resolve(), help='additional exact translation variant directory')
parser.add_argument('--spirv-opt', type=lambda p: Path(p).resolve(), help='local spirv-opt.exe used for measured optimizations')
parser.add_argument('--optimize-shader', action='append', default=[], metavar='HASH', help='embed a measured -O shader; repeat for each validated winner')
args = parser.parse_args()
if not args.output.is_relative_to((repo / 'build').resolve()):
parser.error('output must stay under ignored build/')
@@ -85,12 +173,25 @@ def main():
if not ancestor:
git(['cherry-pick', '-x'] + listing, dxil, log, identity=True)
# libc++ include fixes (GCC pulled these in transitively; libc++ does not)
# and late shader replacement, preserving dxil-spirv's reflected metadata.
for patch, where in (('0001-dxil-spirv-include-exception-for-libcxx.patch', dxil),
('0002-dxbc-spirv-include-new-for-libcxx.patch', dxil / 'subprojects/dxbc-spirv')):
('0002-dxbc-spirv-include-new-for-libcxx.patch', dxil / 'subprojects/dxbc-spirv'),
('0003-preserve-meta-for-shader-overrides.patch', source),
('0004-support-local-optimized-shaders.patch', source)):
full = repo / 'patches/vkd3d-proton-windows' / patch
check = subprocess.run(['git', 'apply', '--check', '--reverse', str(full)], cwd=where, capture_output=True)
if check.returncode: # not applied yet
git(['apply', full], where, log)
optimized_shaders = generate_shader_overrides(source, args.output, args.shader_dump, args.spirv_opt,
args.optimize_shader, log, args.shader_variant)
# Cache identities must include local patches and shader contents, not only upstream HEAD.
build_identity = hashlib.sha256()
build_identity.update((VKD3D_COMMIT + DXIL_FSR_MERGE).encode())
for patch in sorted((repo / 'patches/vkd3d-proton-windows').glob('*.patch')):
build_identity.update(patch.read_bytes())
build_identity.update(json.dumps(optimized_shaders, sort_keys=True).encode())
build_id = build_identity.hexdigest()[:16]
(source / 'vkd3d_build.h.in').write_text('#include <stdint.h>\nstatic const uint64_t vkd3d_build = 0x' + build_id + ';\n')
escaped = lambda path: str(path).replace('\\', '/')
cross = work / 'cross.txt'
cross.write_text('\n'.join([
@@ -129,15 +230,18 @@ def main():
'fsr/d4r_vkd3d_core.dll is vkd3d-proton (LGPL-2.1) built for Windows by tools/windows/build_fsr_payload.py.',
'Corresponding source: ' + VKD3D_URL + ' at ' + VKD3D_COMMIT + ',',
'dxil-spirv with upstream PR 307 (merge ' + DXIL_FSR_MERGE + ') cherry-picked, and the patches in',
'patches/vkd3d-proton-windows/ of the d4r repository (libc++ include fixes). Build: meson cross build with',
'patches/vkd3d-proton-windows/ of the d4r repository (libc++ fixes and metadata-preserving shader overrides).',
'Build: meson cross build with',
'llvm-mingw clang, -Denable_extended_emulation=true, buildtype release; the DLL is stripped and renamed.',
'Built HEADs: ' + json.dumps(heads), 'Patches: ' + json.dumps(patches),
'Cache build ID: ' + build_id, 'Local optimized shaders: ' + json.dumps(optimized_shaders),
'Local shader source inputs and generated header, when selected: shader-sources/.',
'fsr/amdxc64.dll is d4r original code (tools/windows/amdxc64_shim). It is not AMD software.', '']))
files = {str(p.relative_to(args.output)).replace('\\', '/'): sha(p) for p in sorted(args.output.rglob('*'))
if p.is_file() and '_work' not in p.relative_to(args.output).parts}
(args.output / 'fsr-payload.json').write_text(json.dumps(dict(
schema=1, kind='d4r-fsr-payload', amdDenoiserBundled=False, vkd3dProtonCommit=VKD3D_COMMIT, dxilSpirvFsrMerge=DXIL_FSR_MERGE,
builtHeads=heads, patches=patches, files=files), indent=2) + '\n')
builtHeads=heads, patches=patches, optimizedShaders=optimized_shaders, cacheBuildId=build_id, files=files), indent=2) + '\n')
print(json.dumps(files, indent=2))
print('FSR_PAYLOAD_BUILT ' + str(args.output))