std/vp8: calculate the predicted values

This commit, part of a series, is inspired by pull request PR #168 by
Damian Kaczmarek (with AI assistance), with some modifications.

Updates PR #168
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index f8b059c..30f100b 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -15532,6 +15532,7 @@
     uint16_t f_dequants[4][3][2];
     uint32_t f_prob_skip;
     uint8_t f_mb_subblock_modes[16];
+    uint8_t f_yuv_cache[26][32];
     uint32_t f_dst_x;
     uint32_t f_dst_y;
     wuffs_base__pixel_swizzler f_swizzler;
@@ -80976,6 +80977,138 @@
 };
 
 static const uint8_t
+WUFFS_VP8__CLAMP[1024] WUFFS_BASE__POTENTIALLY_UNUSED = {
+  0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u,
+  8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u,
+  16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u,
+  24u, 25u, 26u, 27u, 28u, 29u, 30u, 31u,
+  32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u,
+  40u, 41u, 42u, 43u, 44u, 45u, 46u, 47u,
+  48u, 49u, 50u, 51u, 52u, 53u, 54u, 55u,
+  56u, 57u, 58u, 59u, 60u, 61u, 62u, 63u,
+  64u, 65u, 66u, 67u, 68u, 69u, 70u, 71u,
+  72u, 73u, 74u, 75u, 76u, 77u, 78u, 79u,
+  80u, 81u, 82u, 83u, 84u, 85u, 86u, 87u,
+  88u, 89u, 90u, 91u, 92u, 93u, 94u, 95u,
+  96u, 97u, 98u, 99u, 100u, 101u, 102u, 103u,
+  104u, 105u, 106u, 107u, 108u, 109u, 110u, 111u,
+  112u, 113u, 114u, 115u, 116u, 117u, 118u, 119u,
+  120u, 121u, 122u, 123u, 124u, 125u, 126u, 127u,
+  128u, 129u, 130u, 131u, 132u, 133u, 134u, 135u,
+  136u, 137u, 138u, 139u, 140u, 141u, 142u, 143u,
+  144u, 145u, 146u, 147u, 148u, 149u, 150u, 151u,
+  152u, 153u, 154u, 155u, 156u, 157u, 158u, 159u,
+  160u, 161u, 162u, 163u, 164u, 165u, 166u, 167u,
+  168u, 169u, 170u, 171u, 172u, 173u, 174u, 175u,
+  176u, 177u, 178u, 179u, 180u, 181u, 182u, 183u,
+  184u, 185u, 186u, 187u, 188u, 189u, 190u, 191u,
+  192u, 193u, 194u, 195u, 196u, 197u, 198u, 199u,
+  200u, 201u, 202u, 203u, 204u, 205u, 206u, 207u,
+  208u, 209u, 210u, 211u, 212u, 213u, 214u, 215u,
+  216u, 217u, 218u, 219u, 220u, 221u, 222u, 223u,
+  224u, 225u, 226u, 227u, 228u, 229u, 230u, 231u,
+  232u, 233u, 234u, 235u, 236u, 237u, 238u, 239u,
+  240u, 241u, 242u, 243u, 244u, 245u, 246u, 247u,
+  248u, 249u, 250u, 251u, 252u, 253u, 254u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+  0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u,
+};
+
+static const uint8_t
 WUFFS_VP8__SUBBLOCK_MODE_PROBS[10][10][9] WUFFS_BASE__POTENTIALLY_UNUSED = {
   {
     {
@@ -81688,8 +81821,7 @@
     uint32_t a_mbx,
     uint32_t a_mby,
     uint32_t a_seg,
-    uint32_t a_luma_mode,
-    uint32_t a_chroma_mode);
+    uint32_t a_luma_mode);
 
 WUFFS_BASE__GENERATED_C_CODE
 static wuffs_base__empty_struct
@@ -81806,6 +81938,51 @@
     uint8_t a_left_mode);
 
 WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_y4(
+    wuffs_vp8__decoder* self,
+    uint32_t a_b);
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_y16(
+    wuffs_vp8__decoder* self,
+    uint32_t a_mode);
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_uv8(
+    wuffs_vp8__decoder* self,
+    uint32_t a_b,
+    uint32_t a_mode);
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__reconstruct(
+    wuffs_vp8__decoder* self,
+    wuffs_base__slice_u8 a_workbuf,
+    uint32_t a_mbx,
+    uint32_t a_mby,
+    uint32_t a_luma_mode,
+    uint32_t a_chroma_mode);
+
+WUFFS_BASE__GENERATED_C_CODE
+static uint32_t
+wuffs_vp8__decoder__substitute_dc_top_left(
+    const wuffs_vp8__decoder* self,
+    uint32_t a_mode,
+    uint32_t a_mbx,
+    uint32_t a_mby);
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__prepare_yuv_cache(
+    wuffs_vp8__decoder* self,
+    wuffs_base__slice_u8 a_workbuf,
+    uint32_t a_mbx,
+    uint32_t a_mby);
+
+WUFFS_BASE__GENERATED_C_CODE
 static wuffs_base__status
 wuffs_vp8__decoder__do_decode_image_config(
     wuffs_vp8__decoder* self,
@@ -82040,8 +82217,7 @@
     uint32_t a_mbx,
     uint32_t a_mby,
     uint32_t a_seg,
-    uint32_t a_luma_mode,
-    uint32_t a_chroma_mode) {
+    uint32_t a_luma_mode) {
   uint32_t v_bc = 0;
   uint32_t v_by = 0;
   uint32_t v_bx = 0;
@@ -82679,9 +82855,14 @@
         a_mbx,
         a_mby,
         v_seg,
-        v_luma_mode,
-        v_chroma_mode);
+        v_luma_mode);
   }
+  wuffs_vp8__decoder__reconstruct(self,
+      a_workbuf,
+      a_mbx,
+      a_mby,
+      v_luma_mode,
+      v_chroma_mode);
   return wuffs_base__make_empty_struct();
 }
 
@@ -82830,6 +83011,869 @@
   return 9u;
 }
 
+// -------- func vp8.decoder.predict_y4
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_y4(
+    wuffs_vp8__decoder* self,
+    uint32_t a_b) {
+  uint32_t v_cachey = 0;
+  uint32_t v_cachex = 0;
+  uint32_t v_mode = 0;
+  uint32_t v_z = 0;
+  uint8_t v_avg = 0;
+  uint32_t v_tm0 = 0;
+  uint32_t v_tm1 = 0;
+  uint32_t v_tm2 = 0;
+  uint32_t v_a = 0;
+  uint32_t v_b = 0;
+  uint32_t v_c = 0;
+  uint32_t v_d = 0;
+  uint32_t v_e = 0;
+  uint32_t v_f = 0;
+  uint32_t v_g = 0;
+  uint32_t v_h = 0;
+  uint32_t v_i = 0;
+  uint32_t v_p = 0;
+  uint32_t v_q = 0;
+  uint32_t v_r = 0;
+  uint32_t v_s = 0;
+  uint8_t v_ab = 0;
+  uint8_t v_bc = 0;
+  uint8_t v_cd = 0;
+  uint8_t v_de = 0;
+  uint8_t v_ef = 0;
+  uint8_t v_pa = 0;
+  uint8_t v_qp = 0;
+  uint8_t v_rq = 0;
+  uint8_t v_sr = 0;
+  uint8_t v_abc = 0;
+  uint8_t v_bcd = 0;
+  uint8_t v_cde = 0;
+  uint8_t v_def = 0;
+  uint8_t v_efg = 0;
+  uint8_t v_fgh = 0;
+  uint8_t v_ghi = 0;
+  uint8_t v_hii = 0;
+  uint8_t v_pab = 0;
+  uint8_t v_qpa = 0;
+  uint8_t v_rqp = 0;
+  uint8_t v_srq = 0;
+  uint8_t v_ssr = 0;
+  uint8_t v_sss = 0;
+
+  v_cachey = ((a_b & 12u) + 1u);
+  v_cachex = (((a_b & 3u) * 4u) + 8u);
+  v_mode = ((uint32_t)(self->private_impl.f_mb_subblock_modes[a_b]));
+  if (v_mode == 0u) {
+    v_avg = ((uint8_t)(((4u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)]))) / 8u)));
+    v_z = 0u;
+    while (v_z < 16u) {
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 2u))][(v_cachex + (v_z & 3u))] = v_avg;
+      v_z += 1u;
+    }
+  } else if (v_mode == 1u) {
+    v_tm0 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_z = 0u;
+    while (v_z < 16u) {
+      v_tm1 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 2u))][(v_cachex - 1u)]));
+      v_tm2 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + (v_z & 3u))]));
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 2u))][(v_cachex + (v_z & 3u))] = WUFFS_VP8__CLAMP[(((uint32_t)((v_tm1 + v_tm2) - v_tm0)) & 1023u)];
+      v_z += 1u;
+    }
+  } else if (v_mode == 2u) {
+    v_a = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_e = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)]));
+    v_f = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 4u)]));
+    v_def = ((uint8_t)(((v_d +
+        (2u * v_e) +
+        v_f +
+        2u) / 4u)));
+    v_cde = ((uint8_t)(((v_c +
+        (2u * v_d) +
+        v_e +
+        2u) / 4u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    v_abc = ((uint8_t)(((v_a +
+        (2u * v_b) +
+        v_c +
+        2u) / 4u)));
+    v_z = 0u;
+    while (v_z < 4u) {
+      self->private_impl.f_yuv_cache[(v_cachey + v_z)][v_cachex] = v_abc;
+      self->private_impl.f_yuv_cache[(v_cachey + v_z)][(v_cachex + 1u)] = v_bcd;
+      self->private_impl.f_yuv_cache[(v_cachey + v_z)][(v_cachex + 2u)] = v_cde;
+      self->private_impl.f_yuv_cache[(v_cachey + v_z)][(v_cachex + 3u)] = v_def;
+      v_z += 1u;
+    }
+  } else if (v_mode == 3u) {
+    v_s = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)]));
+    v_r = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)]));
+    v_q = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)]));
+    v_p = ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)]));
+    v_a = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_qpa = ((uint8_t)(((v_q +
+        (2u * v_p) +
+        v_a +
+        2u) / 4u)));
+    v_rqp = ((uint8_t)(((v_r +
+        (2u * v_q) +
+        v_p +
+        2u) / 4u)));
+    v_srq = ((uint8_t)(((v_s +
+        (2u * v_r) +
+        v_q +
+        2u) / 4u)));
+    v_ssr = ((uint8_t)(((v_s +
+        (2u * v_s) +
+        v_r +
+        2u) / 4u)));
+    v_z = 0u;
+    while (v_z < 4u) {
+      self->private_impl.f_yuv_cache[v_cachey][(v_cachex + v_z)] = v_qpa;
+      self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + v_z)] = v_rqp;
+      self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + v_z)] = v_srq;
+      self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + v_z)] = v_ssr;
+      v_z += 1u;
+    }
+  } else if (v_mode == 4u) {
+    v_s = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)]));
+    v_r = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)]));
+    v_q = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)]));
+    v_p = ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)]));
+    v_a = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_e = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)]));
+    v_cde = ((uint8_t)(((v_c +
+        (2u * v_d) +
+        v_e +
+        2u) / 4u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    v_abc = ((uint8_t)(((v_a +
+        (2u * v_b) +
+        v_c +
+        2u) / 4u)));
+    v_pab = ((uint8_t)(((v_p +
+        (2u * v_a) +
+        v_b +
+        2u) / 4u)));
+    v_qpa = ((uint8_t)(((v_q +
+        (2u * v_p) +
+        v_a +
+        2u) / 4u)));
+    v_rqp = ((uint8_t)(((v_r +
+        (2u * v_q) +
+        v_p +
+        2u) / 4u)));
+    v_srq = ((uint8_t)(((v_s +
+        (2u * v_r) +
+        v_q +
+        2u) / 4u)));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_pab;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_abc;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_bcd;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_cde;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_pab;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_abc;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_bcd;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_rqp;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_pab;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_abc;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_srq;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_rqp;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_pab;
+  } else if (v_mode == 5u) {
+    v_r = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)]));
+    v_q = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)]));
+    v_p = ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)]));
+    v_a = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_e = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)]));
+    v_ab = ((uint8_t)(((v_a + v_b + 1u) / 2u)));
+    v_bc = ((uint8_t)(((v_b + v_c + 1u) / 2u)));
+    v_cd = ((uint8_t)(((v_c + v_d + 1u) / 2u)));
+    v_de = ((uint8_t)(((v_d + v_e + 1u) / 2u)));
+    v_cde = ((uint8_t)(((v_c +
+        (2u * v_d) +
+        v_e +
+        2u) / 4u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    v_abc = ((uint8_t)(((v_a +
+        (2u * v_b) +
+        v_c +
+        2u) / 4u)));
+    v_pab = ((uint8_t)(((v_p +
+        (2u * v_a) +
+        v_b +
+        2u) / 4u)));
+    v_qpa = ((uint8_t)(((v_q +
+        (2u * v_p) +
+        v_a +
+        2u) / 4u)));
+    v_rqp = ((uint8_t)(((v_r +
+        (2u * v_q) +
+        v_p +
+        2u) / 4u)));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_ab;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_bc;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_cd;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_de;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_pab;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_abc;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_bcd;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_cde;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_ab;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_bc;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_cd;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_rqp;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_pab;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_abc;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_bcd;
+  } else if (v_mode == 6u) {
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_e = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)]));
+    v_f = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 4u)]));
+    v_g = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 5u)]));
+    v_h = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 6u)]));
+    v_i = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 7u)]));
+    v_hii = ((uint8_t)(((v_h +
+        (2u * v_i) +
+        v_i +
+        2u) / 4u)));
+    v_ghi = ((uint8_t)(((v_g +
+        (2u * v_h) +
+        v_i +
+        2u) / 4u)));
+    v_fgh = ((uint8_t)(((v_f +
+        (2u * v_g) +
+        v_h +
+        2u) / 4u)));
+    v_efg = ((uint8_t)(((v_e +
+        (2u * v_f) +
+        v_g +
+        2u) / 4u)));
+    v_def = ((uint8_t)(((v_d +
+        (2u * v_e) +
+        v_f +
+        2u) / 4u)));
+    v_cde = ((uint8_t)(((v_c +
+        (2u * v_d) +
+        v_e +
+        2u) / 4u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_bcd;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_cde;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_def;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_cde;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_def;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_fgh;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_def;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_fgh;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_ghi;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_fgh;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_ghi;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_hii;
+  } else if (v_mode == 7u) {
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_e = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)]));
+    v_f = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 4u)]));
+    v_g = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 5u)]));
+    v_h = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 6u)]));
+    v_i = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 7u)]));
+    v_ef = ((uint8_t)(((v_e + v_f + 1u) / 2u)));
+    v_de = ((uint8_t)(((v_d + v_e + 1u) / 2u)));
+    v_cd = ((uint8_t)(((v_c + v_d + 1u) / 2u)));
+    v_bc = ((uint8_t)(((v_b + v_c + 1u) / 2u)));
+    v_ghi = ((uint8_t)(((v_g +
+        (2u * v_h) +
+        v_i +
+        2u) / 4u)));
+    v_fgh = ((uint8_t)(((v_f +
+        (2u * v_g) +
+        v_h +
+        2u) / 4u)));
+    v_efg = ((uint8_t)(((v_e +
+        (2u * v_f) +
+        v_g +
+        2u) / 4u)));
+    v_def = ((uint8_t)(((v_d +
+        (2u * v_e) +
+        v_f +
+        2u) / 4u)));
+    v_cde = ((uint8_t)(((v_c +
+        (2u * v_d) +
+        v_e +
+        2u) / 4u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_bc;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_cd;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_de;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_ef;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_bcd;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_cde;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_def;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_cd;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_de;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_ef;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_fgh;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_cde;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_def;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_efg;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_ghi;
+  } else if (v_mode == 8u) {
+    v_s = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)]));
+    v_r = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)]));
+    v_q = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)]));
+    v_p = ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)]));
+    v_a = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_b = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex]));
+    v_c = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)]));
+    v_d = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)]));
+    v_sr = ((uint8_t)(((v_s + v_r + 1u) / 2u)));
+    v_rq = ((uint8_t)(((v_r + v_q + 1u) / 2u)));
+    v_qp = ((uint8_t)(((v_q + v_p + 1u) / 2u)));
+    v_pa = ((uint8_t)(((v_p + v_a + 1u) / 2u)));
+    v_bcd = ((uint8_t)(((v_b +
+        (2u * v_c) +
+        v_d +
+        2u) / 4u)));
+    v_abc = ((uint8_t)(((v_a +
+        (2u * v_b) +
+        v_c +
+        2u) / 4u)));
+    v_pab = ((uint8_t)(((v_p +
+        (2u * v_a) +
+        v_b +
+        2u) / 4u)));
+    v_qpa = ((uint8_t)(((v_q +
+        (2u * v_p) +
+        v_a +
+        2u) / 4u)));
+    v_rqp = ((uint8_t)(((v_r +
+        (2u * v_q) +
+        v_p +
+        2u) / 4u)));
+    v_srq = ((uint8_t)(((v_s +
+        (2u * v_r) +
+        v_q +
+        2u) / 4u)));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_pa;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_pab;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_abc;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_bcd;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_qp;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_pa;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_pab;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_rq;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_rqp;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_qp;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_qpa;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_sr;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_srq;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_rq;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_rqp;
+  } else {
+    v_s = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)]));
+    v_r = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)]));
+    v_q = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)]));
+    v_p = ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)]));
+    v_sr = ((uint8_t)(((v_s + v_r + 1u) / 2u)));
+    v_rq = ((uint8_t)(((v_r + v_q + 1u) / 2u)));
+    v_qp = ((uint8_t)(((v_q + v_p + 1u) / 2u)));
+    v_rqp = ((uint8_t)(((v_r +
+        (2u * v_q) +
+        v_p +
+        2u) / 4u)));
+    v_srq = ((uint8_t)(((v_s +
+        (2u * v_r) +
+        v_q +
+        2u) / 4u)));
+    v_ssr = ((uint8_t)(((v_s +
+        (2u * v_s) +
+        v_r +
+        2u) / 4u)));
+    v_sss = ((uint8_t)(v_s));
+    self->private_impl.f_yuv_cache[v_cachey][v_cachex] = v_qp;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 1u)] = v_rqp;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 2u)] = v_rq;
+    self->private_impl.f_yuv_cache[v_cachey][(v_cachex + 3u)] = v_srq;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][v_cachex] = v_rq;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 1u)] = v_srq;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 2u)] = v_sr;
+    self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex + 3u)] = v_ssr;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][v_cachex] = v_sr;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 1u)] = v_ssr;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 2u)] = v_sss;
+    self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex + 3u)] = v_sss;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][v_cachex] = v_sss;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 1u)] = v_sss;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 2u)] = v_sss;
+    self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex + 3u)] = v_sss;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func vp8.decoder.predict_y16
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_y16(
+    wuffs_vp8__decoder* self,
+    uint32_t a_mode) {
+  uint32_t v_x = 0;
+  uint32_t v_y = 0;
+  uint32_t v_z = 0;
+  uint8_t v_avg = 0;
+  uint8_t v_val = 0;
+  uint32_t v_tm0 = 0;
+  uint32_t v_tm1 = 0;
+  uint32_t v_tm2 = 0;
+
+  if (a_mode == 0u) {
+    v_avg = ((uint8_t)(((16u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][8u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][9u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][10u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][11u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][12u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][13u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][14u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][15u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][16u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][17u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][18u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][19u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][20u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][21u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][22u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][23u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[1u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[2u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[3u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[4u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[5u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[6u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[7u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[8u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[9u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[10u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[11u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[12u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[13u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[14u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[15u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[16u][7u]))) / 32u)));
+    v_z = 0u;
+    while (v_z < 256u) {
+      self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][(8u + (v_z & 15u))] = v_avg;
+      v_z += 1u;
+    }
+  } else if (a_mode == 1u) {
+    v_tm0 = ((uint32_t)(self->private_impl.f_yuv_cache[0u][7u]));
+    v_z = 0u;
+    while (v_z < 256u) {
+      v_tm1 = ((uint32_t)(self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][7u]));
+      v_tm2 = ((uint32_t)(self->private_impl.f_yuv_cache[0u][(8u + (v_z & 15u))]));
+      self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][(8u + (v_z & 15u))] = WUFFS_VP8__CLAMP[(((uint32_t)((v_tm1 + v_tm2) - v_tm0)) & 1023u)];
+      v_z += 1u;
+    }
+  } else if (a_mode == 2u) {
+    v_x = 0u;
+    while (v_x < 16u) {
+      v_val = self->private_impl.f_yuv_cache[0u][(8u + v_x)];
+      v_y = 0u;
+      while (v_y < 16u) {
+        self->private_impl.f_yuv_cache[(1u + v_y)][(8u + v_x)] = v_val;
+        v_y += 1u;
+      }
+      v_x += 1u;
+    }
+  } else if (a_mode == 3u) {
+    v_y = 0u;
+    while (v_y < 16u) {
+      v_val = self->private_impl.f_yuv_cache[(1u + v_y)][7u];
+      v_x = 0u;
+      while (v_x < 16u) {
+        self->private_impl.f_yuv_cache[(1u + v_y)][(8u + v_x)] = v_val;
+        v_x += 1u;
+      }
+      v_y += 1u;
+    }
+  } else if (a_mode <= 10u) {
+    v_avg = ((uint8_t)(((8u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[1u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[2u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[3u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[4u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[5u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[6u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[7u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[8u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[9u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[10u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[11u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[12u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[13u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[14u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[15u][7u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[16u][7u]))) / 16u)));
+    v_z = 0u;
+    while (v_z < 256u) {
+      self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][(8u + (v_z & 15u))] = v_avg;
+      v_z += 1u;
+    }
+  } else if (a_mode == 11u) {
+    v_avg = ((uint8_t)(((8u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][8u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][9u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][10u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][11u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][12u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][13u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][14u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][15u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][16u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][17u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][18u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][19u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][20u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][21u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][22u])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[0u][23u]))) / 16u)));
+    v_z = 0u;
+    while (v_z < 256u) {
+      self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][(8u + (v_z & 15u))] = v_avg;
+      v_z += 1u;
+    }
+  } else {
+    v_z = 0u;
+    while (v_z < 256u) {
+      self->private_impl.f_yuv_cache[(1u + (v_z >> 4u))][(8u + (v_z & 15u))] = 128u;
+      v_z += 1u;
+    }
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func vp8.decoder.predict_uv8
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__predict_uv8(
+    wuffs_vp8__decoder* self,
+    uint32_t a_b,
+    uint32_t a_mode) {
+  uint32_t v_cachey = 0;
+  uint32_t v_cachex = 0;
+  uint32_t v_x = 0;
+  uint32_t v_y = 0;
+  uint32_t v_z = 0;
+  uint8_t v_avg = 0;
+  uint8_t v_val = 0;
+  uint32_t v_tm0 = 0;
+  uint32_t v_tm1 = 0;
+  uint32_t v_tm2 = 0;
+
+  v_cachey = 18u;
+  v_cachex = ((a_b * 16u) + 8u);
+  if (a_mode == 0u) {
+    v_avg = ((uint8_t)(((8u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 4u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 5u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 6u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 7u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 4u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 5u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 6u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 7u)][(v_cachex - 1u)]))) / 16u)));
+    v_z = 0u;
+    while (v_z < 64u) {
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex + (v_z & 7u))] = v_avg;
+      v_z += 1u;
+    }
+  } else if (a_mode == 1u) {
+    v_tm0 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex - 1u)]));
+    v_z = 0u;
+    while (v_z < 64u) {
+      v_tm1 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex - 1u)]));
+      v_tm2 = ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + (v_z & 7u))]));
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex + (v_z & 7u))] = WUFFS_VP8__CLAMP[(((uint32_t)((v_tm1 + v_tm2) - v_tm0)) & 1023u)];
+      v_z += 1u;
+    }
+  } else if (a_mode == 2u) {
+    v_x = 0u;
+    while (v_x < 8u) {
+      v_val = self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + v_x)];
+      v_y = 0u;
+      while (v_y < 8u) {
+        self->private_impl.f_yuv_cache[(v_cachey + v_y)][(v_cachex + v_x)] = v_val;
+        v_y += 1u;
+      }
+      v_x += 1u;
+    }
+  } else if (a_mode == 3u) {
+    v_y = 0u;
+    while (v_y < 8u) {
+      v_val = self->private_impl.f_yuv_cache[(v_cachey + v_y)][(v_cachex - 1u)];
+      v_x = 0u;
+      while (v_x < 8u) {
+        self->private_impl.f_yuv_cache[(v_cachey + v_y)][(v_cachex + v_x)] = v_val;
+        v_x += 1u;
+      }
+      v_y += 1u;
+    }
+  } else if (a_mode <= 10u) {
+    v_avg = ((uint8_t)(((4u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[v_cachey][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 1u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 2u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 3u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 4u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 5u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 6u)][(v_cachex - 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey + 7u)][(v_cachex - 1u)]))) / 8u)));
+    v_z = 0u;
+    while (v_z < 64u) {
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex + (v_z & 7u))] = v_avg;
+      v_z += 1u;
+    }
+  } else if (a_mode == 11u) {
+    v_avg = ((uint8_t)(((4u +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][v_cachex])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 1u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 2u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 3u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 4u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 5u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 6u)])) +
+        ((uint32_t)(self->private_impl.f_yuv_cache[(v_cachey - 1u)][(v_cachex + 7u)]))) / 8u)));
+    v_z = 0u;
+    while (v_z < 64u) {
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex + (v_z & 7u))] = v_avg;
+      v_z += 1u;
+    }
+  } else {
+    v_z = 0u;
+    while (v_z < 64u) {
+      self->private_impl.f_yuv_cache[(v_cachey + (v_z >> 3u))][(v_cachex + (v_z & 7u))] = 128u;
+      v_z += 1u;
+    }
+  }
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func vp8.decoder.reconstruct
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__reconstruct(
+    wuffs_vp8__decoder* self,
+    wuffs_base__slice_u8 a_workbuf,
+    uint32_t a_mbx,
+    uint32_t a_mby,
+    uint32_t a_luma_mode,
+    uint32_t a_chroma_mode) {
+  uint32_t v_mode = 0;
+  uint32_t v_b = 0;
+
+  wuffs_vp8__decoder__prepare_yuv_cache(self, a_workbuf, a_mbx, a_mby);
+  if (a_luma_mode < 4u) {
+    v_mode = wuffs_vp8__decoder__substitute_dc_top_left(self, a_luma_mode, a_mbx, a_mby);
+    wuffs_vp8__decoder__predict_y16(self, v_mode);
+  } else {
+    v_b = 0u;
+    while (v_b < 16u) {
+      wuffs_vp8__decoder__predict_y4(self, v_b);
+      v_b += 1u;
+    }
+  }
+  v_mode = wuffs_vp8__decoder__substitute_dc_top_left(self, a_chroma_mode, a_mbx, a_mby);
+  wuffs_vp8__decoder__predict_uv8(self, 0u, v_mode);
+  wuffs_vp8__decoder__predict_uv8(self, 1u, v_mode);
+  return wuffs_base__make_empty_struct();
+}
+
+// -------- func vp8.decoder.substitute_dc_top_left
+
+WUFFS_BASE__GENERATED_C_CODE
+static uint32_t
+wuffs_vp8__decoder__substitute_dc_top_left(
+    const wuffs_vp8__decoder* self,
+    uint32_t a_mode,
+    uint32_t a_mbx,
+    uint32_t a_mby) {
+  if (a_mode == 0u) {
+    if (a_mby == 0u) {
+      if (a_mbx == 0u) {
+        return 11u;
+      } else {
+        return 12u;
+      }
+    } else if (a_mby == 0u) {
+      return 10u;
+    }
+  }
+  return a_mode;
+}
+
+// -------- func vp8.decoder.prepare_yuv_cache
+
+WUFFS_BASE__GENERATED_C_CODE
+static wuffs_base__empty_struct
+wuffs_vp8__decoder__prepare_yuv_cache(
+    wuffs_vp8__decoder* self,
+    wuffs_base__slice_u8 a_workbuf,
+    uint32_t a_mbx,
+    uint32_t a_mby) {
+  uint32_t v_i = 0;
+  uint32_t v_j = 0;
+  uint64_t v_offset = 0;
+  uint64_t v_o = 0;
+
+  if (a_mbx <= 0u) {
+    v_j = 0u;
+    while (v_j < 17u) {
+      self->private_impl.f_yuv_cache[v_j][7u] = 129u;
+      v_j += 1u;
+    }
+    while (v_j < 26u) {
+      self->private_impl.f_yuv_cache[v_j][7u] = 129u;
+      self->private_impl.f_yuv_cache[v_j][23u] = 129u;
+      v_j += 1u;
+    }
+  } else {
+    v_j = 0u;
+    while (v_j < 17u) {
+      self->private_impl.f_yuv_cache[v_j][7u] = self->private_impl.f_yuv_cache[v_j][23u];
+      v_j += 1u;
+    }
+    while (v_j < 26u) {
+      self->private_impl.f_yuv_cache[v_j][7u] = self->private_impl.f_yuv_cache[v_j][15u];
+      self->private_impl.f_yuv_cache[v_j][23u] = self->private_impl.f_yuv_cache[v_j][31u];
+      v_j += 1u;
+    }
+  }
+  if (a_mby <= 0u) {
+    v_i = 0u;
+    while (v_i < 32u) {
+      self->private_impl.f_yuv_cache[0u][v_i] = 127u;
+      v_i += 1u;
+    }
+    v_i = 0u;
+    while (v_i < 32u) {
+      self->private_impl.f_yuv_cache[17u][v_i] = 127u;
+      v_i += 1u;
+    }
+  } else {
+    v_offset = ((uint64_t)(((((a_mby - 1u) * self->private_impl.f_workbuf_yuv_y_stride) + a_mbx) * 16u)));
+    v_i = 0u;
+    while (v_i < 16u) {
+      v_o = (v_offset + ((uint64_t)(v_i)));
+      if (v_o < ((uint64_t)(a_workbuf.len))) {
+        self->private_impl.f_yuv_cache[0u][(8u + v_i)] = a_workbuf.ptr[v_o];
+      }
+      v_i += 1u;
+    }
+    if ((a_mbx + 1u) < self->private_impl.f_mbw) {
+      while (v_i < 20u) {
+        v_o = (v_offset + ((uint64_t)(v_i)));
+        if (v_o < ((uint64_t)(a_workbuf.len))) {
+          self->private_impl.f_yuv_cache[0u][(8u + v_i)] = a_workbuf.ptr[v_o];
+        }
+        v_i += 1u;
+      }
+    } else {
+      while (v_i < 20u) {
+        v_o = (v_offset + ((uint64_t)(15u)));
+        if (v_o < ((uint64_t)(a_workbuf.len))) {
+          self->private_impl.f_yuv_cache[0u][(8u + v_i)] = a_workbuf.ptr[v_o];
+        }
+        v_i += 1u;
+      }
+    }
+    v_offset = (self->private_impl.f_workbuf_yuv_y_end + ((uint64_t)(((((a_mby - 1u) * self->private_impl.f_workbuf_yuv_uv_stride) + a_mbx) * 8u))));
+    v_i = 0u;
+    while (v_i < 8u) {
+      v_o = (v_offset + ((uint64_t)(v_i)));
+      if (v_o < ((uint64_t)(a_workbuf.len))) {
+        self->private_impl.f_yuv_cache[17u][(8u + v_i)] = a_workbuf.ptr[v_o];
+      }
+      v_i += 1u;
+    }
+    v_offset = (self->private_impl.f_workbuf_yuv_u_end + ((uint64_t)(((((a_mby - 1u) * self->private_impl.f_workbuf_yuv_uv_stride) + a_mbx) * 8u))));
+    v_i = 0u;
+    while (v_i < 8u) {
+      v_o = (v_offset + ((uint64_t)(v_i)));
+      if (v_o < ((uint64_t)(a_workbuf.len))) {
+        self->private_impl.f_yuv_cache[17u][(24u + v_i)] = a_workbuf.ptr[v_o];
+      }
+      v_i += 1u;
+    }
+  }
+  v_j = 4u;
+  while (v_j < 16u) {
+    self->private_impl.f_yuv_cache[v_j][24u] = self->private_impl.f_yuv_cache[0u][24u];
+    self->private_impl.f_yuv_cache[v_j][25u] = self->private_impl.f_yuv_cache[0u][25u];
+    self->private_impl.f_yuv_cache[v_j][26u] = self->private_impl.f_yuv_cache[0u][26u];
+    self->private_impl.f_yuv_cache[v_j][27u] = self->private_impl.f_yuv_cache[0u][27u];
+    v_j += 4u;
+  }
+  return wuffs_base__make_empty_struct();
+}
+
 // -------- func vp8.decoder.get_quirk
 
 WUFFS_BASE__GENERATED_C_CODE
diff --git a/std/vp8/common_consts.wuffs b/std/vp8/common_consts.wuffs
index a849d60..a2e7861 100644
--- a/std/vp8/common_consts.wuffs
+++ b/std/vp8/common_consts.wuffs
@@ -111,6 +111,80 @@
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9,
 ]
 
+pri const CLAMP : roarray[1024] base.u8 = [
+        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+        0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+        0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+        0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
+        0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+        0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
+        0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
+
+        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+        0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+        0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+        0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+        0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+        0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+        0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+        0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
+
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+]
+
 // RFC 6386 Section 11.5. Subblock Mode Probability Table.
 //
 // Note that the specification (the RFC) differs from the implementation
diff --git a/std/vp8/decode_coefficients.wuffs b/std/vp8/decode_coefficients.wuffs
index fcb718d..42512e2 100644
--- a/std/vp8/decode_coefficients.wuffs
+++ b/std/vp8/decode_coefficients.wuffs
@@ -13,8 +13,7 @@
         mbx: base.u32[..= 0x3FF],
         mby: base.u32[..= 0x3FF],
         seg: base.u32[..= 3],
-        luma_mode: base.u32[..= 4],
-        chroma_mode: base.u32[..= 3]) {
+        luma_mode: base.u32[..= 4]) {
     var bc    : base.u32
     var by    : base.u32
     var bx    : base.u32
diff --git a/std/vp8/decode_macroblocks.wuffs b/std/vp8/decode_macroblocks.wuffs
index e5359ba..7fbb434 100644
--- a/std/vp8/decode_macroblocks.wuffs
+++ b/std/vp8/decode_macroblocks.wuffs
@@ -82,8 +82,12 @@
     } else {
         this.decode_coefficients!(
                 workbuf: args.workbuf, mbx: args.mbx, mby: args.mby,
-                seg: seg, luma_mode: luma_mode, chroma_mode: chroma_mode)
+                seg: seg, luma_mode: luma_mode)
     }
+
+    this.reconstruct!(
+            workbuf: args.workbuf, mbx: args.mbx, mby: args.mby,
+            luma_mode: luma_mode, chroma_mode: chroma_mode)
 }
 
 // RFC 6386 Section 11.2. Luma Modes.
diff --git a/std/vp8/decode_predict_default.wuffs b/std/vp8/decode_predict_default.wuffs
new file mode 100644
index 0000000..cacf5ca
--- /dev/null
+++ b/std/vp8/decode_predict_default.wuffs
@@ -0,0 +1,675 @@
+// Copyright 2026 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+// --------
+
+// Predicts a 4×4 luma block, the Xs below, based on samples top and left.
+//
+//  a b c d e f g h i
+//  p X X X X
+//  q X X X X
+//  r X X X X
+//  s X X X X
+pri func decoder.predict_y4!(b: base.u32[..= 15]) {
+    var cachey : base.u32[..= 13]
+    var cachex : base.u32[..= 20]
+    var mode   : base.u32[..= 9]
+    var z      : base.u32
+
+    var avg : base.u8
+
+    var tm0 : base.u32
+    var tm1 : base.u32
+    var tm2 : base.u32
+
+    var a : base.u32
+    var b : base.u32
+    var c : base.u32
+    var d : base.u32
+    var e : base.u32
+    var f : base.u32
+    var g : base.u32
+    var h : base.u32
+    var i : base.u32
+    var p : base.u32
+    var q : base.u32
+    var r : base.u32
+    var s : base.u32
+
+    var ab : base.u8
+    var bc : base.u8
+    var cd : base.u8
+    var de : base.u8
+    var ef : base.u8
+    var pa : base.u8
+    var qp : base.u8
+    var rq : base.u8
+    var sr : base.u8
+
+    var abc : base.u8
+    var bcd : base.u8
+    var cde : base.u8
+    var def : base.u8
+    var efg : base.u8
+    var fgh : base.u8
+    var ghi : base.u8
+    var hii : base.u8
+    var pab : base.u8
+    var qpa : base.u8
+    var rqp : base.u8
+    var srq : base.u8
+    var ssr : base.u8
+    var sss : base.u8
+
+    cachey = ((args.b & 0xC) * 1) + 1
+    cachex = ((args.b & 0x3) * 4) + 8
+    mode = this.mb_subblock_modes[args.b] as base.u32
+
+    if mode == 0 {  // DC.
+        avg = ((4 +
+                (this.yuv_cache[cachey - 1][cachex + 0] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 1] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 2] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 3] as base.u32) +
+                (this.yuv_cache[cachey + 0][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 1][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 2][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 3][cachex - 1] as base.u32)) / 8) as base.u8
+
+        z = 0
+        while z < 16 {
+            this.yuv_cache[cachey + (z >> 2)][cachex + (z & 3)] = avg
+            z += 1
+        }
+
+    } else if mode == 1 {  // TM.
+        tm0 = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        z = 0
+        while z < 16,
+                inv cachey >= 1,
+                inv cachex >= 8,
+        {
+            tm1 = this.yuv_cache[cachey + (z >> 2)][cachex - 1] as base.u32
+            tm2 = this.yuv_cache[cachey - 1][cachex + (z & 3)] as base.u32
+            this.yuv_cache[cachey + (z >> 2)][cachex + (z & 3)] =
+                    CLAMP[((tm1 + tm2) ~mod- tm0) & 1023]
+            z += 1
+        }
+
+    } else if mode == 2 {  // VE.
+        a = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+        e = this.yuv_cache[cachey - 1][cachex + 3] as base.u32
+        f = this.yuv_cache[cachey - 1][cachex + 4] as base.u32
+
+        def = (((d + (2 * e) + f + 2) / 4) & 0xFF) as base.u8
+        cde = (((c + (2 * d) + e + 2) / 4) & 0xFF) as base.u8
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+        abc = (((a + (2 * b) + c + 2) / 4) & 0xFF) as base.u8
+
+        z = 0
+        while z < 4 {
+            this.yuv_cache[cachey + z][cachex + 0] = abc
+            this.yuv_cache[cachey + z][cachex + 1] = bcd
+            this.yuv_cache[cachey + z][cachex + 2] = cde
+            this.yuv_cache[cachey + z][cachex + 3] = def
+            z += 1
+        }
+
+    } else if mode == 3 {  // HE.
+        s = this.yuv_cache[cachey + 3][cachex - 1] as base.u32
+        r = this.yuv_cache[cachey + 2][cachex - 1] as base.u32
+        q = this.yuv_cache[cachey + 1][cachex - 1] as base.u32
+        p = this.yuv_cache[cachey + 0][cachex - 1] as base.u32
+        a = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+
+        qpa = (((q + (2 * p) + a + 2) / 4) & 0xFF) as base.u8
+        rqp = (((r + (2 * q) + p + 2) / 4) & 0xFF) as base.u8
+        srq = (((s + (2 * r) + q + 2) / 4) & 0xFF) as base.u8
+        ssr = (((s + (2 * s) + r + 2) / 4) & 0xFF) as base.u8
+
+        z = 0
+        while z < 4 {
+            this.yuv_cache[cachey + 0][cachex + z] = qpa
+            this.yuv_cache[cachey + 1][cachex + z] = rqp
+            this.yuv_cache[cachey + 2][cachex + z] = srq
+            this.yuv_cache[cachey + 3][cachex + z] = ssr
+            z += 1
+        }
+
+    } else if mode == 4 {  // RD.
+        s = this.yuv_cache[cachey + 3][cachex - 1] as base.u32
+        r = this.yuv_cache[cachey + 2][cachex - 1] as base.u32
+        q = this.yuv_cache[cachey + 1][cachex - 1] as base.u32
+        p = this.yuv_cache[cachey + 0][cachex - 1] as base.u32
+        a = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+        e = this.yuv_cache[cachey - 1][cachex + 3] as base.u32
+
+        cde = (((c + (2 * d) + e + 2) / 4) & 0xFF) as base.u8
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+        abc = (((a + (2 * b) + c + 2) / 4) & 0xFF) as base.u8
+        pab = (((p + (2 * a) + b + 2) / 4) & 0xFF) as base.u8
+        qpa = (((q + (2 * p) + a + 2) / 4) & 0xFF) as base.u8
+        rqp = (((r + (2 * q) + p + 2) / 4) & 0xFF) as base.u8
+        srq = (((s + (2 * r) + q + 2) / 4) & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = pab
+        this.yuv_cache[cachey + 0][cachex + 1] = abc
+        this.yuv_cache[cachey + 0][cachex + 2] = bcd
+        this.yuv_cache[cachey + 0][cachex + 3] = cde
+
+        this.yuv_cache[cachey + 1][cachex + 0] = qpa
+        this.yuv_cache[cachey + 1][cachex + 1] = pab
+        this.yuv_cache[cachey + 1][cachex + 2] = abc
+        this.yuv_cache[cachey + 1][cachex + 3] = bcd
+
+        this.yuv_cache[cachey + 2][cachex + 0] = rqp
+        this.yuv_cache[cachey + 2][cachex + 1] = qpa
+        this.yuv_cache[cachey + 2][cachex + 2] = pab
+        this.yuv_cache[cachey + 2][cachex + 3] = abc
+
+        this.yuv_cache[cachey + 3][cachex + 0] = srq
+        this.yuv_cache[cachey + 3][cachex + 1] = rqp
+        this.yuv_cache[cachey + 3][cachex + 2] = qpa
+        this.yuv_cache[cachey + 3][cachex + 3] = pab
+
+    } else if mode == 5 {  // VR.
+        r = this.yuv_cache[cachey + 2][cachex - 1] as base.u32
+        q = this.yuv_cache[cachey + 1][cachex - 1] as base.u32
+        p = this.yuv_cache[cachey + 0][cachex - 1] as base.u32
+        a = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+        e = this.yuv_cache[cachey - 1][cachex + 3] as base.u32
+
+        ab = (((a + b + 1) / 2) & 0xFF) as base.u8
+        bc = (((b + c + 1) / 2) & 0xFF) as base.u8
+        cd = (((c + d + 1) / 2) & 0xFF) as base.u8
+        de = (((d + e + 1) / 2) & 0xFF) as base.u8
+
+        cde = (((c + (2 * d) + e + 2) / 4) & 0xFF) as base.u8
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+        abc = (((a + (2 * b) + c + 2) / 4) & 0xFF) as base.u8
+        pab = (((p + (2 * a) + b + 2) / 4) & 0xFF) as base.u8
+        qpa = (((q + (2 * p) + a + 2) / 4) & 0xFF) as base.u8
+        rqp = (((r + (2 * q) + p + 2) / 4) & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = ab
+        this.yuv_cache[cachey + 0][cachex + 1] = bc
+        this.yuv_cache[cachey + 0][cachex + 2] = cd
+        this.yuv_cache[cachey + 0][cachex + 3] = de
+
+        this.yuv_cache[cachey + 1][cachex + 0] = pab
+        this.yuv_cache[cachey + 1][cachex + 1] = abc
+        this.yuv_cache[cachey + 1][cachex + 2] = bcd
+        this.yuv_cache[cachey + 1][cachex + 3] = cde
+
+        this.yuv_cache[cachey + 2][cachex + 0] = qpa
+        this.yuv_cache[cachey + 2][cachex + 1] = ab
+        this.yuv_cache[cachey + 2][cachex + 2] = bc
+        this.yuv_cache[cachey + 2][cachex + 3] = cd
+
+        this.yuv_cache[cachey + 3][cachex + 0] = rqp
+        this.yuv_cache[cachey + 3][cachex + 1] = pab
+        this.yuv_cache[cachey + 3][cachex + 2] = abc
+        this.yuv_cache[cachey + 3][cachex + 3] = bcd
+
+    } else if mode == 6 {  // LD.
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+        e = this.yuv_cache[cachey - 1][cachex + 3] as base.u32
+        f = this.yuv_cache[cachey - 1][cachex + 4] as base.u32
+        g = this.yuv_cache[cachey - 1][cachex + 5] as base.u32
+        h = this.yuv_cache[cachey - 1][cachex + 6] as base.u32
+        i = this.yuv_cache[cachey - 1][cachex + 7] as base.u32
+
+        hii = (((h + (2 * i) + i + 2) / 4) & 0xFF) as base.u8
+        ghi = (((g + (2 * h) + i + 2) / 4) & 0xFF) as base.u8
+        fgh = (((f + (2 * g) + h + 2) / 4) & 0xFF) as base.u8
+        efg = (((e + (2 * f) + g + 2) / 4) & 0xFF) as base.u8
+        def = (((d + (2 * e) + f + 2) / 4) & 0xFF) as base.u8
+        cde = (((c + (2 * d) + e + 2) / 4) & 0xFF) as base.u8
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = bcd
+        this.yuv_cache[cachey + 0][cachex + 1] = cde
+        this.yuv_cache[cachey + 0][cachex + 2] = def
+        this.yuv_cache[cachey + 0][cachex + 3] = efg
+
+        this.yuv_cache[cachey + 1][cachex + 0] = cde
+        this.yuv_cache[cachey + 1][cachex + 1] = def
+        this.yuv_cache[cachey + 1][cachex + 2] = efg
+        this.yuv_cache[cachey + 1][cachex + 3] = fgh
+
+        this.yuv_cache[cachey + 2][cachex + 0] = def
+        this.yuv_cache[cachey + 2][cachex + 1] = efg
+        this.yuv_cache[cachey + 2][cachex + 2] = fgh
+        this.yuv_cache[cachey + 2][cachex + 3] = ghi
+
+        this.yuv_cache[cachey + 3][cachex + 0] = efg
+        this.yuv_cache[cachey + 3][cachex + 1] = fgh
+        this.yuv_cache[cachey + 3][cachex + 2] = ghi
+        this.yuv_cache[cachey + 3][cachex + 3] = hii
+
+    } else if mode == 7 {  // VL.
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+        e = this.yuv_cache[cachey - 1][cachex + 3] as base.u32
+        f = this.yuv_cache[cachey - 1][cachex + 4] as base.u32
+        g = this.yuv_cache[cachey - 1][cachex + 5] as base.u32
+        h = this.yuv_cache[cachey - 1][cachex + 6] as base.u32
+        i = this.yuv_cache[cachey - 1][cachex + 7] as base.u32
+
+        ef = (((e + f + 1) / 2) & 0xFF) as base.u8
+        de = (((d + e + 1) / 2) & 0xFF) as base.u8
+        cd = (((c + d + 1) / 2) & 0xFF) as base.u8
+        bc = (((b + c + 1) / 2) & 0xFF) as base.u8
+
+        ghi = (((g + (2 * h) + i + 2) / 4) & 0xFF) as base.u8
+        fgh = (((f + (2 * g) + h + 2) / 4) & 0xFF) as base.u8
+        efg = (((e + (2 * f) + g + 2) / 4) & 0xFF) as base.u8
+        def = (((d + (2 * e) + f + 2) / 4) & 0xFF) as base.u8
+        cde = (((c + (2 * d) + e + 2) / 4) & 0xFF) as base.u8
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = bc
+        this.yuv_cache[cachey + 0][cachex + 1] = cd
+        this.yuv_cache[cachey + 0][cachex + 2] = de
+        this.yuv_cache[cachey + 0][cachex + 3] = ef
+
+        this.yuv_cache[cachey + 1][cachex + 0] = bcd
+        this.yuv_cache[cachey + 1][cachex + 1] = cde
+        this.yuv_cache[cachey + 1][cachex + 2] = def
+        this.yuv_cache[cachey + 1][cachex + 3] = efg
+
+        this.yuv_cache[cachey + 2][cachex + 0] = cd
+        this.yuv_cache[cachey + 2][cachex + 1] = de
+        this.yuv_cache[cachey + 2][cachex + 2] = ef
+        this.yuv_cache[cachey + 2][cachex + 3] = fgh
+
+        this.yuv_cache[cachey + 3][cachex + 0] = cde
+        this.yuv_cache[cachey + 3][cachex + 1] = def
+        this.yuv_cache[cachey + 3][cachex + 2] = efg
+        this.yuv_cache[cachey + 3][cachex + 3] = ghi
+
+    } else if mode == 8 {  // HD.
+        s = this.yuv_cache[cachey + 3][cachex - 1] as base.u32
+        r = this.yuv_cache[cachey + 2][cachex - 1] as base.u32
+        q = this.yuv_cache[cachey + 1][cachex - 1] as base.u32
+        p = this.yuv_cache[cachey + 0][cachex - 1] as base.u32
+        a = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        b = this.yuv_cache[cachey - 1][cachex + 0] as base.u32
+        c = this.yuv_cache[cachey - 1][cachex + 1] as base.u32
+        d = this.yuv_cache[cachey - 1][cachex + 2] as base.u32
+
+        sr = (((s + r + 1) / 2) & 0xFF) as base.u8
+        rq = (((r + q + 1) / 2) & 0xFF) as base.u8
+        qp = (((q + p + 1) / 2) & 0xFF) as base.u8
+        pa = (((p + a + 1) / 2) & 0xFF) as base.u8
+
+        bcd = (((b + (2 * c) + d + 2) / 4) & 0xFF) as base.u8
+        abc = (((a + (2 * b) + c + 2) / 4) & 0xFF) as base.u8
+        pab = (((p + (2 * a) + b + 2) / 4) & 0xFF) as base.u8
+        qpa = (((q + (2 * p) + a + 2) / 4) & 0xFF) as base.u8
+        rqp = (((r + (2 * q) + p + 2) / 4) & 0xFF) as base.u8
+        srq = (((s + (2 * r) + q + 2) / 4) & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = pa
+        this.yuv_cache[cachey + 0][cachex + 1] = pab
+        this.yuv_cache[cachey + 0][cachex + 2] = abc
+        this.yuv_cache[cachey + 0][cachex + 3] = bcd
+
+        this.yuv_cache[cachey + 1][cachex + 0] = qp
+        this.yuv_cache[cachey + 1][cachex + 1] = qpa
+        this.yuv_cache[cachey + 1][cachex + 2] = pa
+        this.yuv_cache[cachey + 1][cachex + 3] = pab
+
+        this.yuv_cache[cachey + 2][cachex + 0] = rq
+        this.yuv_cache[cachey + 2][cachex + 1] = rqp
+        this.yuv_cache[cachey + 2][cachex + 2] = qp
+        this.yuv_cache[cachey + 2][cachex + 3] = qpa
+
+        this.yuv_cache[cachey + 3][cachex + 0] = sr
+        this.yuv_cache[cachey + 3][cachex + 1] = srq
+        this.yuv_cache[cachey + 3][cachex + 2] = rq
+        this.yuv_cache[cachey + 3][cachex + 3] = rqp
+
+    } else {  // HU.
+        s = this.yuv_cache[cachey + 3][cachex - 1] as base.u32
+        r = this.yuv_cache[cachey + 2][cachex - 1] as base.u32
+        q = this.yuv_cache[cachey + 1][cachex - 1] as base.u32
+        p = this.yuv_cache[cachey + 0][cachex - 1] as base.u32
+
+        sr = (((s + r + 1) / 2) & 0xFF) as base.u8
+        rq = (((r + q + 1) / 2) & 0xFF) as base.u8
+        qp = (((q + p + 1) / 2) & 0xFF) as base.u8
+
+        rqp = (((r + (2 * q) + p + 2) / 4) & 0xFF) as base.u8
+        srq = (((s + (2 * r) + q + 2) / 4) & 0xFF) as base.u8
+        ssr = (((s + (2 * s) + r + 2) / 4) & 0xFF) as base.u8
+        sss = (s & 0xFF) as base.u8
+
+        this.yuv_cache[cachey + 0][cachex + 0] = qp
+        this.yuv_cache[cachey + 0][cachex + 1] = rqp
+        this.yuv_cache[cachey + 0][cachex + 2] = rq
+        this.yuv_cache[cachey + 0][cachex + 3] = srq
+
+        this.yuv_cache[cachey + 1][cachex + 0] = rq
+        this.yuv_cache[cachey + 1][cachex + 1] = srq
+        this.yuv_cache[cachey + 1][cachex + 2] = sr
+        this.yuv_cache[cachey + 1][cachex + 3] = ssr
+
+        this.yuv_cache[cachey + 2][cachex + 0] = sr
+        this.yuv_cache[cachey + 2][cachex + 1] = ssr
+        this.yuv_cache[cachey + 2][cachex + 2] = sss
+        this.yuv_cache[cachey + 2][cachex + 3] = sss
+
+        this.yuv_cache[cachey + 3][cachex + 0] = sss
+        this.yuv_cache[cachey + 3][cachex + 1] = sss
+        this.yuv_cache[cachey + 3][cachex + 2] = sss
+        this.yuv_cache[cachey + 3][cachex + 3] = sss
+    }
+}
+
+pri func decoder.predict_y16!(mode: base.u32[..= 12]) {
+    var x : base.u32
+    var y : base.u32
+    var z : base.u32
+
+    var avg : base.u8
+    var val : base.u8
+
+    var tm0 : base.u32
+    var tm1 : base.u32
+    var tm2 : base.u32
+
+    if args.mode == 0 {  // DC.
+        avg = ((16 +
+                (this.yuv_cache[0x00][0x08] as base.u32) +
+                (this.yuv_cache[0x00][0x09] as base.u32) +
+                (this.yuv_cache[0x00][0x0A] as base.u32) +
+                (this.yuv_cache[0x00][0x0B] as base.u32) +
+                (this.yuv_cache[0x00][0x0C] as base.u32) +
+                (this.yuv_cache[0x00][0x0D] as base.u32) +
+                (this.yuv_cache[0x00][0x0E] as base.u32) +
+                (this.yuv_cache[0x00][0x0F] as base.u32) +
+                (this.yuv_cache[0x00][0x10] as base.u32) +
+                (this.yuv_cache[0x00][0x11] as base.u32) +
+                (this.yuv_cache[0x00][0x12] as base.u32) +
+                (this.yuv_cache[0x00][0x13] as base.u32) +
+                (this.yuv_cache[0x00][0x14] as base.u32) +
+                (this.yuv_cache[0x00][0x15] as base.u32) +
+                (this.yuv_cache[0x00][0x16] as base.u32) +
+                (this.yuv_cache[0x00][0x17] as base.u32) +
+                (this.yuv_cache[0x01][0x07] as base.u32) +
+                (this.yuv_cache[0x02][0x07] as base.u32) +
+                (this.yuv_cache[0x03][0x07] as base.u32) +
+                (this.yuv_cache[0x04][0x07] as base.u32) +
+                (this.yuv_cache[0x05][0x07] as base.u32) +
+                (this.yuv_cache[0x06][0x07] as base.u32) +
+                (this.yuv_cache[0x07][0x07] as base.u32) +
+                (this.yuv_cache[0x08][0x07] as base.u32) +
+                (this.yuv_cache[0x09][0x07] as base.u32) +
+                (this.yuv_cache[0x0A][0x07] as base.u32) +
+                (this.yuv_cache[0x0B][0x07] as base.u32) +
+                (this.yuv_cache[0x0C][0x07] as base.u32) +
+                (this.yuv_cache[0x0D][0x07] as base.u32) +
+                (this.yuv_cache[0x0E][0x07] as base.u32) +
+                (this.yuv_cache[0x0F][0x07] as base.u32) +
+                (this.yuv_cache[0x10][0x07] as base.u32)) / 32) as base.u8
+
+        z = 0
+        while z < 256 {
+            this.yuv_cache[0x01 + (z >> 4)][0x08 + (z & 15)] = avg
+            z += 1
+        }
+
+    } else if args.mode == 1 {  // TM.
+        tm0 = this.yuv_cache[0x00][0x07] as base.u32
+        z = 0
+        while z < 256 {
+            tm1 = this.yuv_cache[0x01 + (z >> 4)][0x07] as base.u32
+            tm2 = this.yuv_cache[0x00][0x08 + (z & 15)] as base.u32
+            this.yuv_cache[0x01 + (z >> 4)][0x08 + (z & 15)] =
+                    CLAMP[((tm1 + tm2) ~mod- tm0) & 1023]
+            z += 1
+        }
+
+    } else if args.mode == 2 {  // VE.
+        x = 0
+        while x < 16 {
+            val = this.yuv_cache[0x00][0x08 + x]
+            y = 0
+            while y < 16,
+                    inv x < 16,
+            {
+                this.yuv_cache[0x01 + y][0x08 + x] = val
+                y += 1
+            }
+            x += 1
+        }
+
+    } else if args.mode == 3 {  // HE.
+        y = 0
+        while y < 16 {
+            val = this.yuv_cache[0x01 + y][0x07]
+            x = 0
+            while x < 16,
+                    inv y < 16,
+            {
+                this.yuv_cache[0x01 + y][0x08 + x] = val
+                x += 1
+            }
+            y += 1
+        }
+
+    } else if args.mode <= 10 {  // DCTop.
+        avg = ((8 +
+                (this.yuv_cache[0x01][0x07] as base.u32) +
+                (this.yuv_cache[0x02][0x07] as base.u32) +
+                (this.yuv_cache[0x03][0x07] as base.u32) +
+                (this.yuv_cache[0x04][0x07] as base.u32) +
+                (this.yuv_cache[0x05][0x07] as base.u32) +
+                (this.yuv_cache[0x06][0x07] as base.u32) +
+                (this.yuv_cache[0x07][0x07] as base.u32) +
+                (this.yuv_cache[0x08][0x07] as base.u32) +
+                (this.yuv_cache[0x09][0x07] as base.u32) +
+                (this.yuv_cache[0x0A][0x07] as base.u32) +
+                (this.yuv_cache[0x0B][0x07] as base.u32) +
+                (this.yuv_cache[0x0C][0x07] as base.u32) +
+                (this.yuv_cache[0x0D][0x07] as base.u32) +
+                (this.yuv_cache[0x0E][0x07] as base.u32) +
+                (this.yuv_cache[0x0F][0x07] as base.u32) +
+                (this.yuv_cache[0x10][0x07] as base.u32)) / 16) as base.u8
+
+        z = 0
+        while z < 256 {
+            this.yuv_cache[0x01 + (z >> 4)][0x08 + (z & 15)] = avg
+            z += 1
+        }
+
+    } else if args.mode == 11 {  // DCLeft.
+        avg = ((8 +
+                (this.yuv_cache[0x00][0x08] as base.u32) +
+                (this.yuv_cache[0x00][0x09] as base.u32) +
+                (this.yuv_cache[0x00][0x0A] as base.u32) +
+                (this.yuv_cache[0x00][0x0B] as base.u32) +
+                (this.yuv_cache[0x00][0x0C] as base.u32) +
+                (this.yuv_cache[0x00][0x0D] as base.u32) +
+                (this.yuv_cache[0x00][0x0E] as base.u32) +
+                (this.yuv_cache[0x00][0x0F] as base.u32) +
+                (this.yuv_cache[0x00][0x10] as base.u32) +
+                (this.yuv_cache[0x00][0x11] as base.u32) +
+                (this.yuv_cache[0x00][0x12] as base.u32) +
+                (this.yuv_cache[0x00][0x13] as base.u32) +
+                (this.yuv_cache[0x00][0x14] as base.u32) +
+                (this.yuv_cache[0x00][0x15] as base.u32) +
+                (this.yuv_cache[0x00][0x16] as base.u32) +
+                (this.yuv_cache[0x00][0x17] as base.u32)) / 16) as base.u8
+
+        z = 0
+        while z < 256 {
+            this.yuv_cache[0x01 + (z >> 4)][0x08 + (z & 15)] = avg
+            z += 1
+        }
+
+    } else {  // DCTopLeft.
+        z = 0
+        while z < 256 {
+            this.yuv_cache[0x01 + (z >> 4)][0x08 + (z & 15)] = 0x80
+            z += 1
+        }
+    }
+}
+
+pri func decoder.predict_uv8!(b: base.u32[..= 1], mode: base.u32[..= 12]) {
+    var cachey : base.u32[..= 18]
+    var cachex : base.u32[..= 24]
+    var x      : base.u32
+    var y      : base.u32
+    var z      : base.u32
+
+    var avg : base.u8
+    var val : base.u8
+
+    var tm0 : base.u32
+    var tm1 : base.u32
+    var tm2 : base.u32
+
+    cachey = 0x12
+    cachex = (args.b * 16) + 8
+
+    if args.mode == 0 {  // DC.
+        avg = ((8 +
+                (this.yuv_cache[cachey - 1][cachex + 0] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 1] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 2] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 3] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 4] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 5] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 6] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 7] as base.u32) +
+                (this.yuv_cache[cachey + 0][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 1][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 2][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 3][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 4][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 5][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 6][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 7][cachex - 1] as base.u32)) / 16) as base.u8
+
+        z = 0
+        while z < 64 {
+            this.yuv_cache[cachey + (z >> 3)][cachex + (z & 7)] = avg
+            z += 1
+        }
+
+    } else if args.mode == 1 {  // TM.
+        tm0 = this.yuv_cache[cachey - 1][cachex - 1] as base.u32
+        z = 0
+        while z < 64,
+                inv cachey == 0x12,
+                inv cachex >= 8,
+        {
+            tm1 = this.yuv_cache[cachey + (z >> 3)][cachex - 1] as base.u32
+            tm2 = this.yuv_cache[cachey - 1][cachex + (z & 7)] as base.u32
+            this.yuv_cache[cachey + (z >> 3)][cachex + (z & 7)] =
+                    CLAMP[((tm1 + tm2) ~mod- tm0) & 1023]
+            z += 1
+        }
+
+    } else if args.mode == 2 {  // VE.
+        x = 0
+        while x < 8,
+                inv cachey == 0x12,
+                inv cachex >= 8,
+        {
+            val = this.yuv_cache[cachey - 1][cachex + x]
+            y = 0
+            while y < 8,
+                    inv cachey == 0x12,
+                    inv cachex >= 8,
+                    inv x < 8,
+            {
+                this.yuv_cache[cachey + y][cachex + x] = val
+                y += 1
+            }
+            x += 1
+        }
+
+    } else if args.mode == 3 {  // HE.
+        y = 0
+        while y < 8,
+                inv cachey == 0x12,
+                inv cachex >= 8,
+        {
+            val = this.yuv_cache[cachey + y][cachex - 1]
+            x = 0
+            while x < 8,
+                    inv cachey == 0x12,
+                    inv cachex >= 8,
+                    inv y < 8,
+            {
+                this.yuv_cache[cachey + y][cachex + x] = val
+                x += 1
+            }
+            y += 1
+        }
+
+    } else if args.mode <= 10 {  // DCTop.
+        avg = ((4 +
+                (this.yuv_cache[cachey + 0][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 1][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 2][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 3][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 4][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 5][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 6][cachex - 1] as base.u32) +
+                (this.yuv_cache[cachey + 7][cachex - 1] as base.u32)) / 8) as base.u8
+
+        z = 0
+        while z < 64 {
+            this.yuv_cache[cachey + (z >> 3)][cachex + (z & 7)] = avg
+            z += 1
+        }
+
+    } else if args.mode == 11 {  // DCLeft.
+        avg = ((4 +
+                (this.yuv_cache[cachey - 1][cachex + 0] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 1] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 2] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 3] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 4] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 5] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 6] as base.u32) +
+                (this.yuv_cache[cachey - 1][cachex + 7] as base.u32)) / 8) as base.u8
+
+        z = 0
+        while z < 64 {
+            this.yuv_cache[cachey + (z >> 3)][cachex + (z & 7)] = avg
+            z += 1
+        }
+
+    } else {  // DCTopLeft.
+        z = 0
+        while z < 64 {
+            this.yuv_cache[cachey + (z >> 3)][cachex + (z & 7)] = 0x80
+            z += 1
+        }
+    }
+}
diff --git a/std/vp8/decode_reconstruct.wuffs b/std/vp8/decode_reconstruct.wuffs
new file mode 100644
index 0000000..fbaa8a9
--- /dev/null
+++ b/std/vp8/decode_reconstruct.wuffs
@@ -0,0 +1,176 @@
+// Copyright 2026 The Wuffs Authors.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+pri func decoder.reconstruct!(
+        workbuf: slice base.u8,
+        mbx: base.u32[..= 0x3FF],
+        mby: base.u32[..= 0x3FF],
+        luma_mode: base.u32[..= 4],
+        chroma_mode: base.u32[..= 3]) {
+    var mode : base.u32[..= 12]
+    var b    : base.u32
+
+    this.prepare_yuv_cache!(workbuf: args.workbuf, mbx: args.mbx, mby: args.mby)
+
+    if args.luma_mode < 4 {
+        mode = this.substitute_dc_top_left(mode: args.luma_mode, mbx: args.mbx, mby: args.mby)
+        this.predict_y16!(mode: mode)
+
+    } else {
+        b = 0
+        while b < 16 {
+            this.predict_y4!(b: b)
+            b += 1
+        }
+    }
+
+    mode = this.substitute_dc_top_left(mode: args.chroma_mode, mbx: args.mbx, mby: args.mby)
+
+    this.predict_uv8!(b: 0, mode: mode)
+
+    this.predict_uv8!(b: 1, mode: mode)
+}
+
+pri func decoder.substitute_dc_top_left(
+        mode: base.u32[..= 3],
+        mbx: base.u32[..= 0x3FF],
+        mby: base.u32[..= 0x3FF]) base.u32[..= 12] {
+    if args.mode == 0 {  // DC.
+        if args.mby == 0 {
+            if args.mbx == 0 {
+                return 11  // DCLeft.
+            } else {
+                return 12  // DCTopLeft.
+            }
+        } else if args.mby == 0 {
+            return 10  // DCTop.
+        }
+    }
+    return args.mode
+}
+
+pri func decoder.prepare_yuv_cache!(
+        workbuf: roslice base.u8,
+        mbx: base.u32[..= 0x3FF],
+        mby: base.u32[..= 0x3FF]) {
+    var i      : base.u32
+    var j      : base.u32
+    var offset : base.u64[..= 0x17FE_1FF8]
+    var o      : base.u64
+
+    if args.mbx <= 0 {
+        j = 0x00
+        while j < 0x11 {
+            this.yuv_cache[j][0x07] = 0x81
+            j += 1
+        }
+        while j < 0x1A {
+            this.yuv_cache[j][0x07] = 0x81
+            this.yuv_cache[j][0x17] = 0x81
+            j += 1
+        }
+
+    } else {
+        j = 0x00
+        while j < 0x11 {
+            this.yuv_cache[j][0x07] = this.yuv_cache[j][0x17]
+            j += 1
+        }
+        while j < 0x1A {
+            this.yuv_cache[j][0x07] = this.yuv_cache[j][0x0F]
+            this.yuv_cache[j][0x17] = this.yuv_cache[j][0x1F]
+            j += 1
+        }
+    }
+
+    if args.mby <= 0 {
+        i = 0x00
+        while i < 0x20 {
+            this.yuv_cache[0x00][i] = 0x7F
+            i += 1
+        }
+        i = 0x00
+        while i < 0x20 {
+            this.yuv_cache[0x11][i] = 0x7F
+            i += 1
+        }
+
+    } else {
+        offset = 0 +
+                (((((args.mby - 1) * this.workbuf_yuv_y_stride) + args.mbx) * 16) as base.u64)
+        i = 0x00
+        while i < 0x10,
+                inv args.mby > 0,
+        {
+            o = offset + (i as base.u64)
+            if o < args.workbuf.length() {
+                this.yuv_cache[0x00][0x08 + i] = args.workbuf[o]
+            }
+            i += 1
+        }
+
+        if (args.mbx + 1) < this.mbw {
+            while i < 0x14,
+                    inv args.mby > 0,
+            {
+                o = offset + (i as base.u64)
+                if o < args.workbuf.length() {
+                    this.yuv_cache[0x00][0x08 + i] = args.workbuf[o]
+                }
+                i += 1
+            }
+        } else {
+            while i < 0x14,
+                    inv args.mby > 0,
+            {
+                o = offset + (0x0F as base.u64)
+                if o < args.workbuf.length() {
+                    this.yuv_cache[0x00][0x08 + i] = args.workbuf[o]
+                }
+                i += 1
+            }
+        }
+
+        offset = this.workbuf_yuv_y_end +
+                (((((args.mby - 1) * this.workbuf_yuv_uv_stride) + args.mbx) * 8) as base.u64)
+        i = 0x00
+        while i < 0x08,
+                inv args.mby > 0,
+        {
+            o = offset + (i as base.u64)
+            if o < args.workbuf.length() {
+                this.yuv_cache[0x11][0x08 + i] = args.workbuf[o]
+            }
+            i += 1
+        }
+
+        offset = this.workbuf_yuv_u_end +
+                (((((args.mby - 1) * this.workbuf_yuv_uv_stride) + args.mbx) * 8) as base.u64)
+        i = 0x00
+        while i < 0x08,
+                inv args.mby > 0,
+        {
+            o = offset + (i as base.u64)
+            if o < args.workbuf.length() {
+                this.yuv_cache[0x11][0x18 + i] = args.workbuf[o]
+            }
+            i += 1
+        }
+    }
+
+    j = 0x04
+    while j < 0x10 {
+        this.yuv_cache[j][0x18] = this.yuv_cache[0][0x18]
+        this.yuv_cache[j][0x19] = this.yuv_cache[0][0x19]
+        this.yuv_cache[j][0x1A] = this.yuv_cache[0][0x1A]
+        this.yuv_cache[j][0x1B] = this.yuv_cache[0][0x1B]
+        j += 4
+    }
+}
diff --git a/std/vp8/decode_vp8.wuffs b/std/vp8/decode_vp8.wuffs
index 67a247e..a374bb3 100644
--- a/std/vp8/decode_vp8.wuffs
+++ b/std/vp8/decode_vp8.wuffs
@@ -100,6 +100,8 @@
 
         mb_subblock_modes : array[16] base.u8[..= 9],
 
+        yuv_cache : array[26] array[32] base.u8,
+
         dst_x : base.u32,
         dst_y : base.u32,
 
diff --git a/test/c/std/vp8.c b/test/c/std/vp8.c
index 6d4eeb9..bcd3a4f 100644
--- a/test/c/std/vp8.c
+++ b/test/c/std/vp8.c
@@ -65,7 +65,296 @@
 
 // ---------------- VP8 Tests
 
-// No VP8 tests.
+void  //
+initialize_decoder_test_state(wuffs_vp8__decoder* dec) {
+  // Initialize the top and left luma (Y) pixels to the digits of pi.
+
+  dec->private_impl.f_yuv_cache[0x00][0x07] = 0x31;
+  dec->private_impl.f_yuv_cache[0x00][0x08] = 0x41;
+  dec->private_impl.f_yuv_cache[0x00][0x09] = 0x59;
+  dec->private_impl.f_yuv_cache[0x00][0x0A] = 0x26;
+  dec->private_impl.f_yuv_cache[0x00][0x0B] = 0x53;
+  dec->private_impl.f_yuv_cache[0x00][0x0C] = 0x58;
+  dec->private_impl.f_yuv_cache[0x00][0x0D] = 0x97;
+  dec->private_impl.f_yuv_cache[0x00][0x0E] = 0x93;
+  dec->private_impl.f_yuv_cache[0x00][0x0F] = 0x23;
+  dec->private_impl.f_yuv_cache[0x00][0x10] = 0x84;
+  dec->private_impl.f_yuv_cache[0x00][0x11] = 0x62;
+  dec->private_impl.f_yuv_cache[0x00][0x12] = 0x64;
+  dec->private_impl.f_yuv_cache[0x00][0x13] = 0x33;
+  dec->private_impl.f_yuv_cache[0x00][0x14] = 0x83;
+  dec->private_impl.f_yuv_cache[0x00][0x15] = 0x27;
+  dec->private_impl.f_yuv_cache[0x00][0x16] = 0x95;
+  dec->private_impl.f_yuv_cache[0x00][0x17] = 0x02;
+
+  dec->private_impl.f_yuv_cache[0x01][0x07] = 0x88;
+  dec->private_impl.f_yuv_cache[0x02][0x07] = 0x41;
+  dec->private_impl.f_yuv_cache[0x03][0x07] = 0x97;
+  dec->private_impl.f_yuv_cache[0x04][0x07] = 0x16;
+  dec->private_impl.f_yuv_cache[0x05][0x07] = 0x93;
+  dec->private_impl.f_yuv_cache[0x06][0x07] = 0x99;
+  dec->private_impl.f_yuv_cache[0x07][0x07] = 0x37;
+  dec->private_impl.f_yuv_cache[0x08][0x07] = 0x51;
+  dec->private_impl.f_yuv_cache[0x09][0x07] = 0x05;
+  dec->private_impl.f_yuv_cache[0x0A][0x07] = 0x82;
+  dec->private_impl.f_yuv_cache[0x0B][0x07] = 0x09;
+  dec->private_impl.f_yuv_cache[0x0C][0x07] = 0x74;
+  dec->private_impl.f_yuv_cache[0x0D][0x07] = 0x94;
+  dec->private_impl.f_yuv_cache[0x0E][0x07] = 0x45;
+  dec->private_impl.f_yuv_cache[0x0F][0x07] = 0x92;
+  dec->private_impl.f_yuv_cache[0x10][0x07] = 0x30;
+
+  // Initialize the top and left chroma-blue (U) pixels to the digits of e.
+
+  dec->private_impl.f_yuv_cache[0x11][0x07] = 0x27;
+  dec->private_impl.f_yuv_cache[0x11][0x08] = 0x18;
+  dec->private_impl.f_yuv_cache[0x11][0x09] = 0x28;
+  dec->private_impl.f_yuv_cache[0x11][0x0A] = 0x18;
+  dec->private_impl.f_yuv_cache[0x11][0x0B] = 0x28;
+  dec->private_impl.f_yuv_cache[0x11][0x0C] = 0x45;
+  dec->private_impl.f_yuv_cache[0x11][0x0D] = 0x90;
+  dec->private_impl.f_yuv_cache[0x11][0x0E] = 0x45;
+  dec->private_impl.f_yuv_cache[0x11][0x0F] = 0x23;
+
+  dec->private_impl.f_yuv_cache[0x12][0x07] = 0x53;
+  dec->private_impl.f_yuv_cache[0x13][0x07] = 0x60;
+  dec->private_impl.f_yuv_cache[0x14][0x07] = 0x28;
+  dec->private_impl.f_yuv_cache[0x15][0x07] = 0x74;
+  dec->private_impl.f_yuv_cache[0x16][0x07] = 0x71;
+  dec->private_impl.f_yuv_cache[0x17][0x07] = 0x35;
+  dec->private_impl.f_yuv_cache[0x18][0x07] = 0x26;
+  dec->private_impl.f_yuv_cache[0x19][0x07] = 0x62;
+}
+
+const char*  //
+test_wuffs_vp8_decode_predict_uv8() {
+  CHECK_FOCUS(__func__);
+
+  const uint64_t test_cases[13][8] = {
+      {0x4444444444444444, 0x4444444444444444, 0x4444444444444444,
+       0x4444444444444444, 0x4444444444444444, 0x4444444444444444,
+       0x4444444444444444, 0x4444444444444444},
+      {0x4454445471BC714F, 0x516151617EC97E5C, 0x1929192946914624,
+       0x6575657592DD9270, 0x627262728FDA8F6D, 0x26362636539E5331,
+       0x17271727448F4422, 0x5363536380CB805E},
+      {0x1828182845904523, 0x1828182845904523, 0x1828182845904523,
+       0x1828182845904523, 0x1828182845904523, 0x1828182845904523,
+       0x1828182845904523, 0x1828182845904523},
+      {0x5353535353535353, 0x6060606060606060, 0x2828282828282828,
+       0x7474747474747474, 0x7171717171717171, 0x3535353535353535,
+       0x2626262626262626, 0x6262626262626262},
+
+      {0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0},
+
+      {0x5050505050505050, 0x5050505050505050, 0x5050505050505050,
+       0x5050505050505050, 0x5050505050505050, 0x5050505050505050,
+       0x5050505050505050, 0x5050505050505050},
+      {0x3838383838383838, 0x3838383838383838, 0x3838383838383838,
+       0x3838383838383838, 0x3838383838383838, 0x3838383838383838,
+       0x3838383838383838, 0x3838383838383838},
+      {0x8080808080808080, 0x8080808080808080, 0x8080808080808080,
+       0x8080808080808080, 0x8080808080808080, 0x8080808080808080,
+       0x8080808080808080, 0x8080808080808080},
+  };
+
+  wuffs_vp8__decoder dec = {0};
+  for (int mode = 0; mode < 13; mode++) {
+    uint64_t w0 = test_cases[mode][0];
+    uint64_t w1 = test_cases[mode][1];
+    uint64_t w2 = test_cases[mode][2];
+    uint64_t w3 = test_cases[mode][3];
+    uint64_t w4 = test_cases[mode][4];
+    uint64_t w5 = test_cases[mode][5];
+    uint64_t w6 = test_cases[mode][6];
+    uint64_t w7 = test_cases[mode][7];
+
+    if (w0 == 0) {
+      continue;
+    }
+
+    initialize_decoder_test_state(&dec);
+
+    wuffs_vp8__decoder__predict_uv8(&dec, 0, mode);
+
+    uint64_t h0 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x12][8]);
+    uint64_t h1 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x13][8]);
+    uint64_t h2 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x14][8]);
+    uint64_t h3 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x15][8]);
+    uint64_t h4 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x16][8]);
+    uint64_t h5 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x17][8]);
+    uint64_t h6 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x18][8]);
+    uint64_t h7 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x19][8]);
+
+    if ((h0 != w0) || (h1 != w1) || (h2 != w2) || (h3 != w3) ||  //
+        (h4 != w4) || (h5 != w5) || (h6 != w6) || (h7 != w7)) {
+      RETURN_FAIL(
+          "mode=%d:"                                                         //
+          "\nhave %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64  //
+          " %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64        //
+          "\nwant %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64  //
+          " %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64,       //
+          mode, h0, h1, h2, h3, h4, h5, h6, h7, w0, w1, w2, w3, w4, w5, w6, w7);
+    }
+  }
+
+  return NULL;
+}
+
+const char*  //
+test_wuffs_vp8_decode_predict_y16() {
+  CHECK_FOCUS(__func__);
+
+  const uint64_t test_cases[13][9] = {
+
+      {0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A,
+       0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A,
+       0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A, 0x5A5A5A5A5A5A5A5A},
+      {0x98B07DAAAFEEEA7A, 0x5169366368A7A333, 0xA7BF8CB9BEFDF989,
+       0x263E0B383D7C7808, 0xA3BB88B5BAF9F585, 0xA9C18EBBC0FFFB8B,
+       0x475F2C595E9D9929, 0x6179467378B7B343, 0x152D00272C6B6700},
+      {0x4159265358979323, 0x4159265358979323, 0x4159265358979323,
+       0x4159265358979323, 0x4159265358979323, 0x4159265358979323,
+       0x4159265358979323, 0x4159265358979323, 0x4159265358979323},
+      {0x8888888888888888, 0x4141414141414141, 0x9797979797979797,
+       0x1616161616161616, 0x9393939393939393, 0x9999999999999999,
+       0x3737373737373737, 0x5151515151515151, 0x0505050505050505},
+
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+      {0, 0, 0, 0, 0, 0, 0, 0, 0},
+
+      {0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D,
+       0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D,
+       0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D, 0x5D5D5D5D5D5D5D5D},
+      {0x5757575757575757, 0x5757575757575757, 0x5757575757575757,
+       0x5757575757575757, 0x5757575757575757, 0x5757575757575757,
+       0x5757575757575757, 0x5757575757575757, 0x5757575757575757},
+      {0x8080808080808080, 0x8080808080808080, 0x8080808080808080,
+       0x8080808080808080, 0x8080808080808080, 0x8080808080808080,
+       0x8080808080808080, 0x8080808080808080, 0x8080808080808080},
+  };
+
+  wuffs_vp8__decoder dec = {0};
+  for (int mode = 0; mode < 13; mode++) {
+    uint64_t w0 = test_cases[mode][0];
+    uint64_t w1 = test_cases[mode][1];
+    uint64_t w2 = test_cases[mode][2];
+    uint64_t w3 = test_cases[mode][3];
+    uint64_t w4 = test_cases[mode][4];
+    uint64_t w5 = test_cases[mode][5];
+    uint64_t w6 = test_cases[mode][6];
+    uint64_t w7 = test_cases[mode][7];
+    uint64_t w8 = test_cases[mode][8];
+
+    if (w0 == 0) {
+      continue;
+    }
+
+    initialize_decoder_test_state(&dec);
+
+    wuffs_vp8__decoder__predict_y16(&dec, mode);
+
+    uint64_t h0 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x01][8]);
+    uint64_t h1 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x02][8]);
+    uint64_t h2 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x03][8]);
+    uint64_t h3 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x04][8]);
+    uint64_t h4 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x05][8]);
+    uint64_t h5 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x06][8]);
+    uint64_t h6 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x07][8]);
+    uint64_t h7 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x08][8]);
+    uint64_t h8 = wuffs_base__peek_u64be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[0x09][8]);
+
+    if ((h0 != w0) || (h1 != w1) || (h2 != w2) || (h3 != w3) ||  //
+        (h4 != w4) || (h5 != w5) || (h6 != w6) || (h7 != w7) || (h8 != w8)) {
+      RETURN_FAIL(
+          "mode=%d:"                                                         //
+          "\nhave %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64  //
+          " %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64        //
+          " %016" PRIX64                                                     //
+          "\nwant %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64  //
+          " %016" PRIX64 " %016" PRIX64 " %016" PRIX64 " %016" PRIX64        //
+          " %016" PRIX64,                                                    //
+          mode, h0, h1, h2, h3, h4, h5, h6, h7, h8,                          //
+          w0, w1, w2, w3, w4, w5, w6, w7, w8);
+    }
+  }
+
+  return NULL;
+}
+
+const char*  //
+test_wuffs_vp8_decode_predict_y4() {
+  CHECK_FOCUS(__func__);
+
+  const uint32_t test_cases[10][4] = {
+      {0x51515151, 0x51515151, 0x51515151, 0x51515151},
+      {0x98B07DAA, 0x51693663, 0xA7BF8CB9, 0x263E0B38},
+      {0x43463E49, 0x43463E49, 0x43463E49, 0x43463E49},
+      {0x61616161, 0x68686868, 0x61616161, 0x36363636},
+      {0x4B43463E, 0x614B4346, 0x68614B43, 0x6168614B},
+      {0x394D403D, 0x4B43463E, 0x61394D40, 0x684B4346},
+      {0x463E4967, 0x3E496786, 0x49678678, 0x6786783F},
+      {0x4D403D56, 0x463E4967, 0x403D5686, 0x3E496778},
+      {0x5D4B4346, 0x65615D4B, 0x6C686561, 0x57616C68},
+      {0x65686C61, 0x6C615736, 0x57361616, 0x16161616},
+  };
+
+  wuffs_vp8__decoder dec = {0};
+  for (int mode = 0; mode < 10; mode++) {
+    uint32_t w0 = test_cases[mode][0];
+    uint32_t w1 = test_cases[mode][1];
+    uint32_t w2 = test_cases[mode][2];
+    uint32_t w3 = test_cases[mode][3];
+
+    initialize_decoder_test_state(&dec);
+
+    dec.private_impl.f_mb_subblock_modes[0] = mode;
+    wuffs_vp8__decoder__predict_y4(&dec, 0);
+
+    uint32_t h0 = wuffs_base__peek_u32be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[1][8]);
+    uint32_t h1 = wuffs_base__peek_u32be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[2][8]);
+    uint32_t h2 = wuffs_base__peek_u32be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[3][8]);
+    uint32_t h3 = wuffs_base__peek_u32be__no_bounds_check(
+        &dec.private_impl.f_yuv_cache[4][8]);
+
+    if ((h0 != w0) || (h1 != w1) || (h2 != w2) || (h3 != w3)) {
+      RETURN_FAIL(
+          "mode=%d:"                                                      //
+          "\nhave %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32   //
+          "\nwant %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32,  //
+          mode, h0, h1, h2, h3, w0, w1, w2, w3);
+    }
+  }
+  return NULL;
+}
 
 // ---------------- Mimic Tests
 
@@ -91,7 +380,9 @@
 
 proc g_tests[] = {
 
-// No VP8 tests.
+    test_wuffs_vp8_decode_predict_uv8,
+    test_wuffs_vp8_decode_predict_y16,
+    test_wuffs_vp8_decode_predict_y4,
 
 #ifdef WUFFS_MIMIC