fix(gpu): cap the MS-SSIM dB output at max_db instead of clamping the linear score - #1382
Draft
lusoris wants to merge 1 commit into
Draft
fix(gpu): cap the MS-SSIM dB output at max_db instead of clamping the linear score#1382lusoris wants to merge 1 commit into
lusoris wants to merge 1 commit into
Conversation
lusoris
force-pushed
the
fix/gpu-ms-ssim-max-db
branch
2 times, most recently
from
September 7, 2026 09:12
61340ed to
913eb8a
Compare
6 tasks
lusoris
force-pushed
the
fix/gpu-ms-ssim-max-db
branch
from
September 7, 2026 10:17
913eb8a to
bec3098
Compare
… linear score
`clip_db` selects a CEILING on the dB output, derived once from the frame
geometry. float_ms_ssim.c computes it at init():
const unsigned peak = (1 << bpc) - 1;
const double mse = 0.5 / (w * h);
s->max_db = clip_db ? ceil(10. * log10(peak * peak / mse)) : INFINITY;
and convert_to_db() returns MIN(-10*log10(1 - score), max_db), short-circuiting
to max_db when score >= 1.0 because log10(0) would be -Inf.
The CUDA, SYCL and HIP twins read clip_db as a clamp on the LINEAR score
instead -- [0, 1] and then an unbounded conversion -- and none of the three
carried a max_db field at all. Two consequences:
1. On an identical reference/distorted pair, MS-SSIM is 1.0, the clamp leaves
it at 1.0, and -10*log10(0) is +Inf where the CPU returns the finite max_db.
Scoring a file against itself is an ordinary thing to do.
2. For every other high-similarity pair the twins returned an unbounded dB
value where the CPU caps it, so clip_db did not clip.
Each twin now derives max_db in init() with the CPU's exact expression and
integer types, and converts through an ms_ssim_convert_to_db() helper that
mirrors the reference including its score >= 1.0 short-circuit.
Verified on an RTX 4090 (CUDA), an Arc A380 (SYCL) and gfx1030 (HIP): with
enable_db=true, clip_db=true and an identical pair, each unfixed twin returns a
non-finite score against the CPU's finite max_db, and each fixed twin matches.
The pre-existing parity tests could not see it: they ran with NULL options, and
with enable_db off neither path converts to dB at all. Each backend now has a
test_ms_ssim_clip_db_ceiling variant. Note that the variant needs an IDENTICAL
pair -- the first version, on the existing high-similarity fixture, passed
against the unfixed twins because the ceiling never binds there.
The Metal MS-SSIM twin exposes only enable_lcs and rejects enable_db / clip_db
outright, so it cannot produce a dB score at all; that is a feature gap rather
than a wrong answer and is tracked separately.
ADR-1221.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
lusoris
force-pushed
the
fix/gpu-ms-ssim-max-db
branch
from
September 7, 2026 12:16
bec3098 to
da6ab0e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
clip_dbselects a ceiling on the dB output, derived once from the framegeometry.
float_ms_ssim.c:The CUDA, SYCL and HIP twins read it as a clamp on the linear score instead,
and none of the three carried a
max_dbfield at all:Two consequences:
+Infon an identical reference/distorted pair. MS-SSIM is1.0, theclamp leaves it at
1.0, and-10 * log10(0)is+Inf. The CPU returns thefinite
max_db. Scoring a file against itself is an ordinary thing to do.clip_dbdid not clip. Every high-similarity pair returned an unboundeddB value where the CPU caps it — the option's whole purpose.
Each twin now derives
max_dbininit()with the CPU's exact expression andinteger types, and converts through an
ms_ssim_convert_to_db()helper thatmirrors the reference, short-circuit included.
Reproducer
meson setup build-cuda core -Denable_cuda=true -Denable_sycl=false -Db_lto=false ninja -C build-cuda meson test -C build-cuda test_cuda_float_ms_ssim_parity --print-errorlogs -vRevert
core/src/feature/cuda/and the new variant fails with:Verified on an RTX 4090 (CUDA), an Arc A380 (SYCL) and gfx1030 (HIP) — each
unfixed twin returns a non-finite score against the CPU's finite
max_db, andeach fixed twin matches. The pre-existing default-options parity tests stay
green.
The fixture had to saturate
The obvious variant — set
enable_db=true, clip_db=trueon the existingfixture — passed against the unfixed twins. On a merely high-similarity pair
-10*log10(1 - score)sits well belowmax_db, so the ceiling never binds.Only feeding the same picture as reference and distorted, driving MS-SSIM to
exactly
1.0, exposes it. A test for a saturating rule has to saturate; that iswritten up in the digest.
Why the existing tests were blind
Every MS-SSIM parity test instantiated its extractors with
NULLoptions, andwith
enable_dboff neither path converts to dB at all — the divergent code wasnever executed. Same shape as ADR-1216 / ADR-1217 / ADR-1220, with one
difference: the twin was not ignoring the option, it was honouring a plausible
misreading of it. A grep for "is this option read anywhere?" finds
clip_dbandmoves on.
Scope
float_ms_ssim_metal.mmexposes onlyenable_lcsand rejectsenable_db/clip_db/enable_chromaoutright, so it cannot emit a dB or chroma score atall. That is a loud failure rather than a wrong answer — a feature gap, tracked
in
docs/state.mdrather than fixed here.Deep-dive deliverables (ADR-0108)
docs/research/2038-clip-db-semantics-drift.md: a twin honouring a plausible misreading of an option name, and why the first version of the parity variant was green against the unfixed code.docs/adr/1221-gpu-ms-ssim-db-ceiling.md## Alternatives considered(four options; the runner-up "just guardscore == 1.0" removes the+Infbut leavesclip_dbstill not clipping).core/src/feature/cuda/AGENTS.md, cross-referenced fromcore/src/feature/sycl/AGENTS.md, with a section incore/src/feature/hip/AGENTS.md.changelog.d/fixed/1221-gpu-ms-ssim-db-ceiling.md.docs/rebase-notes.md— entryADR-1221 — MS-SSIM clip_db is a dB ceiling (2026-09-07).Docs (rule 10)
docs/metrics/ms-ssim.mdgains a note on whatclip_dbmeans, what the twins did instead, and the instruction to re-measureany GPU MS-SSIM dB score taken with it set.
Bug status (rule 13 / ADR-0165)
docs/state.md— closesT-GPU-MS-SSIM-CLIP-DB-SEMANTICS-2026-09-07, and opensT-GAP-METAL-MS-SSIM-DB-CHROMA-OPTIONS-2026-09-07.🤖 Generated with Claude Code