fix: use the native float atomic add instead of compare-exchange loops #886

Closed
yassine-milal wants to merge 3 commits from fix/native-float-add into main
yassine-milal commented 2026-11-09 00:21:24 +00:00 (Migrated from github.com)

StorageAtomicAddF32 is always emitted as a compare-exchange retry loop (f32_add_cas). Under contention, with many
invocations adding to one address, nearly every attempt fails and retries up to the loop's cap, and the additions that
give up are lost.

Where the device has VK_EXT_shader_atomic_float with shaderBufferFloat32AtomicAdd (NVIDIA since Maxwell, AMD since
GCN, Intel Xe), it is now one OpAtomicFAddEXT on an F32 view of the storage buffer. Otherwise the loop stays.
RX_VK_NATIVE_FADD=0 turns it off; it is an RX_VK_NATIVE* switch, so the program cache follows it.

Tested (P4000, 582.16, v2.0.2):

  • Two compute passes, ab7699ee7f536755 (Kakariko, toward the fence) and 7984161db3e053b5 (Death Mountain Trail
    and Kakariko), took 20-53 ms a frame against ~1 ms elsewhere. After the change the 53 ms spike did not come back where
    it was seen before. The fog (7984161db3e053b5) now shows, where it was thin before.
  • 7984161db3e053b5 still reaches ~18 ms in places: it also has compare-exchange loops for packed 16-bit atomics,
    which this does not touch.
  • Translator change: the program cache is prepared once again.

Testing. Played on a Quadro P4000 (Pascal, 8 GB, no mesh shaders), NVIDIA 582.16, Xeon W-2133, 32 GB, Windows 11, with Hookshot v2.0.2 and the same change. On main this branch compiles (RX_VK_ONLY=1 nx2/build.py --standalone, llvm-mingw) and tests/run_all.py gives the same result as untouched main on this PC: 98 passed, 12 skipped, 1 failed (tests/test_fps_overlay_order.py, which fails on main here too with llvm-mingw's clang). The game itself was not rebuilt on main.

🤖 Generated with Claude Code

`StorageAtomicAddF32` is always emitted as a compare-exchange retry loop (`f32_add_cas`). Under contention, with many invocations adding to one address, nearly every attempt fails and retries up to the loop's cap, and the additions that give up are lost. Where the device has `VK_EXT_shader_atomic_float` with `shaderBufferFloat32AtomicAdd` (NVIDIA since Maxwell, AMD since GCN, Intel Xe), it is now one `OpAtomicFAddEXT` on an F32 view of the storage buffer. Otherwise the loop stays. `RX_VK_NATIVE_FADD=0` turns it off; it is an `RX_VK_NATIVE*` switch, so the program cache follows it. **Tested** (P4000, 582.16, v2.0.2): - Two compute passes, `ab7699ee7f536755` (Kakariko, toward the fence) and `7984161db3e053b5` (Death Mountain Trail and Kakariko), took 20-53 ms a frame against ~1 ms elsewhere. After the change the 53 ms spike did not come back where it was seen before. The fog (`7984161db3e053b5`) now shows, where it was thin before. - `7984161db3e053b5` still reaches ~18 ms in places: it also has compare-exchange loops for packed 16-bit atomics, which this does not touch. - Translator change: the program cache is prepared once again. **Testing.** Played on a Quadro P4000 (Pascal, 8 GB, no mesh shaders), NVIDIA 582.16, Xeon W-2133, 32 GB, Windows 11, with Hookshot v2.0.2 and the same change. On `main` this branch compiles (`RX_VK_ONLY=1 nx2/build.py --standalone`, llvm-mingw) and `tests/run_all.py` gives the same result as untouched `main` on this PC: 98 passed, 12 skipped, 1 failed (`tests/test_fps_overlay_order.py`, which fails on `main` here too with llvm-mingw's clang). The game itself was not rebuilt on `main`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
NotRexed commented 2026-11-09 05:30:50 +00:00 (Migrated from github.com)

Closing to keep the queue clear — please rebase on current main and reopen; thanks!

Closing to keep the queue clear — please rebase on current main and reopen; thanks!
Commenting is not possible because the repository is archived.
No description provided.