mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-24 03:38:52 +08:00
[AGC] Support the clamp modifier on packed f16 VOP3P ops (#460)
The VOP3P emitter rejected any packed op with the clamp bit set. Clamp saturates each f16 output half to [0, 1] (and flushes NaN to 0, matching RDNA), so games that emit clamped packed arithmetic fell back to a loud emit failure. Apply the saturation to the f32 result of each lane, before it is narrowed back to f16. Because 0.0 and 1.0 are exact in both f32 and f16 and the clamp is monotonic, clamping in f32 and then rounding to f16 yields the same value as clamping the f16 result directly; for the fused multiply-add the pre-narrowing value is the round-to-odd f32, which preserves that equivalence through the final round-to-nearest-even. The saturation uses ordered compares so a NaN result collapses to 0 without a separate IsNan test. Verification: - The local exact-reference harness now also clamps: add, mul, and fma each compared against an f16-domain clamp reference (NaN -> 0, else [0, 1]) over directed boundary inputs and 24M random cases. 0 mismatches, alongside the existing 34M unclamped fma cases. - ShaderDump pk-f16 gains a clamped add and a clamped fma; all decode and emit. - The exec program computes the pinned fma with clamp (both lanes exceed 1.0, so each saturates to 0x3C00) and stores it at offset 28; GpuConformance checks it on device. All values match on an AMD Radeon RX 7700 XT.
This commit is contained in:
committed by
GitHub
parent
33be88bdf9
commit
472fc96a37
@@ -17,6 +17,8 @@
|
||||
// multiply-add would give 0x7A6A instead
|
||||
// [6] the same fma with the addend negated -> 0x7A6A packed (just below the
|
||||
// same midpoint), pinning the opposite rounding direction
|
||||
// [7] the pinned fma with the clamp modifier -> 0x3C00 packed (both lanes
|
||||
// exceed 1.0, so each saturates to 1.0)
|
||||
// Every other word of the buffer must still hold the sentinel afterwards.
|
||||
//
|
||||
// Creating the compute pipeline doubles as a driver-acceptance check for the
|
||||
@@ -45,6 +47,9 @@ var expectedRestored = BitConverter.SingleToUInt32Bits(1.5f);
|
||||
// addend decides the rounding direction under a single fused rounding.
|
||||
const uint ExpectedPkFma = 0x7A6B_7A6B;
|
||||
const uint ExpectedPkFmaNeg = 0x7A6A_7A6A;
|
||||
// Both lanes of the pinned fma are ~52560, far above 1.0, so the clamp modifier
|
||||
// saturates each to 1.0 (0x3C00 in f16).
|
||||
const uint ExpectedPkFmaClamp = 0x3C00_3C00;
|
||||
|
||||
unsafe
|
||||
{
|
||||
@@ -365,6 +370,7 @@ unsafe
|
||||
("store after exec restore (offset 16)", words[4], expectedRestored),
|
||||
("v_pk_fma_f16 fused rounds up at midpoint", words[5], ExpectedPkFma),
|
||||
("v_pk_fma_f16 neg addend rounds down", words[6], ExpectedPkFmaNeg),
|
||||
("v_pk_fma_f16 clamp saturates to 1.0", words[7], ExpectedPkFmaClamp),
|
||||
};
|
||||
var failures = 0;
|
||||
foreach (var (name, actual, expected) in results)
|
||||
|
||||
@@ -57,6 +57,8 @@ const ulong ProgramAddress = 0x100000;
|
||||
0xCC114006, 0x18020300, // v_pk_min_f16 v6, v0, v1
|
||||
0xCC124007, 0x18020300, // v_pk_max_f16 v7, v0, v1
|
||||
0xCC0E4408, 0x9C0A0300, // v_pk_fma_f16 v8, v0, v1, neg_lo:[0,0,1] neg_hi:[0,0,1] v2
|
||||
0xCC0FC009, 0x18020000, // v_pk_add_f16 v9, v0, v0 clamp (2.5+2.5=5 -> saturates to 1.0)
|
||||
0xCC0EC40A, 0x1C0A0300, // v_pk_fma_f16 v10, v0, v1, v2 clamp
|
||||
0xBF810000, // s_endpgm
|
||||
]),
|
||||
("mrt", true, [
|
||||
@@ -158,8 +160,10 @@ const ulong ProgramAddress = 0x100000;
|
||||
0x7E1202FF, 0x04EA04EA, // v_mov_b32 v9, 0x04EA04EA (~7.496e-5 packed)
|
||||
0xCC0E400A, 0x1C261107, // v_pk_fma_f16 v10, v7, v8, v9
|
||||
0xCC0E440B, 0x9C261107, // v_pk_fma_f16 v11, v7, v8, neg_lo:[0,0,1] neg_hi:[0,0,1] v9
|
||||
0xCC0EC00C, 0x1C261107, // v_pk_fma_f16 v12, v7, v8, v9 clamp (>=1 -> saturates to 1.0)
|
||||
0xE0700014, 0x80020A00, // buffer_store_dword v10, off, s[8:11], 0 offset:20
|
||||
0xE0700018, 0x80020B00, // buffer_store_dword v11, off, s[8:11], 0 offset:24
|
||||
0xE070001C, 0x80020C00, // buffer_store_dword v12, off, s[8:11], 0 offset:28
|
||||
0xBF810000, // s_endpgm
|
||||
]),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user