Files
daedalus-fourier/tests/test_intra_pred_chroma8x8.c
T
claude-noether d7100459f2 h264: Intra_8x8 chroma prediction — 4-mode C reference + spec gates
Third intra-prediction primitive after PR #12 (Intra_4x4 luma) and
PR #13 (Intra_16x16 luma).  Covers Intra_8x8 chroma per H.264 §8.3.3:
4 modes used for BOTH Cb and Cr planes at 4:2:0.

Mode quirks worth flagging in code review:

  - Mode 0 DC is asymmetric per quadrant.  The 8x8 chroma block
    splits into four 4x4 quadrants with different DC formulas:
      (0,0) top-left  : (sum_top[0..3] + sum_left[0..3] + 4) >> 3
      (0,1) top-right : (sum_top[4..7]                  + 2) >> 2
      (1,0) bot-left  : (sum_left[4..7]                 + 2) >> 2
      (1,1) bot-right : (sum_top[4..7] + sum_left[4..7] + 4) >> 3
    The top-right quadrant deliberately IGNORES the top-left half
    even though it's available — that's per spec §8.3.3.2.

  - Mode 3 Plane uses slope coefficient 34 (not 5 like Intra_16x16
    luma).  Centre is (x-3, y-3) instead of (x-7, y-7).  Sums span
    4 differences instead of 8.  Easy to copy-paste-bug from the
    luma Plane if you don't notice the constants change.

Test highlights:

  - DC quadrants: distinct expected values per quadrant (16, 16,
    40, 28 from asymmetric top/left halves) — any quadrant mix-up
    would surface immediately.  Hand-derived from the formulas
    in the test comment.
  - Plane uniform: all-100 context → all-100 output (a = 3200,
    H = V = 0, (3200+16) >> 5 = 100 exactly).
  - Plane gradient: top + left = 0..7, hand-derives pred[0][0] = 1
    and pred[7][7] = 15 via the full arithmetic chain (H = V = 56,
    b = c = 30, a = 224).  Same hand-traced spec-walkthrough as
    the Intra_16x16 Plane gradient test.

Verified on hertz:

  $ ./build/test_intra_pred_chroma8x8
    Horizontal (mode 1)            PASS
    Vertical (mode 2)              PASS
    DC quadrants (mode 0)          PASS
    Plane uniform (mode 3)         PASS
    Plane gradient (mode 3)        PASS (corners 1, 15)

  ALL Intra_8x8 chroma mode references PASS

All 5 tests PASS first try.  The DC quadrant correctness is meaningful
(4 different formulas in one kernel) and the Plane gradient corners
validate the slope=34 + centre=(x-3,y-3) constants vs the luma
equivalents.

Combined coverage after this PR:
  - Intra_4x4 luma:   9 modes ✓ (PR #12, all 9 PASS)
  - Intra_16x16 luma: 4 modes ✓ (PR #13, all 5 tests PASS)
  - Intra_8x8 chroma: 4 modes ✓ (this PR, all 5 tests PASS)
  - Intra_8x8 luma (High profile): 9 modes + smoothing — pending.

Remaining backlog: Intra_8x8 luma (High profile, 9 modes + 1-2-1
smoothing pre-filter — distinct algorithm from Intra_4x4 because of
the pre-filter), neighbour-availability fallback, dispatch wrappers.
2026-05-25 00:42:49 +02:00

171 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Tests the 4 H.264 Intra_8x8 chroma prediction modes against
* spec-derived expected patterns. Same buffer layout idea as the
* other intra tests: a buffer that holds the 8x8 output + 1-pixel
* top/left context + 1-pixel top-left corner.
*
* row 0: [tl][t0..t7]
* row 1: [l0][output row 0]
* ...
* row 8: [l7][output row 7]
*
* Dimensions: 9 rows × 9 cols. dst (passed to pred fns) = &buf[1][1].
*/
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
extern void daedalus_h264_pred_chroma8x8_dc_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_horizontal_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_vertical_ref(uint8_t *dst, ptrdiff_t stride);
extern void daedalus_h264_pred_chroma8x8_plane_ref(uint8_t *dst, ptrdiff_t stride);
#define STRIDE 9
#define ROWS 9
static void set_ctx(uint8_t buf[ROWS][STRIDE], int tl,
const int t[8], const int l[8])
{
for (int r = 0; r < ROWS; r++)
for (int c = 0; c < STRIDE; c++) buf[r][c] = 0xff;
buf[0][0] = (uint8_t) tl;
for (int c = 0; c < 8; c++) buf[0][1 + c] = (uint8_t) t[c];
for (int r = 0; r < 8; r++) buf[1 + r][0] = (uint8_t) l[r];
}
static int check_per_cell(const uint8_t buf[ROWS][STRIDE], const char *name,
const uint8_t expect[8][8])
{
int diff = 0;
int first_r = 0, first_c = 0, first_got = 0, first_exp = 0;
for (int r = 0; r < 8; r++) {
for (int c = 0; c < 8; c++) {
uint8_t got = buf[1 + r][1 + c];
uint8_t exp = expect[r][c];
if (got != exp) {
if (diff == 0) {
first_r = r; first_c = c;
first_got = got; first_exp = exp;
}
diff++;
}
}
}
if (diff == 0)
printf(" %-30s PASS\n", name);
else
printf(" %-30s FAIL (%d/64 wrong, first r=%d c=%d got=%u exp=%u)\n",
name, diff, first_r, first_c, first_got, first_exp);
return diff == 0 ? 0 : 1;
}
int main(void)
{
int fail = 0;
/* --- Mode 1 Horizontal --- */
{
uint8_t buf[ROWS][STRIDE];
int t[8] = {0}, l[8] = {10, 20, 30, 40, 50, 60, 70, 80};
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_horizontal_ref(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = (uint8_t) l[r];
fail |= check_per_cell(buf, "Horizontal (mode 1)", exp);
}
/* --- Mode 2 Vertical --- */
{
uint8_t buf[ROWS][STRIDE];
int t[8] = {15, 25, 35, 45, 55, 65, 75, 85}, l[8] = {0};
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_vertical_ref(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = (uint8_t) t[c];
fail |= check_per_cell(buf, "Vertical (mode 2)", exp);
}
/* --- Mode 0 DC: per-quadrant. Test with distinct halves so any
* quadrant mix-up surfaces immediately.
*
* top[0..3] = 4 × 8 → sum_top_lo = 32
* top[4..7] = 4 × 16 → sum_top_hi = 64
* left[0..3] = 4 × 24 → sum_left_lo = 96
* left[4..7] = 4 × 40 → sum_left_hi = 160
*
* dc00 = (32 + 96 + 4) >> 3 = 132/8 = 16
* dc01 = (64 + 2) >> 2 = 66/4 = 16
* dc10 = ( 160 + 2) >> 2 = 162/4 = 40
* dc11 = (64 + 160 + 4) >> 3 = 228/8 = 28
*/
{
uint8_t buf[ROWS][STRIDE];
int t[8] = { 8, 8, 8, 8, 16, 16, 16, 16 };
int l[8] = { 24, 24, 24, 24, 40, 40, 40, 40 };
set_ctx(buf, 99, t, l);
daedalus_h264_pred_chroma8x8_dc_ref(&buf[1][1], STRIDE);
uint8_t exp[8][8] = {
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{16,16,16,16, 16,16,16,16},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
{40,40,40,40, 28,28,28,28},
};
fail |= check_per_cell(buf, "DC quadrants (mode 0)", exp);
}
/* --- Mode 3 Plane (uniform): H = V = 0; a = 16 * (100 + 100) = 3200.
* pred[y][x] = (3200 + 0 + 0 + 16) >> 5 = 3216 >> 5 = 100. */
{
uint8_t buf[ROWS][STRIDE];
int t[8], l[8];
for (int i = 0; i < 8; i++) { t[i] = 100; l[i] = 100; }
set_ctx(buf, 100, t, l);
daedalus_h264_pred_chroma8x8_plane_ref(&buf[1][1], STRIDE);
uint8_t exp[8][8];
for (int r = 0; r < 8; r++) for (int c = 0; c < 8; c++) exp[r][c] = 100;
fail |= check_per_cell(buf, "Plane uniform (mode 3)", exp);
}
/* --- Mode 3 Plane gradient sanity ---
* t = 0..7, l = 0..7, tl = 0.
* H = 1*(t[4]-t[2]) + 2*(t[5]-t[1]) + 3*(t[6]-t[0]) + 4*(t[7]-tl)
* = 1*(4-2) + 2*(5-1) + 3*(6-0) + 4*(7-0)
* = 2 + 8 + 18 + 28 = 56
* V = same shape on left = 56
* b = (34*56 + 32) >> 6 = 1936 >> 6 = 30
* c = 30
* a = 16 * (l[7] + t[7]) = 16 * (7 + 7) = 224
*
* pred[0][0] = (224 + 30*(-3) + 30*(-3) + 16) >> 5
* = (224 - 90 - 90 + 16) >> 5
* = 60 >> 5 = 1
* pred[7][7] = (224 + 30*4 + 30*4 + 16) >> 5
* = (224 + 120 + 120 + 16) >> 5
* = 480 >> 5 = 15
* Spot-check those two corners. */
{
uint8_t buf[ROWS][STRIDE];
int t[8], l[8];
for (int i = 0; i < 8; i++) { t[i] = i; l[i] = i; }
set_ctx(buf, 0, t, l);
daedalus_h264_pred_chroma8x8_plane_ref(&buf[1][1], STRIDE);
uint8_t tl_actual = buf[1 + 0][1 + 0];
uint8_t br_actual = buf[1 + 7][1 + 7];
int spot_fail = 0;
if (tl_actual != 1) { fprintf(stderr, "Plane gradient pred[0][0] = %u, expected 1\n", tl_actual); spot_fail = 1; }
if (br_actual != 15) { fprintf(stderr, "Plane gradient pred[7][7] = %u, expected 15\n", br_actual); spot_fail = 1; }
if (!spot_fail) printf(" %-30s PASS (corners 1, 15)\n", "Plane gradient (mode 3)");
else printf(" %-30s FAIL\n", "Plane gradient (mode 3)");
fail |= spot_fail;
}
if (fail == 0) printf("\nALL Intra_8x8 chroma mode references PASS\n");
else fprintf(stderr, "\n%d test(s) FAILED\n", fail);
return fail ? 1 : 0;
}