Clamp the patch merge to ±2π in the native Swin encoders

NVIDIA's enc1 and enc2 clamp the patch merge's result to ±2π (as f16) before
its e4m3 encoding (max.f16x2 / min.f16x2 with 0fC0C90FDB / 0f40C90FDB after the
merge's last MMA). The native layers did not, in either template or set:
merge_clamp (swin_common.h) now does, at the three sites that encode the merged
tokens (swin_block.h's e4m3-activation and f16 paths, swin_tok.h), and
swin_check.py's model clamps the same way.

Measured on an RX 9070 XT against a run with no native kernels (preset L,
accuracy set, the flags of Ghost of Tsushima, 1280x720 -> 3840x2160, one
frame): native enc1 alone 34 dB and enc2 alone 31 dB from the translated
kernels before, byte-identical after; the whole native set 28 -> 80 dB (the
rest is dec1, 0.09% of the output values). Preset M's fast set against
translated M: 30.8 -> 35.1 dB after 30 frames. The gfx11 path has the same
change and was not run on hardware.

The repo's tests pass (36, 3 skipped).
This commit is contained in:
woutermans committed 2026-10-08 02:21:41 +02:00
1 parent 62738a01cc
commit 934fb486c7
5 files changed
+22 -4

No files matched your search

+3 -2
View File
@@ -975,7 +975,8 @@ __device__ __forceinline__ void swin_block(const CommonParams& p, const TubePara
continue;
const int ch = ginv(16 * (wv * NTP + j) + l16);
#ifdef SWIN_A8
const uint32_t code[2] = {codes4(y[j].pair(0), y[j].pair(1)), codes4(y[j].pair(2), y[j].pair(3))};
const uint32_t code[2] = {codes4(merge_clamp(y[j].pair(0)), merge_clamp(y[j].pair(1))),
codes4(merge_clamp(y[j].pair(2)), merge_clamp(y[j].pair(3)))};
#endif
#pragma unroll
for (int i = 0; i < 8; ++i)
@@ -988,7 +989,7 @@ __device__ __forceinline__ void swin_block(const CommonParams& p, const TubePara
#ifdef SWIN_A8
(uint8_t)(code[i >> 2] >> (8 * (i & 3)));
#else
(uint8_t)enc8(y[j].get(i));
(uint8_t)enc8(merge_clamp(y[j].get(i)));
#endif
}
}