Skip to content

feat(shader): implement the float and 64-bit inc/dec buffer atomics - #332

Merged
oneandonlydean merged 2 commits into
boykopovar:mainfrom
adriadam10:feat/buffer-atomics-float
Oct 4, 2026
Merged

oneandonlydean merged 2 commits into
boykopovar:mainfrom
adriadam10:feat/buffer-atomics-float

Conversation

@adriadam10

Copy link
Copy Markdown
Collaborator

What

This implements the six buffer atomics still missing. It also fixes the existing 32-bit buffer_atomic_fmin/fmax.

Opcode Semantics (measured on an RDNA2 GPU)
buffer_atomic_fcmpswap (0x3e) / _x2 (0x5e) mem = (mem == cmp) ? src : mem, compared as floats: −0 equals +0, NaN equals nothing, denormals compare exactly
buffer_atomic_fmin_x2 (0x5f) / fmax_x2 (0x60) IEEE minNum/maxNum on f64: −0 < +0. A signalling NaN operand gives that NaN quieted (src first). A quiet NaN loses to a number. Two quiet NaNs give src
buffer_atomic_inc_x2 (0x5c) / dec_x2 (0x5d) as the 32-bit inc/dec from #321, on u64

Bug: the existing 32-bit buffer_atomic_fmin/fmax (EmitFloatAtomicReplacement) kept the old value whenever either operand was a NaN or both were zeros. The hardware follows the same rule as the f64 forms above:

  • fmin(qNaN, 1.0) = 1.0
  • fmin(+0, −0) = −0
  • fmin(1.0, sNaN 0x7fa00000) = 0x7fe00000

2048/2048 vectors on hardware. The helper is now unused and is removed.

Implementation:

Measuring: float atomics are not performed on fine-grained system memory. The first capture returned zeros, while the integer atomics were fine. The vectors were captured with the buffers in the GPU's coarse-grained pool.

Tests, all values captured on the RDNA2 GPU (ROCm HSA, raw kernels):

  • agc_driver_buffer_atomics_float: fcmpswap (32/64) returned and stored values, fmin/fmax 32 and 64 across ±0, ±inf, quiet and signalling NaNs with payloads, and denormals.
  • agc_driver_buffer_atomics_inc_dec64: the wrap edges (0, limit, limit ± 1, 2^32, 2^64−1).

Tested

Linux, full ctest (101) passes.

  • RADV (Radeon 660M) and lavapipe: both tests pass.
  • With the old 32-bit replacement: fmin_mem0 is 0x7fa00000, expected 0x7fe00000. Without the sNaN quieting: fmin_x2_mem0 is 0xbf800000, expected 0x00000001.

Checklist

@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Progress report (2cf901b → 7f291b7)

📈 GPU shader instructions: 81.73% (+1.46%, +17 implemented instructions)

✅ 17 implemented
Encoding Name
MUBUF BUFFER_ATOMIC_ADD_X2
MUBUF BUFFER_ATOMIC_AND_X2
MUBUF BUFFER_ATOMIC_CMPSWAP_X2
MUBUF BUFFER_ATOMIC_DEC
MUBUF BUFFER_ATOMIC_DEC_X2
MUBUF BUFFER_ATOMIC_FCMPSWAP
MUBUF BUFFER_ATOMIC_FCMPSWAP_X2
MUBUF BUFFER_ATOMIC_FMAX_X2
MUBUF BUFFER_ATOMIC_FMIN_X2
MUBUF BUFFER_ATOMIC_INC
MUBUF BUFFER_ATOMIC_INC_X2
MUBUF BUFFER_ATOMIC_SMAX_X2
MUBUF BUFFER_ATOMIC_SMIN_X2
MUBUF BUFFER_ATOMIC_SUB_X2
MUBUF BUFFER_ATOMIC_UMAX_X2
MUBUF BUFFER_ATOMIC_UMIN_X2
MUBUF BUFFER_ATOMIC_XOR_X2

This was referenced Oct 2, 2026
@github-actions github-actions Bot added build shader core/shader agc libSceAgc* labels Oct 2, 2026
@github-actions github-actions Bot added ci .github needs rebase Conflicts with main, rebase needed labels Oct 2, 2026
@adriadam10
adriadam10 force-pushed the feat/buffer-atomics-float branch from a337b96 to 7933efc Compare October 3, 2026 09:44
@adriadam10

Copy link
Copy Markdown
Collaborator Author

Rebased on main. main now has SharedAtomicUpdate for the LDS atomics, so this PR no longer carries its own SharedFloatAtomic: the shared min/max path is main's, unchanged. The buffer side (AtomicFloatBits, BufferAtomic64Update) is as before. Still stacked on #321; review only the last commit.

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 3, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

This passed my PPSA21564 check too; it needs a rebase once #321 is rebased, since #319 to #331 are now on main. Then it's ready to merge from my side.

adriadam10 and others added 2 commits October 4, 2026 11:59
…buffer atomics

buffer_atomic_inc, buffer_atomic_dec, buffer_atomic_cmpswap_x2 and
buffer_atomic_{add,sub,smin,umin,smax,umax,and,xor}_x2 threw in the decoder.
The 64-bit ones use native 64-bit SPIR-V atomics like the existing
swap_x2/or_x2; inc and dec wrap at the data operand through the existing
compare-exchange helpers.

Co-Authored-By: Claude <noreply@anthropic.com>
buffer_atomic_fcmpswap, fcmpswap_x2, fmin_x2, fmax_x2, inc_x2 and
dec_x2 are compare-and-swap loops on the dword or qword. fcmpswap
compares as floats (-0 equals +0, NaN equals nothing) and fmin/fmax are
IEEE minNum/maxNum with -0 < +0, a quieted result for a signalling NaN
and the other operand for a quiet one, all with integer ops so the
driver's float controls do not matter. The existing 32-bit fmin/fmax
kept the old value whenever a NaN or two zeros were involved; it now
uses the same rule.

Co-Authored-By: Claude <noreply@anthropic.com>
@adriadam10
adriadam10 force-pushed the feat/buffer-atomics-float branch from 7933efc to 7f291b7 Compare October 4, 2026 10:01
@adriadam10

Copy link
Copy Markdown
Collaborator Author

Rebased on the rebased #321 and current main (same MUBUF table conflict, both sides kept). BufferAtomicsFloat, BufferAtomicsIncDec64 and BufferAtomics pass on RADV and lavapipe.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks for the rebase. Both commits have exactly the content I ran through my PPSA21564 check (the first is #321's head), and agc_driver_buffer_atomics_float, agc_driver_buffer_atomics_inc_dec64 and agc_driver_buffer_atomics pass here on current main. Ready to merge right after #321.

@oneandonlydean
oneandonlydean merged commit b255863 into boykopovar:main Oct 4, 2026
3 checks passed
@adriadam10
adriadam10 deleted the feat/buffer-atomics-float branch October 5, 2026 06:47
oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 5, 2026
Conflicts resolved:
- libSceAudioPropagation/Export.cpp: upstream's boykopovar#482 + boykopovar#489 version taken; it is
  the same no-propagation model as astrobot's stand-in, with SourceRender and the
  handle-only UnregisterMaterial already in it.
- State.cpp (boykopovar#453): astrobot's resident depth model kept; it already skips the
  tests of an absent plane (boykopovar#453's test is on astrobot since e087a4f).
- Graphics.cpp, State.hpp, ShaderResources.cpp: astrobot's DepthTarget model kept
  (exportIndex, no DepthSurface.hpp), upstream's ThreadOwned include added.
- BdaResources.cpp: astrobot's form with boykopovar#390's message.
- VulkanDevice.cpp, Context.hpp, PacketExecution.cpp: both sides kept
  (calibrated timestamps, host query reset, GDS, memory budget; pipeline stats).
- Spirv: astrobot's split-wave rules first, then boykopovar#608's wave-mask ballot and
  boykopovar#587's host subgroup lane; astrobot's function LDS sizing and boykopovar#573's LDS lock
  both kept; conditionalDepth kept in the atomic update loops; upstream's
  buffer atomics (boykopovar#321 boykopovar#332 boykopovar#594) and 64-bit LDS atomics taken.
- TechnicalDebt.md: both sides, duplicate lines dropped.


Build fixes folded in: the upstream boykopovar#453 test block duplicated next to
astrobot's adapted copy removed; a lost closing brace after the host
query reset block restored; lookupLog() is a function since boykopovar#590; the
duplicate MUTEX_TYPE_ADAPTIVE constant (astrobot's 93b2d0e equals boykopovar#156)
removed; the ops boykopovar#596 drops removed from the masked-select list and the
BDA test message updated (the gate-batch-2 integ commits 559e4fab6 and
2ec968fb5).
thuanquang added a commit to thuanquang/AnyPS5 that referenced this pull request Oct 21, 2026
…mics

On RDNA2 the image, buffer and global float atomics (fmin, fmax,
fcmpswap and the _x2 forms) flush both operands to a signed zero when
bit 0 of the shader's denormal field is clear, as the LDS forms do: the
f32 field for the 32-bit forms, the f16/f64 field for _x2. Only the
LDS forms flushed here. floatAtomicFlush (was sharedFloatFlush) now
sets MemoryInfo::flushDenormals for every float atomic, and
AtomicFloatBits applies it in minMax and compareSwap.

The float atomic tests from boykopovar#332, boykopovar#506 and boykopovar#562 were measured with
denormals kept, so they now set FLOAT_MODE 0xf0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build ci .github shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants