From e00a03c6f68b30e54e0c75725992bc8bdec1a00c Mon Sep 17 00:00:00 2001 From: claude-noether Date: Mon, 25 May 2026 23:18:17 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20swap=20=5Fv/=5Fh=20dispatch=20fn=20selec?= =?UTF-8?q?tion=20=E2=80=94=20naming=20refers=20to=20filter=20direction=20?= =?UTF-8?q?not=20edge=20direction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/daedalus_decoder.c | 20 ++++++++++++------- tests/test_deblock_smoke.c | 39 +++++++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/daedalus_decoder.c b/src/daedalus_decoder.c index 8394df6..90cacad 100644 --- a/src/daedalus_decoder.c +++ b/src/daedalus_decoder.c @@ -298,21 +298,27 @@ static int dispatch_deblock_pass( uint8_t *, size_t, size_t, const daedalus_h264_deblock_meta *); + /* daedalus-fourier kernel naming convention: + * _v = "v_loop_filter" — filter applied VERTICALLY across a + * HORIZONTAL edge. Use for our orient=1 (H edge). + * _h = "h_loop_filter" — filter applied HORIZONTALLY across a + * VERTICAL edge. Use for our orient=0 (V edge). + * The names refer to the FILTER DIRECTION, not the edge direction. */ deblock_dispatch_fn fn; if (target_plane == 0) { - if (target_orient == 0) - fn = target_bS_intra ? daedalus_dispatch_h264_deblock_luma_v_intra - : daedalus_dispatch_h264_deblock_luma_v; - else + if (target_orient == 0) /* V edge → h_loop_filter */ fn = target_bS_intra ? daedalus_dispatch_h264_deblock_luma_h_intra : daedalus_dispatch_h264_deblock_luma_h; + else /* H edge → v_loop_filter */ + fn = target_bS_intra ? daedalus_dispatch_h264_deblock_luma_v_intra + : daedalus_dispatch_h264_deblock_luma_v; } else { if (target_orient == 0) - fn = target_bS_intra ? daedalus_dispatch_h264_deblock_chroma_v_intra - : daedalus_dispatch_h264_deblock_chroma_v; - else fn = target_bS_intra ? daedalus_dispatch_h264_deblock_chroma_h_intra : daedalus_dispatch_h264_deblock_chroma_h; + else + fn = target_bS_intra ? daedalus_dispatch_h264_deblock_chroma_v_intra + : daedalus_dispatch_h264_deblock_chroma_v; } return fn(dec->dctx, sub, scratch, stride, n, meta_scratch); diff --git a/tests/test_deblock_smoke.c b/tests/test_deblock_smoke.c index 16d5524..d65bf5d 100644 --- a/tests/test_deblock_smoke.c +++ b/tests/test_deblock_smoke.c @@ -105,28 +105,43 @@ static int build_mb_edges(int mb_x, int mb_y, int last_mb_x, int last_mb_y, (e == 0) ? 4 : (int)(1 + xs64() % 3), /*boundary?*/ (e == 0 && mb_y == 0)); - /* V chroma Cb: 2 edges. */ + /* V chroma Cb: 2 edges. Read DEBLOCK_CHROMA_MODE env at runtime: + * unset / "all" → both edges (current default test). + * "intra_only" → only bS=4 boundary edge. + * "none" → all chroma edges bS=0 (luma-only test). + * Lets us bisect substrate divergence without rebuilding. */ + int chroma_intra_only = 0, chroma_none = 0; + const char *cm = getenv("DEBLOCK_CHROMA_MODE"); + if (cm) { + if (!strcmp(cm, "intra_only")) chroma_intra_only = 1; + else if (!strcmp(cm, "none")) chroma_none = 1; + } + for (int e = 0; e < 2; e++) EDGE(0, /*Cb*/1, e, (e == 0) ? 4 : (int)(1 + xs64() % 3), + (chroma_none) || (chroma_intra_only && e != 0) || (e == 0 && mb_x == 0)); /* H chroma Cb. */ for (int e = 0; e < 2; e++) EDGE(1, 1, e, (e == 0) ? 4 : (int)(1 + xs64() % 3), + (chroma_none) || (chroma_intra_only && e != 0) || (e == 0 && mb_y == 0)); /* V chroma Cr. */ for (int e = 0; e < 2; e++) EDGE(0, /*Cr*/2, e, (e == 0) ? 4 : (int)(1 + xs64() % 3), + (chroma_none) || (chroma_intra_only && e != 0) || (e == 0 && mb_x == 0)); /* H chroma Cr. */ for (int e = 0; e < 2; e++) EDGE(1, 2, e, (e == 0) ? 4 : (int)(1 + xs64() % 3), + (chroma_none) || (chroma_intra_only && e != 0) || (e == 0 && mb_y == 0)); #undef EDGE @@ -246,12 +261,30 @@ int main(int argc, char **argv) /* Check 1: CPU vs QPU byte-exact. */ size_t y_diffs = 0, uv_diffs = 0; + size_t y_first = (size_t) -1, uv_first = (size_t) -1; for (size_t i = 0; i < y_size; i++) - if (out_cpu_y[i] != out_qpu_y[i]) y_diffs++; + if (out_cpu_y[i] != out_qpu_y[i]) { + if (y_first == (size_t) -1) y_first = i; + y_diffs++; + } for (size_t i = 0; i < uv_size; i++) - if (out_cpu_uv[i] != out_qpu_uv[i]) uv_diffs++; + if (out_cpu_uv[i] != out_qpu_uv[i]) { + if (uv_first == (size_t) -1) uv_first = i; + uv_diffs++; + } printf("CPU vs QPU: Y diff %zu/%zu, UV diff %zu/%zu\n", y_diffs, y_size, uv_diffs, uv_size); + if (uv_diffs && uv_first != (size_t)-1) { + size_t chroma_w = (size_t) width; /* NV12 UV row pitch = width */ + size_t row = uv_first / chroma_w; + size_t col = uv_first % chroma_w; + size_t mb_x = col / 16; /* NV12 interleaved Cb/Cr; 2 chroma px per pair → 8 chroma cols / MB but 16 NV12 bytes */ + size_t mb_y = row / 8; + printf(" first UV diff at byte %zu (row %zu col %zu) -> MB(%zu,%zu) chroma_%s offset (%zu,%zu)\n", + uv_first, row, col, mb_x, mb_y, + (col & 1) ? "Cr" : "Cb", row % 8, (col % 16) / 2); + printf(" CPU=%u QPU=%u\n", out_cpu_uv[uv_first], out_qpu_uv[uv_first]); + } if (y_diffs != 0 || uv_diffs != 0) { fprintf(stderr, "FAIL: CPU and QPU outputs differ — dispatch wiring broken\n"); return 1;