wip: predicted samples plumbing
This commit is contained in:
+63
-15
@@ -1,12 +1,16 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
/*
|
||||
* test_idct_bitexact — phase1 stage1 bit-exact gate for the frame-
|
||||
* scaled luma IDCT 4×4 dispatch.
|
||||
* scaled luma + chroma IDCT 4×4 / 8×8 dispatch + Stage 2 predicted-
|
||||
* samples plumbing.
|
||||
*
|
||||
* Generates a frame of random coefficients, runs daedalus_decoder
|
||||
* (with predicted=0 by the scaffold's flush_frame contract), and
|
||||
* compares every output byte against an inline C reference that
|
||||
* mirrors the H.264 §8.5.12.1 1D butterfly.
|
||||
* Generates a frame of random coefficients AND random predicted
|
||||
* samples per MB, runs daedalus_decoder (which writes the predicted
|
||||
* samples into its frame-scoped predicted_y/_uv buffers via
|
||||
* append_mb, then pre-fills the IDCT dispatch scratch from them in
|
||||
* flush_frame), and compares every output byte against an inline C
|
||||
* reference that mirrors the H.264 §8.5.12.1 1D butterfly applied
|
||||
* to the same predicted+coeffs inputs.
|
||||
*
|
||||
* Why "bit-exact": the GPU shader and the C reference apply the same
|
||||
* integer arithmetic. Any rounding / sign / overflow disagreement is
|
||||
@@ -30,7 +34,7 @@
|
||||
* Not in scope (covered by other tests / future PRs):
|
||||
* - Chroma DC / Intra16x16 DC Hadamard pre-pass
|
||||
* - bit-exactness against real H.264 streams (test-vector PR)
|
||||
* - non-zero predicted pixels (intra prediction lands in Stage 2a)
|
||||
* - deblock (lands in Stage 2 PR-b after this one)
|
||||
*/
|
||||
|
||||
#include "daedalus_decoder.h"
|
||||
@@ -202,15 +206,25 @@ int main(int argc, char **argv)
|
||||
|
||||
/* Build the per-MB inputs. Each MB gets 16 luma 4×4 blocks of
|
||||
* random coeffs in [-512, 511] — same range as the daedalus-fourier
|
||||
* cycle-6 M1 gate uses. */
|
||||
int16_t (*per_mb_coeffs)[384] = malloc((size_t) n_mbs * sizeof(*per_mb_coeffs));
|
||||
if (!per_mb_coeffs) { fprintf(stderr, "alloc fail\n"); return 1; }
|
||||
* cycle-6 M1 gate uses. Plus random predicted samples (uint8 each)
|
||||
* to exercise the Stage 2 predicted-samples plumbing — when this
|
||||
* is non-zero, flush_frame must pre-fill the IDCT-dispatch scratch
|
||||
* from dec->predicted_y / dec->predicted_uv (Stage 2 PR-a) rather
|
||||
* than from calloc-zero (the Stage 1 scaffold contract). The
|
||||
* reference path mirrors this by pre-filling ref_y / ref_cb / ref_cr
|
||||
* from the same predicted bytes BEFORE the per-block ref_idct*_add
|
||||
* calls — so the test catches any mismatch between caller-supplied
|
||||
* predicted and what reaches the GPU's IDCT-add starting state. */
|
||||
int16_t (*per_mb_coeffs)[384] = malloc((size_t) n_mbs * sizeof(*per_mb_coeffs));
|
||||
uint8_t (*per_mb_predicted)[384] = malloc((size_t) n_mbs * sizeof(*per_mb_predicted));
|
||||
if (!per_mb_coeffs || !per_mb_predicted) { fprintf(stderr, "alloc fail\n"); return 1; }
|
||||
|
||||
for (int mb = 0; mb < n_mbs; mb++) {
|
||||
for (int i = 0; i < 384; i++) {
|
||||
/* Random coeffs in [-512, 511] for all of luma + Cb + Cr.
|
||||
* Same range as the daedalus-fourier cycle-6 M1 gate. */
|
||||
/* Random coeffs in [-512, 511] for all of luma + Cb + Cr. */
|
||||
per_mb_coeffs[mb][i] = (int16_t)((int)(xs64() % 1024) - 512);
|
||||
/* Random predicted samples in [0, 255]. */
|
||||
per_mb_predicted[mb][i] = (uint8_t)(xs64() & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,6 +244,7 @@ int main(int argc, char **argv)
|
||||
mb.mb_x = (uint16_t) mx;
|
||||
mb.mb_y = (uint16_t) my;
|
||||
mb.coeffs = per_mb_coeffs[idx];
|
||||
mb.predicted = per_mb_predicted[idx];
|
||||
mb.transform_8x8 = mb_8x8[idx];
|
||||
if (mb_8x8[idx]) n_8x8_mbs++; else n_4x4_mbs++;
|
||||
if (daedalus_decoder_append_mb(dec, &mb) != 0) {
|
||||
@@ -256,9 +271,26 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Compute the reference output: same per-MB → flat raster block
|
||||
* layout as flush_frame uses. Branch per MB on transform_8x8. */
|
||||
uint8_t *ref_y = calloc(1, y_size);
|
||||
* layout as flush_frame uses. Branch per MB on transform_8x8.
|
||||
*
|
||||
* ref_y is pre-filled with each MB's 16×16 luma predicted samples
|
||||
* at raster (my*16, mx*16), then ref_idct4_add/8_add overlay the
|
||||
* residual via FFmpeg `idct_add` semantics (dst += idct(coeffs);
|
||||
* clip255). This mirrors what flush_frame does on the GPU side:
|
||||
* scratch_y starts from dec->predicted_y, IDCT-add writes back. */
|
||||
uint8_t *ref_y = malloc(y_size);
|
||||
if (!ref_y) return 1;
|
||||
for (int my = 0; my < mb_h; my++) {
|
||||
for (int mx = 0; mx < mb_w; mx++) {
|
||||
int mb_idx = my * mb_w + mx;
|
||||
const uint8_t *p_y = per_mb_predicted[mb_idx]; /* [0..256) */
|
||||
for (int r = 0; r < 16; r++) {
|
||||
memcpy(&ref_y[((size_t) my * 16 + r) * (size_t) width
|
||||
+ (size_t) mx * 16],
|
||||
&p_y[r * 16], 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
int16_t block_scratch[64]; /* large enough for 8x8 */
|
||||
for (int my = 0; my < mb_h; my++) {
|
||||
for (int mx = 0; mx < mb_w; mx++) {
|
||||
@@ -302,9 +334,24 @@ int main(int argc, char **argv)
|
||||
size_t chroma_w = (size_t) width / 2;
|
||||
size_t chroma_h = (size_t) height / 2;
|
||||
size_t chroma_plane_size = chroma_w * chroma_h;
|
||||
uint8_t *ref_cb = calloc(1, chroma_plane_size);
|
||||
uint8_t *ref_cr = calloc(1, chroma_plane_size);
|
||||
uint8_t *ref_cb = malloc(chroma_plane_size);
|
||||
uint8_t *ref_cr = malloc(chroma_plane_size);
|
||||
if (!ref_cb || !ref_cr) return 1;
|
||||
/* Pre-fill ref_cb / ref_cr with per-MB 8x8 chroma predicted samples
|
||||
* (mirrors the predicted-samples plumbing on the chroma path). */
|
||||
for (int my = 0; my < mb_h; my++) {
|
||||
for (int mx = 0; mx < mb_w; mx++) {
|
||||
int mb_idx = my * mb_w + mx;
|
||||
const uint8_t *p_cb = per_mb_predicted[mb_idx] + 256;
|
||||
const uint8_t *p_cr = per_mb_predicted[mb_idx] + 256 + 64;
|
||||
for (int r = 0; r < 8; r++) {
|
||||
memcpy(&ref_cb[((size_t) my * 8 + r) * chroma_w + (size_t) mx * 8],
|
||||
&p_cb[r * 8], 8);
|
||||
memcpy(&ref_cr[((size_t) my * 8 + r) * chroma_w + (size_t) mx * 8],
|
||||
&p_cr[r * 8], 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int my = 0; my < mb_h; my++) {
|
||||
for (int mx = 0; mx < mb_w; mx++) {
|
||||
int mb_idx = my * mb_w + mx;
|
||||
@@ -386,6 +433,7 @@ int main(int argc, char **argv)
|
||||
free(gpu_uv);
|
||||
free(gpu_y);
|
||||
free(mb_8x8);
|
||||
free(per_mb_predicted);
|
||||
free(per_mb_coeffs);
|
||||
daedalus_decoder_destroy(dec);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user