Use per-channel array for blk_skip to avoid uninitialized values

The old `blk_skip` array was used as a bit-field, combining blk_skip values of 3 planes into one value. However, for sub-8x8 blocks, where a chroma block can cover multiple luma blocks, the `blk_skip` values for chroma planes were uninitialized / garbage during RDO in some cases, because saving/restoring logic was only using the luma block size.

Also, added back an assertion which checked for uninitialized values -- it was removed during adoption of SDP.

The issue was observed in lossless mode only for now (see #160 ), where all transform sizes are forced to be 4x4. 

No change in stats for lossy encoding in release build.

Fixes #160
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index d8f0cec..ef01c11 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -755,11 +755,10 @@
   /*! \brief Whether to skip transform and quantization on a txfm block level.
    *
    * Skips transform and quantization on a transform block level inside the
-   * current partition block. Each element of this array is used as a bit-field.
-   * So for example, the we are skipping on the luma plane, then the last bit
-   * would be set to 1.
+   * current partition block. For each plane, when we are skipping transform and
+   * quantization, the last bit will be set to 1.
    */
-  uint8_t blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
+  uint8_t blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE];
 
   /*! \brief Transform types inside the partition block
    *
@@ -1929,31 +1928,26 @@
          !xd->lossless[mbmi->segment_id];
 }
 
-static INLINE void set_blk_skip(uint8_t txb_skip[], int plane, int blk_idx,
-                                int skip) {
+static INLINE void set_blk_skip(uint8_t txb_skip[], int blk_idx, int skip) {
   if (skip)
-    txb_skip[blk_idx] |= 1UL << plane;
+    txb_skip[blk_idx] |= 1UL;
   else
-    txb_skip[blk_idx] &= ~(1UL << plane);
+    txb_skip[blk_idx] &= ~(1UL);
 #ifndef NDEBUG
-  // Set chroma planes to uninitialized states when luma is set to check if
-  // it will be set later
-  if (plane == 0) {
-    txb_skip[blk_idx] |= 1UL << (1 + 4);
-    txb_skip[blk_idx] |= 1UL << (2 + 4);
-  }
-
-  // Clear the initialization checking bit
-  txb_skip[blk_idx] &= ~(1UL << (plane + 4));
+  // Mark this block as initialized (0).
+  txb_skip[blk_idx] &= ~(1UL << 4);
 #endif
 }
 
-static INLINE int is_blk_skip(uint8_t *txb_skip, int plane, int blk_idx) {
+static INLINE int is_blk_skip(uint8_t *txb_skip, int blk_idx) {
 #ifndef NDEBUG
-  // The magic number is 0x77, this is to test if there is garbage data
-  assert((txb_skip[blk_idx] & 0x88) == 0);
+  // Ensure that this block is initialized.
+  assert((txb_skip[blk_idx] & (1U << 4)) == 0);
+  // These were initialized to fixed pattern 0x11 in `av1_rd_pick_partition`.
+  // Ensure other bits are 0 to make sure there is no garbage data.
+  assert((txb_skip[blk_idx] & 0xEE) == 0);
 #endif
-  return (txb_skip[blk_idx] >> plane) & 1;
+  return txb_skip[blk_idx] & 1;
 }
 
 #if CONFIG_EXT_RECUR_PARTITIONS
diff --git a/av1/encoder/context_tree.c b/av1/encoder/context_tree.c
index 75f0307..e6ed6ae 100644
--- a/av1/encoder/context_tree.c
+++ b/av1/encoder/context_tree.c
@@ -24,7 +24,7 @@
 };
 
 void av1_copy_tree_context(PICK_MODE_CONTEXT *dst_ctx,
-                           PICK_MODE_CONTEXT *src_ctx) {
+                           PICK_MODE_CONTEXT *src_ctx, int num_planes) {
   dst_ctx->mic = src_ctx->mic;
 #if CONFIG_C071_SUBBLK_WARPMV
   if (is_warp_mode(src_ctx->mic.motion_mode)) {
@@ -37,8 +37,12 @@
   dst_ctx->num_4x4_blk_chroma = src_ctx->num_4x4_blk_chroma;
   dst_ctx->skippable = src_ctx->skippable;
 
-  memcpy(dst_ctx->blk_skip, src_ctx->blk_skip,
-         sizeof(uint8_t) * src_ctx->num_4x4_blk);
+  for (int i = 0; i < num_planes; ++i) {
+    const int num_blk_plane =
+        (i == 0) ? src_ctx->num_4x4_blk : src_ctx->num_4x4_blk_chroma;
+    memcpy(dst_ctx->blk_skip[i], src_ctx->blk_skip[i],
+           sizeof(*src_ctx->blk_skip[i]) * num_blk_plane);
+  }
   av1_copy_array(dst_ctx->tx_type_map, src_ctx->tx_type_map,
                  src_ctx->num_4x4_blk);
   av1_copy_array(dst_ctx->cctx_type_map, src_ctx->cctx_type_map,
@@ -131,8 +135,6 @@
   ctx->num_4x4_blk = num_blk;
   ctx->num_4x4_blk_chroma = num_pix_chroma / 16;
 
-  AOM_CHECK_MEM_ERROR(&error, ctx->blk_skip,
-                      aom_calloc(num_blk, sizeof(*ctx->blk_skip)));
   AOM_CHECK_MEM_ERROR(&error, ctx->tx_type_map,
                       aom_calloc(num_blk, sizeof(*ctx->tx_type_map)));
 #if CONFIG_C071_SUBBLK_WARPMV
@@ -154,6 +156,8 @@
 #else
     const int num_blk_plane = ctx->num_4x4_blk;
 #endif  // CONFIG_FLEX_PARTITION
+    AOM_CHECK_MEM_ERROR(&error, ctx->blk_skip[i],
+                        aom_calloc(num_blk_plane, sizeof(*ctx->blk_skip[i])));
     AOM_CHECK_MEM_ERROR(
         &error, ctx->eobs[i],
         aom_memalign(32, num_blk_plane * sizeof(*ctx->eobs[i])));
@@ -185,8 +189,10 @@
     free(ctx->submic);
   }
 #endif  // CONFIG_C071_SUBBLK_WARPMV
-  aom_free(ctx->blk_skip);
-  ctx->blk_skip = NULL;
+  for (int i = 0; i < MAX_MB_PLANE; ++i) {
+    aom_free(ctx->blk_skip[i]);
+    ctx->blk_skip[i] = NULL;
+  }
   aom_free(ctx->tx_type_map);
   aom_free(ctx->cctx_type_map);
   for (int i = 0; i < num_planes; ++i) {
@@ -596,7 +602,7 @@
       dst->none_chroma =
           av1_alloc_pmc(cm, tree_type, mi_row, mi_col, bsize, dst,
                         PARTITION_NONE, 0, ss_x, ss_y, shared_bufs);
-      av1_copy_tree_context(dst->none_chroma, src->none_chroma);
+      av1_copy_tree_context(dst->none_chroma, src->none_chroma, num_planes);
     }
   }
 #endif  // CONFIG_EXTENDED_SDP
@@ -613,7 +619,7 @@
             av1_alloc_pmc(cm, tree_type, mi_row, mi_col, bsize, dst,
                           PARTITION_NONE, 0, ss_x, ss_y, shared_bufs);
         av1_copy_tree_context(dst->none[cur_region_type],
-                              src->none[cur_region_type]);
+                              src->none[cur_region_type], num_planes);
 #if CONFIG_MVP_IMPROVEMENT
         if (is_inter_block(&src->none[cur_region_type]->mic, xd->tree_type)) {
 #if WARP_CU_BANK
@@ -631,7 +637,7 @@
       if (src->none) {
         dst->none = av1_alloc_pmc(cm, tree_type, mi_row, mi_col, bsize, dst,
                                   PARTITION_NONE, 0, ss_x, ss_y, shared_bufs);
-        av1_copy_tree_context(dst->none, src->none);
+        av1_copy_tree_context(dst->none, src->none, num_planes);
 #if CONFIG_MVP_IMPROVEMENT
         if (is_inter_block(&src->none->mic, xd->tree_type)) {
 #if WARP_CU_BANK
diff --git a/av1/encoder/context_tree.h b/av1/encoder/context_tree.h
index 37c8744..9cd1298 100644
--- a/av1/encoder/context_tree.h
+++ b/av1/encoder/context_tree.h
@@ -40,7 +40,7 @@
 #endif  // CONFIG_C071_SUBBLK_WARPMV
   MB_MODE_INFO_EXT_FRAME mbmi_ext_best;
   uint8_t *color_index_map[2];
-  uint8_t *blk_skip;
+  uint8_t *blk_skip[MAX_MB_PLANE];
 
   tran_low_t *coeff[MAX_MB_PLANE];
   tran_low_t *qcoeff[MAX_MB_PLANE];
@@ -180,7 +180,7 @@
                                  PC_TREE_SHARED_BUFFERS *shared_bufs);
 void av1_free_pmc(PICK_MODE_CONTEXT *ctx, int num_planes);
 void av1_copy_tree_context(PICK_MODE_CONTEXT *dst_ctx,
-                           PICK_MODE_CONTEXT *src_ctx);
+                           PICK_MODE_CONTEXT *src_ctx, int num_planes);
 
 void av1_setup_sms_tree(struct AV1_COMP *const cpi, struct ThreadData *td);
 void av1_free_sms_tree(struct ThreadData *td);
diff --git a/av1/encoder/encodeframe_utils.c b/av1/encoder/encodeframe_utils.c
index c352e68..ddc725a 100644
--- a/av1/encoder/encodeframe_utils.c
+++ b/av1/encoder/encodeframe_utils.c
@@ -288,8 +288,12 @@
 #endif  // CONFIG_SEP_COMP_DRL
     );
 
-  memcpy(txfm_info->blk_skip, ctx->blk_skip,
-         sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+  for (i = 0; i < num_planes; ++i) {
+    const int num_blk_plane =
+        (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+    memcpy(txfm_info->blk_skip[i], ctx->blk_skip[i],
+           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+  }
 
   txfm_info->skip_txfm = ctx->rd_stats.skip_txfm;
   if (xd->tree_type != CHROMA_PART) {
diff --git a/av1/encoder/encodemb.c b/av1/encoder/encodemb.c
index 1ee70ad..7afde0a 100644
--- a/av1/encoder/encodemb.c
+++ b/av1/encoder/encodemb.c
@@ -757,7 +757,7 @@
   CctxType cctx_type =
       plane ? av1_get_cctx_type(xd, blk_row, blk_col) : CCTX_NONE;
 
-  if (!is_blk_skip(x->txfm_search_info.blk_skip, plane,
+  if (!is_blk_skip(x->txfm_search_info.blk_skip[plane],
                    blk_row * bw + blk_col) &&
       (plane < AOM_PLANE_V || !is_cctx_allowed(cm, xd) ||
 #if CCTX_C2_DROPPED
@@ -1343,7 +1343,7 @@
   }
 #endif
 
-  if (plane == 0 && is_blk_skip(x->txfm_search_info.blk_skip, plane,
+  if (plane == 0 && is_blk_skip(x->txfm_search_info.blk_skip[plane],
                                 blk_row * bw + blk_col)) {
     *eob = 0;
     *bob_code = 0;
diff --git a/av1/encoder/intra_mode_search.c b/av1/encoder/intra_mode_search.c
index e8254f7..f93b486 100644
--- a/av1/encoder/intra_mode_search.c
+++ b/av1/encoder/intra_mode_search.c
@@ -101,8 +101,10 @@
 #endif  // CONFIG_NEW_TX_PARTITION
       filter_intra_mode_info = mbmi->filter_intra_mode_info;
       av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
-      memcpy(ctx->blk_skip, x->txfm_search_info.blk_skip,
-             sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
+      memcpy(ctx->blk_skip[AOM_PLANE_Y],
+             x->txfm_search_info.blk_skip[AOM_PLANE_Y],
+             sizeof(*x->txfm_search_info.blk_skip[AOM_PLANE_Y]) *
+                 ctx->num_4x4_blk);
       *rate = this_rate;
       *rate_tokenonly = tokenonly_rd_stats.rate;
       *distortion = tokenonly_rd_stats.dist;
@@ -956,7 +958,7 @@
     return skippable;
   }
 
-  memcpy(x->txfm_search_info.blk_skip, best_blk_skip,
+  memcpy(x->txfm_search_info.blk_skip[AOM_PLANE_Y], best_blk_skip,
          sizeof(best_blk_skip[0]) * bsize_to_num_blk(bsize));
   av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk);
   memcpy(color_map, best_palette_color_map,
@@ -1078,8 +1080,8 @@
     *rate_tokenonly = this_rate_tokenonly;
     *distortion = rd_stats.dist;
     *skippable = rd_stats.skip_txfm;
-    av1_copy_array(ctx->blk_skip, x->txfm_search_info.blk_skip,
-                   ctx->num_4x4_blk);
+    av1_copy_array(ctx->blk_skip[AOM_PLANE_Y],
+                   x->txfm_search_info.blk_skip[AOM_PLANE_Y], ctx->num_4x4_blk);
     av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
     return 1;
   }
@@ -1117,7 +1119,7 @@
   TX_SIZE best_tx_size = mbmi->tx_size;
   FILTER_INTRA_MODE best_fi_mode = FILTER_DC_PRED;
   uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
-  memcpy(best_blk_skip, x->txfm_search_info.blk_skip,
+  memcpy(best_blk_skip, x->txfm_search_info.blk_skip[AOM_PLANE_Y],
          sizeof(best_blk_skip[0]) * ctx->num_4x4_blk);
   TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
 #if CONFIG_NEW_TX_PARTITION
@@ -1145,7 +1147,7 @@
       best_tx_partition = mbmi->tx_partition_type[0];
 #endif  // CONFIG_NEW_TX_PARTITION
       av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
-      memcpy(best_blk_skip, x->txfm_search_info.blk_skip,
+      memcpy(best_blk_skip, x->txfm_search_info.blk_skip[AOM_PLANE_Y],
              sizeof(best_blk_skip[0]) * ctx->num_4x4_blk);
       best_fi_mode = fi_mode;
       *rd_stats_y = rd_stats_y_fi;
@@ -1159,8 +1161,8 @@
   mbmi->tx_partition_type[0] = best_tx_partition;
 #endif  // CONFIG_NEW_TX_PARTITION
   av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk);
-  memcpy(x->txfm_search_info.blk_skip, best_blk_skip,
-         sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
+  memcpy(x->txfm_search_info.blk_skip[AOM_PLANE_Y], best_blk_skip,
+         sizeof(*x->txfm_search_info.blk_skip[AOM_PLANE_Y]) * ctx->num_4x4_blk);
 
   if (filter_intra_selected_flag) {
     mbmi->filter_intra_mode_info.use_filter_intra = 1;
@@ -1747,8 +1749,10 @@
           best_filt = 0;
           best_angle_delta = mbmi->angle_delta[PLANE_TYPE_Y];
           av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
-          memcpy(ctx->blk_skip, x->txfm_search_info.blk_skip,
-                 sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
+          memcpy(ctx->blk_skip[AOM_PLANE_Y],
+                 x->txfm_search_info.blk_skip[AOM_PLANE_Y],
+                 sizeof(*x->txfm_search_info.blk_skip[AOM_PLANE_Y]) *
+                     ctx->num_4x4_blk);
           *rate = this_rate;
           *rate_tokenonly = tokenonly_rd_stats.rate;
           *distortion = tokenonly_rd_stats.dist;
@@ -2048,8 +2052,10 @@
           *rate_tokenonly = this_rate_tokenonly;
           *distortion = this_distortion;
           *skippable = s;
-          memcpy(ctx->blk_skip, x->txfm_search_info.blk_skip,
-                 sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
+          memcpy(ctx->blk_skip[AOM_PLANE_Y],
+                 x->txfm_search_info.blk_skip[AOM_PLANE_Y],
+                 sizeof(*x->txfm_search_info.blk_skip[AOM_PLANE_Y]) *
+                     ctx->num_4x4_blk);
           av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
         }
       }
@@ -2089,7 +2095,7 @@
                                   &best_mbmi, best_palette_color_map, &best_rd,
                                   &best_model_rd, rate, rate_tokenonly,
                                   distortion, skippable, &beat_best_rd, ctx,
-                                  ctx->blk_skip, ctx->tx_type_map);
+                                  ctx->blk_skip[AOM_PLANE_Y], ctx->tx_type_map);
   }
 
   // Searches filter_intra
diff --git a/av1/encoder/palette.c b/av1/encoder/palette.c
index 342ac55..421078e 100644
--- a/av1/encoder/palette.c
+++ b/av1/encoder/palette.c
@@ -297,8 +297,9 @@
     memcpy(best_palette_color_map, color_map,
            block_width * block_height * sizeof(color_map[0]));
     *best_mbmi = *mbmi;
-    memcpy(blk_skip, x->txfm_search_info.blk_skip,
-           sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
+    memcpy(
+        blk_skip, x->txfm_search_info.blk_skip[AOM_PLANE_Y],
+        sizeof(*x->txfm_search_info.blk_skip[AOM_PLANE_Y]) * ctx->num_4x4_blk);
     av1_copy_array(tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
     if (rate) *rate = this_rate;
     if (rate_tokenonly) *rate_tokenonly = tokenonly_rd_stats.rate;
diff --git a/av1/encoder/partition_search.c b/av1/encoder/partition_search.c
index fc1851d..0af18db 100644
--- a/av1/encoder/partition_search.c
+++ b/av1/encoder/partition_search.c
@@ -5198,12 +5198,14 @@
     // Copy of mode search results if the ctx is ready.
     if (is_ctx_ready[ab_part_type][0]) {
       av1_copy_tree_context(cur_part_ctxs[ab_part_type][0],
-                            mode_srch_ctx[ab_part_type][0][0]);
+                            mode_srch_ctx[ab_part_type][0][0],
+                            av1_num_planes(cm));
       cur_part_ctxs[ab_part_type][0]->mic.partition = part_type;
       cur_part_ctxs[ab_part_type][0]->rd_mode_is_ready = 1;
       if (is_ctx_ready[ab_part_type][1]) {
         av1_copy_tree_context(cur_part_ctxs[ab_part_type][1],
-                              mode_srch_ctx[ab_part_type][1][0]);
+                              mode_srch_ctx[ab_part_type][1][0],
+                              av1_num_planes(cm));
         cur_part_ctxs[ab_part_type][1]->mic.partition = part_type;
         cur_part_ctxs[ab_part_type][1]->rd_mode_is_ready = 1;
       }
@@ -8738,12 +8740,15 @@
 
 #ifndef NDEBUG
   // Nothing should rely on the default value of this array (which is just
-  // leftover from encoding the previous block. Setting it to fixed pattern
+  // leftover from encoding the previous block). Setting it to fixed pattern
   // when debugging.
-  // bit 0, 1, 2 are blk_skip of each plane
-  // bit 4, 5, 6 are initialization checking of each plane
-  memset(x->txfm_search_info.blk_skip, 0x77,
-         sizeof(x->txfm_search_info.blk_skip));
+  // bit 0 is blk_skip of each plane.
+  // bit 4 is initialization checking bit (1 = uninitialized).
+  // See related logic in `set_blk_skip` and `is_blk_skip`.
+  for (int i = (xd->tree_type == CHROMA_PART); i < num_planes; ++i) {
+    memset(x->txfm_search_info.blk_skip[i], 0x11,
+           sizeof(x->txfm_search_info.blk_skip[i]));
+  }
 #endif  // NDEBUG
 
   assert(bsize < BLOCK_SIZES_ALL);
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index d96450b..e5d4d3e 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -2082,7 +2082,7 @@
   const int rate2_nocoeff = rd_stats->rate;
   int best_xskip_txfm = 0;
   RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
-  uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
+  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE];
   TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
   CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
   const int rate_mv0 =
@@ -3218,8 +3218,13 @@
           best_rd_stats_y = *rd_stats_y;
           best_rate_mv = tmp_rate_mv;
           if (num_planes > 1) best_rd_stats_uv = *rd_stats_uv;
-          memcpy(best_blk_skip, txfm_info->blk_skip,
-                 sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
+          for (int i = 0; i < num_planes; ++i) {
+            const int num_blk_plane =
+                (xd->plane[i].height * xd->plane[i].width) >>
+                (2 * MI_SIZE_LOG2);
+            memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
+                   sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+          }
           av1_copy_array(best_tx_type_map, xd->tx_type_map,
                          xd->height * xd->width);
           av1_copy_array(
@@ -3248,8 +3253,12 @@
   *rd_stats = best_rd_stats;
   *rd_stats_y = best_rd_stats_y;
   if (num_planes > 1) *rd_stats_uv = best_rd_stats_uv;
-  memcpy(txfm_info->blk_skip, best_blk_skip,
-         sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
+  for (int i = 0; i < num_planes; ++i) {
+    const int num_blk_plane =
+        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
+    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
+           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+  }
   av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
   av1_copy_array(
       xd->cctx_type_map, best_cctx_type_map,
@@ -5035,7 +5044,7 @@
   int64_t ret_val = INT64_MAX;
   RD_STATS best_rd_stats, best_rd_stats_y, best_rd_stats_uv;
   int64_t best_rd = INT64_MAX;
-  uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE];
+  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE];
   TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
   CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
   MB_MODE_INFO best_mbmi = *mbmi;
@@ -6295,8 +6304,13 @@
                       }
 #endif  // CONFIG_C071_SUBBLK_WARPMV
                       best_xskip_txfm = txfm_info->skip_txfm;
-                      memcpy(best_blk_skip, txfm_info->blk_skip,
-                             sizeof(best_blk_skip[0]) * xd->height * xd->width);
+                      for (i = 0; i < num_planes; ++i) {
+                        const int num_blk_plane =
+                            (xd->plane[i].height * xd->plane[i].width) >>
+                            (2 * MI_SIZE_LOG2);
+                        memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
+                               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+                      }
                       av1_copy_array(best_tx_type_map, xd->tx_type_map,
                                      xd->height * xd->width);
                       av1_copy_array(
@@ -6368,8 +6382,12 @@
   txfm_info->skip_txfm = best_xskip_txfm;
   assert(IMPLIES(mbmi->comp_group_idx == 1,
                  mbmi->interinter_comp.type != COMPOUND_AVERAGE));
-  memcpy(txfm_info->blk_skip, best_blk_skip,
-         sizeof(best_blk_skip[0]) * xd->height * xd->width);
+  for (i = 0; i < num_planes; ++i) {
+    const int num_blk_plane =
+        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
+    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
+           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+  }
   av1_copy_array(xd->tx_type_map, best_tx_type_map, xd->height * xd->width);
   av1_copy_array(
       xd->cctx_type_map, best_cctx_type_map,
@@ -6693,7 +6711,7 @@
 #endif  // CONFIG_MORPH_PRED
   MB_MODE_INFO best_mbmi = *mbmi;
   RD_STATS best_rdstats = *rd_stats;
-  uint8_t best_blk_skip[MAX_MIB_SIZE * MAX_MIB_SIZE] = { 0 };
+  uint8_t best_blk_skip[MAX_MB_PLANE][MAX_MIB_SIZE * MAX_MIB_SIZE] = { 0 };
   TX_TYPE best_tx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
   av1_copy_array(best_tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
   CctxType best_cctx_type_map[MAX_MIB_SIZE * MAX_MIB_SIZE];
@@ -7070,8 +7088,12 @@
         best_rd = rd_stats_yuv.rdcost;
         best_mbmi = *mbmi;
         best_rdstats = rd_stats_yuv;
-        memcpy(best_blk_skip, txfm_info->blk_skip,
-               sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
+        for (int i = 0; i < num_planes; ++i) {
+          const int num_blk_plane =
+              (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
+          memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
+                 sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+        }
         av1_copy_array(best_tx_type_map, xd->tx_type_map,
                        xd->height * xd->width);
         av1_copy_array(best_cctx_type_map, xd->cctx_type_map,
@@ -7089,8 +7111,12 @@
       best_rd = rd_stats_yuv.rdcost;
       best_mbmi = *mbmi;
       best_rdstats = rd_stats_yuv;
-      memcpy(best_blk_skip, txfm_info->blk_skip,
-             sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
+      for (int i = 0; i < num_planes; ++i) {
+        const int num_blk_plane =
+            (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
+        memcpy(best_blk_skip[i], txfm_info->blk_skip[i],
+               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+      }
       av1_copy_array(best_tx_type_map, xd->tx_type_map, xd->height * xd->width);
       av1_copy_array(
           best_cctx_type_map, xd->cctx_type_map,
@@ -7108,8 +7134,12 @@
 #endif  // CONFIG_IBC_BV_IMPROVEMENT
 
   *rd_stats = best_rdstats;
-  memcpy(txfm_info->blk_skip, best_blk_skip,
-         sizeof(txfm_info->blk_skip[0]) * xd->height * xd->width);
+  for (int i = 0; i < num_planes; ++i) {
+    const int num_blk_plane =
+        (xd->plane[i].height * xd->plane[i].width) >> (2 * MI_SIZE_LOG2);
+    memcpy(txfm_info->blk_skip[i], best_blk_skip[i],
+           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+  }
   av1_copy_array(xd->tx_type_map, best_tx_type_map, ctx->num_4x4_blk);
   av1_copy_array(xd->cctx_type_map, best_cctx_type_map,
                  ctx->num_4x4_blk_chroma);
@@ -7161,8 +7191,8 @@
       // Set up the tx variables for reproducing the y predictions in case we
       // need it for chroma-from-luma.
       if (xd->is_chroma_ref && store_cfl_required_rdo(cm, x)) {
-        memcpy(txfm_info->blk_skip, ctx->blk_skip,
-               sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+        memcpy(txfm_info->blk_skip[AOM_PLANE_Y], ctx->blk_skip[AOM_PLANE_Y],
+               sizeof(*txfm_info->blk_skip[AOM_PLANE_Y]) * ctx->num_4x4_blk);
         av1_copy_array(xd->tx_type_map, ctx->tx_type_map, ctx->num_4x4_blk);
       }
       const TX_SIZE max_uv_tx_size = av1_get_tx_size(AOM_PLANE_U, xd);
@@ -7191,8 +7221,12 @@
     best_rd = rd_cost->rdcost;
   if (rd_pick_intrabc_mode_sb(cpi, x, ctx, rd_cost, bsize, best_rd) < best_rd) {
     ctx->rd_stats.skip_txfm = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
-    memcpy(ctx->blk_skip, txfm_info->blk_skip,
-           sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+    for (int i = 0; i < num_planes; ++i) {
+      const int num_blk_plane =
+          (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+      memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
+             sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+    }
     assert(rd_cost->rate != INT_MAX);
   }
   if (rd_cost->rate == INT_MAX) return;
@@ -7648,8 +7682,12 @@
         restore_dst_buf(xd, orig_dst, num_planes);
       } else {
         x->txfm_search_info.skip_txfm = 0;
-        memcpy(ctx->blk_skip, txfm_info->blk_skip,
-               sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+        for (int i = 0; i < num_planes; ++i) {
+          const int num_blk_plane =
+              (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+          memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
+                 sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+        }
         av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
         av1_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                        ctx->num_4x4_blk_chroma);
@@ -8003,7 +8041,7 @@
           memset(mbmi->inter_tx_size, mbmi->tx_size,
                  sizeof(mbmi->inter_tx_size));
           for (int i = 0; i < xd->height * xd->width; ++i)
-            set_blk_skip(txfm_info->blk_skip, 0, i, rd_stats_y.skip_txfm);
+            set_blk_skip(txfm_info->blk_skip[0], i, rd_stats_y.skip_txfm);
         }
       } else {
         av1_pick_uniform_tx_size_type_yrd(cpi, x, &rd_stats_y, bsize,
@@ -8048,7 +8086,12 @@
           RDCOST(x->rdmult, this_rate, (rd_stats_y.dist + rd_stats_uv.dist));
       if (best_rd > this_rd) {
         *best_mbmode = *mbmi;
-        av1_copy_array(ctx->blk_skip, txfm_info->blk_skip, ctx->num_4x4_blk);
+        for (int i = 0; i < num_planes; ++i) {
+          const int num_blk_plane =
+              (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+          av1_copy_array(ctx->blk_skip[i], txfm_info->blk_skip[i],
+                         num_blk_plane);
+        }
         av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
         av1_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                        ctx->num_4x4_blk_chroma);
@@ -9287,8 +9330,12 @@
 #endif  // CONFIG_SKIP_TXFM_OPT
     search_state->best_rate_uv = new_best_rd_stats_uv->rate;
   }
-  memcpy(ctx->blk_skip, txfm_info->blk_skip,
-         sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+  for (int i = 0; i < av1_num_planes(cm); ++i) {
+    const int num_blk_plane =
+        (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+    memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
+           sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+  }
   av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
   av1_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                  ctx->num_4x4_blk_chroma);
@@ -10561,8 +10608,12 @@
       search_state.best_mbmode = *mbmi;
       search_state.best_skip2 = 0;
       search_state.best_mode_skippable = this_skippable;
-      memcpy(ctx->blk_skip, txfm_info->blk_skip,
-             sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+      for (i = 0; i < num_planes; ++i) {
+        const int num_blk_plane =
+            (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+        memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
+               sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+      }
       av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
       av1_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                      ctx->num_4x4_blk_chroma);
@@ -10617,8 +10668,13 @@
         search_state.best_skip2 = mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
         search_state.best_mode_skippable =
             mbmi->skip_txfm[xd->tree_type == CHROMA_PART];
-        memcpy(ctx->blk_skip, txfm_info->blk_skip,
-               sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
+
+        for (i = 0; i < num_planes; ++i) {
+          const int num_blk_plane =
+              (i == AOM_PLANE_Y) ? ctx->num_4x4_blk : ctx->num_4x4_blk_chroma;
+          memcpy(ctx->blk_skip[i], txfm_info->blk_skip[i],
+                 sizeof(*txfm_info->blk_skip[i]) * num_blk_plane);
+        }
         av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
         av1_copy_array(ctx->cctx_type_map, xd->cctx_type_map,
                        ctx->num_4x4_blk_chroma);
diff --git a/av1/encoder/tx_search.c b/av1/encoder/tx_search.c
index b6705dc..df37302 100644
--- a/av1/encoder/tx_search.c
+++ b/av1/encoder/tx_search.c
@@ -410,8 +410,8 @@
   MACROBLOCKD *const xd = &x->e_mbd;
   MB_MODE_INFO *const mbmi = xd->mi[0];
   mbmi->tx_size = tx_rd_info->tx_size;
-  memcpy(x->txfm_search_info.blk_skip, tx_rd_info->blk_skip,
-         sizeof(tx_rd_info->blk_skip[0]) * n4);
+  memcpy(x->txfm_search_info.blk_skip[AOM_PLANE_Y], tx_rd_info->blk_skip,
+         sizeof(*tx_rd_info->blk_skip) * n4);
   av1_copy(mbmi->inter_tx_size, tx_rd_info->inter_tx_size);
 #if CONFIG_NEW_TX_PARTITION
   av1_copy(mbmi->tx_partition_type, tx_rd_info->tx_partition_type);
@@ -571,7 +571,7 @@
 #endif  // CONFIG_NEW_TX_PARTITION
   mbmi->tx_size = tx_size;
   for (int i = 0; i < n4; ++i)
-    set_blk_skip(x->txfm_search_info.blk_skip, 0, i, 1);
+    set_blk_skip(x->txfm_search_info.blk_skip[0], i, 1);
   rd_stats->skip_txfm = 1;
   dist = ROUND_POWER_OF_TWO(dist, (xd->bd - 8) * 2);
   rd_stats->dist = rd_stats->sse = (dist << 4);
@@ -630,8 +630,8 @@
   const MB_MODE_INFO *const mbmi = xd->mi[0];
   tx_rd_info->hash_value = hash;
   tx_rd_info->tx_size = mbmi->tx_size;
-  memcpy(tx_rd_info->blk_skip, x->txfm_search_info.blk_skip,
-         sizeof(tx_rd_info->blk_skip[0]) * n4);
+  memcpy(tx_rd_info->blk_skip, x->txfm_search_info.blk_skip[AOM_PLANE_Y],
+         sizeof(*tx_rd_info->blk_skip) * n4);
   av1_copy(tx_rd_info->inter_tx_size, mbmi->inter_tx_size);
 #if CONFIG_NEW_TX_PARTITION
   av1_copy(tx_rd_info->tx_partition_type, mbmi->tx_partition_type);
@@ -3436,7 +3436,7 @@
     update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT);
   }
   rd_stats->skip_txfm = pick_skip_txfm;
-  set_blk_skip(x->txfm_search_info.blk_skip, 0, blk_row * bw + blk_col,
+  set_blk_skip(x->txfm_search_info.blk_skip[0], blk_row * bw + blk_col,
                pick_skip_txfm);
 
 #if !CONFIG_NEW_TX_PARTITION
@@ -3817,7 +3817,7 @@
     mbmi->inter_tx_size[index] = tx_size_selected;
     update_txk_array(xd, offsetr, offsetc, sub_tx,
                      best_partition_tx_types[txb_idx]);
-    set_blk_skip(x->txfm_search_info.blk_skip, 0, offsetr * bw + offsetc,
+    set_blk_skip(x->txfm_search_info.blk_skip[0], offsetr * bw + offsetc,
                  full_blk_skip[txb_idx]);
     block += sub_step;
   }
@@ -3850,7 +3850,7 @@
       mbmi->tx_size = tx_size_selected;
       update_txk_array(xd, offsetr, offsetc, sub_tx,
                        best_partition_tx_types[cur_partition]);
-      set_blk_skip(x->txfm_search_info.blk_skip, 0, offsetr * bw + offsetc,
+      set_blk_skip(x->txfm_search_info.blk_skip[0], offsetr * bw + offsetc,
                    full_blk_skip[cur_partition]);
       block += sub_step;
       cur_partition++;
@@ -3949,7 +3949,7 @@
     mbmi->tx_size = tx_size;
     update_txk_array(xd, blk_row, blk_col, tx_size, no_split.tx_type);
     const int bw = mi_size_wide[plane_bsize];
-    set_blk_skip(x->txfm_search_info.blk_skip, 0, blk_row * bw + blk_col,
+    set_blk_skip(x->txfm_search_info.blk_skip[0], blk_row * bw + blk_col,
                  rd_stats->skip_txfm);
   } else {
     *rd_stats = split_rd_stats;
@@ -4120,7 +4120,7 @@
                                   cur_tx_size, FTXS_NONE, 0);
 
     if (cur_rd < best_rd) {
-      av1_copy_array(best_blk_skip, txfm_info->blk_skip, num_blks);
+      av1_copy_array(best_blk_skip, txfm_info->blk_skip[AOM_PLANE_Y], num_blks);
       av1_copy_array(best_txk_type_map, xd->tx_type_map, num_blks);
       best_tx_size = cur_tx_size;
 #if CONFIG_WAIP
@@ -4167,7 +4167,7 @@
     mbmi->tx_partition_type[0] = best_tx_partition_type;
 #endif  // CONFIG_TX_PARTITION_TYPE_EXT
     av1_copy_array(xd->tx_type_map, best_txk_type_map, num_blks);
-    av1_copy_array(txfm_info->blk_skip, best_blk_skip, num_blks);
+    av1_copy_array(txfm_info->blk_skip[AOM_PLANE_Y], best_blk_skip, num_blks);
   }
 }
 #else
@@ -4327,10 +4327,10 @@
 
   TxfmSearchInfo *txfm_info = &x->txfm_search_info;
   if (plane == 0)
-    set_blk_skip(txfm_info->blk_skip, plane, blk_idx,
+    set_blk_skip(txfm_info->blk_skip[plane], blk_idx,
                  x->plane[plane].eobs[block] == 0);
   else
-    set_blk_skip(txfm_info->blk_skip, plane, blk_idx, 0);
+    set_blk_skip(txfm_info->blk_skip[plane], blk_idx, 0);
 
   int64_t rd;
   if (is_inter) {
@@ -4488,13 +4488,13 @@
       rd_stats->rate = zero_blk_rate;
       rd_stats->dist = rd_stats->sse;
       rd_stats->skip_txfm = 1;
-      set_blk_skip(txfm_info->blk_skip, 0, blk_row * mi_width + blk_col, 1);
+      set_blk_skip(txfm_info->blk_skip[0], blk_row * mi_width + blk_col, 1);
       x->plane[0].eobs[block] = 0;
       x->plane[0].txb_entropy_ctx[block] = 0;
       update_txk_array(xd, blk_row, blk_col, tx_size, DCT_DCT);
     } else {
       rd_stats->skip_txfm = 0;
-      set_blk_skip(txfm_info->blk_skip, 0, blk_row * mi_width + blk_col, 0);
+      set_blk_skip(txfm_info->blk_skip[0], blk_row * mi_width + blk_col, 0);
     }
     if (tx_size > TX_4X4 && depth < MAX_VARTX_DEPTH)
       rd_stats->rate += x->mode_costs.txfm_partition_cost[ctx][0];
@@ -4673,7 +4673,7 @@
     const int blk_idx =
         blk_row * (block_size_wide[plane_bsize] >> MI_SIZE_LOG2) + blk_col;
     TxfmSearchInfo *txfm_info = &x->txfm_search_info;
-    set_blk_skip(txfm_info->blk_skip, plane, blk_idx, 0);
+    set_blk_skip(txfm_info->blk_skip[plane], blk_idx, 0);
 
     int64_t rd;
     if (is_inter) {
@@ -5296,7 +5296,7 @@
            sizeof(mbmi->tx_partition_type));
 #endif  // CONFIG_NEW_TX_PARTITION
     for (int i = 0; i < xd->height * xd->width; ++i)
-      set_blk_skip(x->txfm_search_info.blk_skip, 0, i, rd_stats_y->skip_txfm);
+      set_blk_skip(x->txfm_search_info.blk_skip[0], i, rd_stats_y->skip_txfm);
   }
 
   if (rd_stats_y->rate == INT_MAX) return 0;