Repository navigation
fix(shader): saturate VOP3 v_add/sub_nc_u32 and 16-bit add/sub on clamp - #1898
Conversation
klosixgaming-arch
left a comment
There was a problem hiding this comment.
Strong PR. Splitting VAddNcU16/VAddNcI16 (and the sub forms) so the i16 variants sign-extend their operands is a real correctness fix — previously both fell through to the unsigned path. The hardware verification is exemplary for this repo: tools/hw-oracle on gfx1036 with two independent mode settings giving matching results, a 32-row measured table pinned in the test (u32 wrap, u16/i16 boundaries, junk in bits 31:16), and cross-backend runs (RADV / NVIDIA / lavapipe). Reusing saturateInteger16 is clean, and carry-with-clamp still throwing is the correct conservative boundary.
Written with AI assistance.
|
A real-title data point for this: EVO-PLAYER v0.11.0 (PPSA99039, built from source) compiles its FSR EASU upscaler pixel shader with amdllpc for gfx1013, and that shader starts with two unsigned saturating subtracts: On Setup: Linux, RX 7600 (RADV, Mesa 25.2.8). The base was |
|
Native Windows run, since no Windows results were posted. Setup: Windows 10 (19045), RTX 3060 Laptop (NVIDIA 616.92), MinGW-w64 GCC 15.2.0 (WinLibs r7), Release. Head
No title was run. 🤖 Addressed by Claude Code |
|
Checked all 7 clamped forms on the HW oracle (gfx1035): the 32 rows the test pins match bit for bit. Another 525 rows (u16/i16/u32 boundaries crossed with each other, plus random inputs) and op_sel high-half sources match the saturation model. Also checked: the test fails without the change, ctest is green on RADV, and there are no conflicts with main. Merging. |
…lamp fix(shader): saturate VOP3 v_add/sub_nc_u32 and 16-bit add/sub on clamp
What
Closes #1897.
This makes the recompiler accept
clampon VOP3v_add_nc_u32,v_sub_nc_u32,v_subrev_nc_u32,v_add_nc_u16,v_sub_nc_u16,v_add_nc_i16andv_sub_nc_i16, and saturates the result.For u32,
vAddSubNcU32already saturated for SDWA, so the three opcodes only needed adding tousesIntegerSaturateClamp.For the 16-bit ops, a new
isVop3Integer16AddSubOpcodelets clamp throughcheckNativeVop3Modifiersand keeps it insupportsNativeVop3Clamp, andinteger16Binarynow passes its result through the existingsaturateInteger16. The i16 forms now read their operands sign-extended. That doesn't change the low 16 bits when clamp is off.The semantics were measured with
tools/hw-oracleon a Ryzen 5 7600X iGPU (gfx1036, RDNA2, wave32). The settings were IEEE=0, DX10_CLAMP=1, denorm32=0, denorm16=3, round32=0, round16=0, fp16_overflow=0. A second run with IEEE=1, DX10_CLAMP=0, denorm 3/3, round toward zero and fp16_overflow=1 gave the same results. The new test,tests/execution/Vop3AddSubClamp.cpp, pins all 32 measured rows for the 7 clamped ops plus an unclampedv_add_nc_u32control. The rows include u32 wrap, the u16/i16 boundaries, and inputs with junk in bits 31:16.The carry ops with clamp still throw. See the issue.
Tested
Nobara Linux 44 (kernel 7.2), Release build.
main+ new testShaderRecompiler::Recompile: VOP3 source modifiers are not implementedVOP3 add/sub clamp tests passedctest -R ^agc_on this branchtools/check_conventions.py --base origin/mainpasses.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)