feat(d3d): add opt-in hardware ray-traced GI

Merged
NO
10d ago
+5169-128

Stacked on #130. Review and merge after it.

Summary

Opt-in one-bounce ray-traced global illumination on D3D12 DXR, composited into the D3D11 frame. D3D11 stays the renderer and the fallback.

per frame (RECOMP_D3D_RTGI=1)
  collect draws -> skin indexed ranges -> build or refit BLAS/TLAS (D3D12)
  trace at RECOMP_D3D_RTGI_SCALE, RECOMP_D3D_RTGI_HZ  (sky occlusion, alpha-tested rays, hit texture color)
  temporal reproject through mesh motion -> spatial filter -> dithered composite into the D3D11 target
  • Tuning hotkeys for strength, pause and frame step (Windows only; elsewhere they compile out).
  • RECOMP_PERF_COUNTER=1 reports per-stage CPU and GPU cost.
  • Also dithers opaque main-target color before 8-bit quantization, which removes banding on skin.
  • Research notes: docs/wayfinder/research/rtgi-*.md.
  • MSVC builds only. llvm-mingw ships a stub DirectXMath, so clang builds, which is how players build, leave RTGI out. Shipping it to players needs its math ported to plain floats.

Verification

  • MSVC Debug build and ctest at this layer: 39/39 passed.
  • python tools/public_export.py verify --require-public-tree passes.
  • clang, macOS and Linux: covered by this PR's public-ci run. Its first clang run failed on DirectXMath; f710d93 builds RTGI with MSVC only.
  • Player play tests of the integrated build on several courts with the hotkeys.

Merge danger

Two-way door. GI is off by default and needs a DXR-capable GPU. The always-on part is the main-target dither, which changes 8-bit output by at most one step.

Contribution checklist

  • The change follows AGENTS.md and CONTRIBUTING.md.
  • No XBE, generated game C, retail instruction bytes, extracted assets or
    filenames, saves, BIOS data, private paths, or run evidence are included.
  • Third-party material and its license are identified, if applicable.