protonscr

Forza Horizon 6 crashes when enabling Ray Tracing

vkd3dclosed
HansKristian-Work/vkd3d-proton#3032 · opened 2026-05-16 by craimasjien · updated 2026-08-10 · 3 comments · github
Ccraimasjien 2026-05-16 github

Forza Horizon 6 crashes immediately on the first frame when Ray Tracing is enabled in graphics settings. With RT disabled the game runs relatively okay.

The crash is a GPU page fault on an unmapped VA, occurring from a scalar (SQC) load on the vkd3d_queue thread immediately after a CmdTraceRaysKHR. RADV's hang capture (RADV_DEBUG=hang,syncshaders) shows the CP advanced through the trace-ray dispatch and then died on the DISPATCH_DIRECT that executes the raygen wrapper.

Sequence captured (trace.log, last reached / first not reached):

CmdBindPipeline -> CmdSetRayTracingPipelineStackSizeKHR
              -> CmdSetDescriptorBufferOffsetsEXT
              -> CmdPushConstants
              -> CmdTraceRaysKHR:
    [... compute pipeline setup, user-data writes ...]
    Trace point ID: 94
    DISPATCH_DIRECT(shader_type=compute):
        DIM_X = 120 (0x78)  DIM_Y = 2160 (0x870)  DIM_Z = 1
        COMPUTE_DISPATCH_INITIATOR = 0x0000a047  (CS_W32_EN=1, TUNNEL_ENABLE=1)
    Trace point ID: 95

DIM_X * 32 = 3840, DIM_Y = 2160 → wave32 raygen launch over a 4K render target.
vkd3d-proton is using VK_EXT_descriptor_buffer for binding.

GPU page fault (dmesg, fault repeats ~10 times until throttled):

amdgpu 0000:2d:00.0: [gfxhub] page fault (src_id:0 ring:24 vmid:6 pasid:331)
amdgpu 0000:2d:00.0:  Process forzahorizon6.e pid <pid> thread vkd3d_queue pid <tid>
amdgpu 0000:2d:00.0:   in page starting at address 0x00008000f1198000 from client 10
amdgpu 0000:2d:00.0: GCVM_L2_PROTECTION_FAULT_STATUS:0x00601431
amdgpu 0000:2d:00.0:          Faulty UTCL2 client ID: SQC (data) (0xa)
amdgpu 0000:2d:00.0:          PERMISSION_FAULTS: 0x3
amdgpu 0000:2d:00.0:          MAPPING_ERROR: 0x0
amdgpu 0000:2d:00.0:          RW: 0x0

RADV vm_fault.log:

Failing VM page: 0x8000f1198000
GCVM_L2_PROTECTION_FAULT_STATUS: 0x601430
   CLIENT_ID: (SQC (data)) 0xa
   PERMISSION_FAULTS: 3   RW: 0
Performing some verifications with address binding report...
VA not found!

The page is not covered by any BO RADV is tracking, the shader is dereferencing a pointer that points at unmapped VA, not "wrong perms on a real buffer."

In-flight pipeline: single RT state object, 1 raygen + ~20 closest-hit groups (driver pipeline hash 11508522364814361689). Raygen wrapper user-data inputs include the standard RT continuation args: ac.rt.traversal_shader_addr, ac.rt.sbt_descriptors, ac.rt.launch_size_addr, ac.rt.dynamic_callable_stack_base.

Address-formation observation: the faulting address is 0x0000_8000_f119_8000. The raygen-wrapper disassembly visibly constructs the high half from a hardcoded 0x8000 immediate just before the indirect call into the next shader stage:

s_load_b64 s[0:1], s[6:7], 0x0     ; load shader-record pointer from SBT
s_load_b64 s[10:11], s[0:1], 0x0   ; deref it
...
s_movk_i32 s9, 0x8000              ; <-- top half of constructed pointer
...
s_swappc_b64 s[0:1], s[2:3]        ; indirect call

The high half 0x8000 is invariant across RT lowering paths. Only the low half changes when the lowering changes:

Run Faulting address(es)
stock 0x00008000_f1198000
RADV_DEBUG=nobvh8 0x00008000_f1198000 (identical)
RADV_PERFTEST=emulate_rt 0x00008000_f1198000 and 0x00008000_e82c2000 (interleaved)

The bug is not specific to the HW BVH8 path. it survives the HW→SW RT lowering swap. Only the SBT/shader-record walk produces different low halves.

Software information

  • Game: Forza Horizon 6 (Steam app 2483190), depot 4.0.20260415.225012
  • Settings: Ray Tracing enabled (any RT setting). Renders at 3840×2160. Crash is immediate on first RT frame.
  • Reproduction: launch game → enable any RT option in graphics settings → apply → instant crash.

System information

  • GPU: AMD Radeon RX 9070 XT (GFX1201 / RDNA 4, PCI ID 0x7550 rev 0xc0, 16 GB VRAM)
  • Driver: Mesa/RADV 26.1.0-arch2.1 (vulkan-radeon 2:26.1.0-1), kernel 7.0.5-1-cachyos-bore-lto, DRM 3.64.0
  • Wine version: wine-cachyos 11.0 (proton-cachyos local build from branch cachyos_11.0_20260506); Steam runtime steamrt4 4.0.20260415.225012
  • VKD3D-Proton version: vkd3d-1.1-5204-g64f5776f (submodule commit 64f5776f)

Other relevant components: DXVK v2.7.1-591-g60978eb9, display server Wayland (KWin/Plasma).

Log files

Captured with:

PROTON_LOG=1
VKD3D_DEBUG=info VKD3D_SHADER_DEBUG=warn
RADV_DEBUG=hang,syncshaders,zerovram
MESA_VK_ABORT_ON_DEVICE_LOSS=1
MESA_SHADER_CACHE_DISABLE=true

Attached / available on request:

  • steam-<appid>.log — Proton log
  • RADV hang dump (radv_dumps_*): trace.log, pipeline.log, vm_fault.log, app_info.log, gpu_info.log, registers.log, bo_history.log, addr_binding_report.log
  • dmesg excerpt covering the fault

What I have ruled out

  • Not the HW BVH8 path: RADV_DEBUG=nobvh8 reproduces unchanged.
  • Not a generic compute hang: only triggered by RT pipelines (CmdTraceRaysKHR).
  • Not a missing BO mapping RADV knows about: vm_fault.log reports "VA not found", the page is genuinely outside any tracked BO.

What I have not yet tried

  • Re-run with RADV_DEBUG=hang,syncshaders,allbos to populate bo_ranges.log and identify the BO closest to 0x8000f1198000 (would localize whether this is the SBT, scratch, or descriptor-buffer BO).
  • mesa-git to test post-26.1 RADV fixes.
  • vkd3d-proton bisect across 64f5776f and earlier releases.

Happy to re-capture with any additional flags or run targeted bisects if useful.

HHansKristian-Work maintainer 2026-05-16 github

Root cause is already resolved by https://github.com/HansKristian-Work/vkd3d-proton/pull/3033. This analysis misses the mark. It's a simple heap OOB.

HHitmehplox 2026-08-10 github

Corroborating report — different game, same GPU, same fault, same 0x00008000 VA high half.

Cyberpunk 2077 (Steam 1091500) through vkd3d-proton hits what looks like this exact bug. Five occurrences in one evening, byte-identical fault status word each time. Two full amdgpu devcoredumps captured; happy to attach them or any specific registers from them.

System

GPU RX 9070 XT (Sapphire), PCI 1002:7550 rev c0, VBIOS 113-1E4893U-N8K
Driver Mesa 26.1.4-arch3.1, RADV, GFX1201, Vulkan 1.4.354
Kernel 7.1.6-1-cachyos, GC IP v12.0.1.0.0
Proton GE-Proton11-3

Ray tracing on: RayTracedReflections, RayTracedSunShadows, RayTracedLocalShadows all true, RayTracedLighting=Medium, RayTracedPathTracing=False. Noting it since you traced yours to an RT raygen shader.

Fault

amdgpu 0000:03:00.0: [gfxhub] page fault (src_id:0 ring:24 vmid:6 pasid:1116)
amdgpu 0000:03:00.0:  Process GameThread pid 303580 thread vkd3d_queue pid 304273
amdgpu 0000:03:00.0:   in page starting at address 0x00008000b9eaf000 from client 10
amdgpu 0000:03:00.0: GCVM_L2_PROTECTION_FAULT_STATUS:0x00601431
amdgpu 0000:03:00.0:          Faulty UTCL2 client ID: SQC (data) (0xa)
amdgpu 0000:03:00.0:          MORE_FAULTS: 0x1
amdgpu 0000:03:00.0:          WALKER_ERROR: 0x0
amdgpu 0000:03:00.0:          PERMISSION_FAULTS: 0x3
amdgpu 0000:03:00.0:          MAPPING_ERROR: 0x0
amdgpu 0000:03:00.0:          RW: 0x0
amdgpu 0000:03:00.0: ring gfx_0.0.0 timeout, signaled seq=176367281, emitted seq=176367283
amdgpu 0000:03:00.0: Starting gfx_0.0.0 ring reset
amdgpu 0000:03:00.0: Ring gfx_0.0.0 reset succeeded
amdgpu 0000:03:00.0: [drm] device wedged, but no recovery needed

GCVM_L2_PROTECTION_FAULT_STATUS = 0x00601431 on all five. The same address faults 4–5× in a row before the ring times out. Ring reset succeeds, so the desktop survives, but the game process spins unkillably and needs kill -9.

One difference from your report worth flagging: mine times out on gfx_0.0.0, yours on ring 24 / compute. Same client and status word, different ring.

The VA high half

faulting VA
yours (FH6) 0x00008000f1198000
mine #4 0x00008000f2084000
mine #5 0x00008000b9eaf000

Same 0x00008000 high dword, varying low half — consistent with your finding that the pointer is built with a hardcoded 0x8000 high half.

Supporting detail from the devcoredumps: every command buffer is in 0x00008001…CP_IB1_BASE_HI and the CP_HQD_IB_BASE_ADDR_HI of every active compute queue. So the faulting pointer is provably not in the command-buffer VA range on this side either.

Other data points

Timing is wildly variable — 3 m 55 s and 17 m 03 s on back-to-back sessions with identical config (historical range on this box: 78 s to 1 h 25 m). Points at a discrete trigger rather than progressive corruption.

Deterministic trigger: open world map → select a job → close map. 3/3 on RADV. That is when transient render targets get destroyed.

Does not reproduce on AMDVLK. Same hardware, kernel, Proton, save — only the ICD swapped. n=1 session, no A/B/A control yet, so a lead rather than proof.

RADV_DEBUG=hang makes it vanish (hang implies syncshaders) — consistent with a race.

Ruled out here: stock voltage and a −500 MHz core offset (ceiling 2950 vs 3450 stock) both still fault, so not thermal/electrical; not mods; not X11 vs Wayland; not VKD3D_DISABLE_EXTENSIONS=VK_EXT_dgc. VKD3D_CONFIG=single_queue did not help — though I'll note breadcrumbs and descriptor_qa are accepted by the config parser but not compiled into this Proton build, so I can only claim it didn't help, not that it ruled out cross-queue hazards.

Possibly related

Three unrelated engines (REDengine/vkd3d, FH6/vkd3d, UE5) on the same silicon + driver. Glad to run instrumented sessions on request — the trigger is reproducible in about two minutes.

BBlisto91 2026-08-10 github

@Hitmehplox make a new issue. Skip the LLM analysis and attach a Proton log when doing so (just fill out the issue template)