Add an experiment to disable lpf on tile boundaries

This commit adds a new experiment to allow disabling of loop filtering
on tile boundaries. It is implemented by adding a syntax field
"loopfilter_across_tiles_enabled" into the uncompressed frame header. 
If it is set to 0, decoder and encoder will disables loop filtering for
block edges that are also tile boundaries.

Change-Id: Ib80bfd82d49c74f1ba46ae18ceedb30704ac8aa5
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 687df65..29d0134 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -277,6 +277,22 @@
    */
   AV1E_SET_TILE_ROWS,
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  /*!\brief Codec control function to set loop_filter_across_tiles_enabled.
+   *
+   * In encoding and decoding, AV1 allows disabling loop filter across tile
+   * boundary The parameter for this control describes the value of this flag,
+   * which has a valid range [0, 1]:
+   *            0 = disable loop filter across tile boundary
+   *            1 = enable loop filter across tile boundary
+   *
+   * By default, the value is 0, i.e. disable loop filter across tile boundary.
+   *
+   * Supported in codecs: AV1
+   */
+  AV1E_SET_TILE_LOOPFILTER,
+#endif
+
   /*!\brief Codec control function to enable frame parallel decoding feature.
    *
    * AV1 has a bitstream feature to reduce decoding dependency between frames
@@ -568,6 +584,10 @@
 #define AOM_CTRL_AV1E_SET_TILE_COLUMNS
 AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, int)
 #define AOM_CTRL_AV1E_SET_TILE_ROWS
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+AOM_CTRL_USE_TYPE(AV1E_SET_TILE_LOOPFILTER, int)
+#define AOM_CTRL_AV1E_SET_TILE_LOOPFILTER
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 
 AOM_CTRL_USE_TYPE(AOME_GET_LAST_QUANTIZER, int *)
 #define AOM_CTRL_AOME_GET_LAST_QUANTIZER
diff --git a/aomenc.c b/aomenc.c
index bf26531..0fe5338 100644
--- a/aomenc.c
+++ b/aomenc.c
@@ -376,6 +376,10 @@
 static const arg_def_t tile_rows =
     ARG_DEF(NULL, "tile-rows", 1,
             "Number of tile rows to use, log2 (set to 0 while threads > 1)");
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+static const arg_def_t tile_loopfilter = ARG_DEF(
+    NULL, "tile-loopfilter", 1, "Enable loop filter across tile boundary");
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 static const arg_def_t lossless =
     ARG_DEF(NULL, "lossless", 1, "Lossless mode (0: false (default), 1: true)");
 #if CONFIG_AOM_QM
@@ -468,6 +472,9 @@
                                        &static_thresh,
                                        &tile_cols,
                                        &tile_rows,
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+                                       &tile_loopfilter,
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
                                        &arnr_maxframes,
                                        &arnr_strength,
                                        &tune_ssim,
@@ -507,6 +514,9 @@
                                         AOME_SET_STATIC_THRESHOLD,
                                         AV1E_SET_TILE_COLUMNS,
                                         AV1E_SET_TILE_ROWS,
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+                                        AV1E_SET_TILE_LOOPFILTER,
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
                                         AOME_SET_ARNR_MAXFRAMES,
                                         AOME_SET_ARNR_STRENGTH,
                                         AOME_SET_TUNING,
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index c3abf2d..1286dda 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -34,6 +34,9 @@
   unsigned int static_thresh;
   unsigned int tile_columns;
   unsigned int tile_rows;
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  unsigned int loop_filter_across_tiles_enabled;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
   unsigned int arnr_max_frames;
   unsigned int arnr_strength;
   unsigned int min_gf_interval;
@@ -80,7 +83,10 @@
 #else
   0,  // tile_columns
   0,  // tile_rows
-#endif            // CONFIG_EXT_TILE
+#endif  // CONFIG_EXT_TILE
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  0,              // loop_filter_across_tiles_enabled
+#endif            // CONFIG_DEBLOCKING_ACROSS_TILES
   7,              // arnr_max_frames
   5,              // arnr_strength
   0,              // min_gf_interval; 0 -> default decision
@@ -250,6 +256,9 @@
   RANGE_CHECK_HI(extra_cfg, tile_columns, 6);
   RANGE_CHECK_HI(extra_cfg, tile_rows, 2);
 #endif  // CONFIG_EXT_TILE
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_enabled, 1);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
   RANGE_CHECK_HI(extra_cfg, sharpness, 7);
   RANGE_CHECK_HI(extra_cfg, arnr_max_frames, 15);
   RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
@@ -483,6 +492,11 @@
   oxcf->tile_rows = extra_cfg->tile_rows;
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  oxcf->loop_filter_across_tiles_enabled =
+      extra_cfg->loop_filter_across_tiles_enabled;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
   oxcf->error_resilient_mode = cfg->g_error_resilient;
   oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
 
@@ -645,6 +659,16 @@
   return update_extra_cfg(ctx, &extra_cfg);
 }
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+static aom_codec_err_t ctrl_set_tile_loopfilter(aom_codec_alg_priv_t *ctx,
+                                                va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.loop_filter_across_tiles_enabled =
+      CAST(AV1E_SET_TILE_LOOPFILTER, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
 static aom_codec_err_t ctrl_set_arnr_max_frames(aom_codec_alg_priv_t *ctx,
                                                 va_list args) {
   struct av1_extracfg extra_cfg = ctx->extra_cfg;
@@ -1329,6 +1353,9 @@
   { AOME_SET_STATIC_THRESHOLD, ctrl_set_static_thresh },
   { AV1E_SET_TILE_COLUMNS, ctrl_set_tile_columns },
   { AV1E_SET_TILE_ROWS, ctrl_set_tile_rows },
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  { AV1E_SET_TILE_LOOPFILTER, ctrl_set_tile_loopfilter },
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
   { AOME_SET_ARNR_MAXFRAMES, ctrl_set_arnr_max_frames },
   { AOME_SET_ARNR_STRENGTH, ctrl_set_arnr_strength },
   { AOME_SET_TUNING, ctrl_set_tuning },
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 9fd5510..859986a 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -350,6 +350,9 @@
   int num_proj_ref[2];
   WarpedMotionParams wm_params[2];
 #endif  // CONFIG_WARPED_MOTION
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  TILE_BOUNDARY_TYPE tile_boundary_info;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 } MB_MODE_INFO;
 
 typedef struct MODE_INFO {
diff --git a/av1/common/enums.h b/av1/common/enums.h
index c2e9329..6889935 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -222,6 +222,15 @@
   TX_TYPES,
 } TX_TYPE;
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+typedef enum {
+  TILE_LEFT_BOUNDARY = 1,
+  TILE_RIGHT_BOUNDARY = 2,
+  TILE_ABOVE_BOUNDARY = 4,
+  TILE_BOTTOM_BOUNDARY = 8,
+} TILE_BOUNDARY_TYPE;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
 #if CONFIG_EXT_TX
 #define EXT_TX_SIZES 4       // number of sizes that use extended transforms
 #define EXT_TX_SETS_INTER 4  // Sets of transform selections for INTER
diff --git a/av1/common/loopfilter.c b/av1/common/loopfilter.c
index 5821c75..16c3763 100644
--- a/av1/common/loopfilter.c
+++ b/av1/common/loopfilter.c
@@ -884,6 +884,34 @@
     *int_4x4_y |= (size_mask[block_size] & 0xffffffffffffffffULL) << shift_y;
 }
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+// This function update the bit masks for the entire 64x64 region represented
+// by mi_row, mi_col. In case one of the edge is a tile boundary, loop filtering
+// for that edge is disabled. This function only check the tile boundary info
+// for the top left corner mi to determine the boundary information for the
+// top and left edge of the whole super block
+static void update_tile_boundary_filter_mask(AV1_COMMON *const cm,
+                                             const int mi_row, const int mi_col,
+                                             LOOP_FILTER_MASK *lfm) {
+  int i;
+  MODE_INFO *const mi = cm->mi + mi_row * cm->mi_stride + mi_col;
+
+  if (mi->mbmi.tile_boundary_info & TILE_LEFT_BOUNDARY) {
+    for (i = 0; i <= TX_32X32; i++) {
+      lfm->left_y[i] &= 0xfefefefefefefefeULL;
+      lfm->left_uv[i] &= 0xeeee;
+    }
+  }
+
+  if (mi->mbmi.tile_boundary_info & TILE_ABOVE_BOUNDARY) {
+    for (i = 0; i <= TX_32X32; i++) {
+      lfm->above_y[i] &= 0xffffffffffffff00ULL;
+      lfm->above_uv[i] &= 0xfff0;
+    }
+  }
+}
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
 // This function sets up the bit masks for the entire 64x64 region represented
 // by mi_row, mi_col.
 // TODO(JBB): This function only works for yv12.
@@ -1169,6 +1197,12 @@
     }
   }
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  if (av1_disable_loopfilter_on_tile_boundary(cm)) {
+    update_tile_boundary_filter_mask(cm, mi_row, mi_col, lfm);
+  }
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
   // Assert if we try to apply 2 different loop filters at the same position.
   assert(!(lfm->left_y[TX_16X16] & lfm->left_y[TX_8X8]));
   assert(!(lfm->left_y[TX_16X16] & lfm->left_y[TX_4X4]));
@@ -1410,8 +1444,15 @@
       }
     }
 
-    // Disable filtering on the leftmost column
+    // Disable filtering on the leftmost column or tile boundary
     border_mask = ~(mi_col == 0);
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+    if (av1_disable_loopfilter_on_tile_boundary(cm) &&
+        ((mib[0]->mbmi.tile_boundary_info & TILE_LEFT_BOUNDARY) != 0)) {
+      border_mask = 0xfffffffe;
+    }
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
 #if CONFIG_AOM_HIGHBITDEPTH
     if (cm->use_highbitdepth) {
       highbd_filter_selectively_vert(
@@ -1602,10 +1643,21 @@
     unsigned int mask_8x8_r;
     unsigned int mask_4x4_r;
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+    // Disable filtering on the abovemost row or tile boundary
+    const MODE_INFO *mi = cm->mi + (mi_row + r) * cm->mi_stride;
+    if ((av1_disable_loopfilter_on_tile_boundary(cm) &&
+         (mi->mbmi.tile_boundary_info & TILE_ABOVE_BOUNDARY)) ||
+        (mi_row + idx_r == 0)) {
+      mask_16x16_r = 0;
+      mask_8x8_r = 0;
+      mask_4x4_r = 0;
+#else
     if (mi_row + idx_r == 0) {
       mask_16x16_r = 0;
       mask_8x8_r = 0;
       mask_4x4_r = 0;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
     } else {
       mask_16x16_r = mask_16x16[r];
       mask_8x8_r = mask_8x8[r];
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 2c9505c..fcf2694 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -363,6 +363,10 @@
   int tile_cols, tile_rows;
   int tile_width, tile_height;  // In MI units
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  int loop_filter_across_tiles_enabled;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
   int byte_alignment;
   int skip_loop_filter;
 
diff --git a/av1/common/tile_common.c b/av1/common/tile_common.c
index 2c0e5c6..62ceb12 100644
--- a/av1/common/tile_common.c
+++ b/av1/common/tile_common.c
@@ -59,3 +59,29 @@
   assert(*min_log2_tile_cols <= *max_log2_tile_cols);
 }
 #endif  // !CONFIG_EXT_TILE
+
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+void av1_update_tile_boundary_info(const struct AV1Common *cm,
+                                   const TileInfo *const tile_info, int mi_row,
+                                   int mi_col) {
+  int row, col;
+  for (row = mi_row; row < (mi_row + cm->mib_size); row++)
+    for (col = mi_col; col < (mi_col + cm->mib_size); col++) {
+      MODE_INFO *const mi = cm->mi + row * cm->mi_stride + col;
+      mi->mbmi.tile_boundary_info = 0;
+      if (row == tile_info->mi_row_start)
+        mi->mbmi.tile_boundary_info |= TILE_ABOVE_BOUNDARY;
+      if (col == tile_info->mi_col_start)
+        mi->mbmi.tile_boundary_info |= TILE_LEFT_BOUNDARY;
+      if ((row + 1) >= tile_info->mi_row_end)
+        mi->mbmi.tile_boundary_info |= TILE_BOTTOM_BOUNDARY;
+      if ((col + 1) >= tile_info->mi_col_end)
+        mi->mbmi.tile_boundary_info |= TILE_RIGHT_BOUNDARY;
+    }
+}
+
+int av1_disable_loopfilter_on_tile_boundary(const struct AV1Common *cm) {
+  return (!cm->loop_filter_across_tiles_enabled &&
+          (cm->tile_cols * cm->tile_rows > 1));
+}
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
diff --git a/av1/common/tile_common.h b/av1/common/tile_common.h
index 2e83820..a5023a7 100644
--- a/av1/common/tile_common.h
+++ b/av1/common/tile_common.h
@@ -38,6 +38,13 @@
 void av1_get_tile_n_bits(const int mi_cols, int *min_log2_tile_cols,
                          int *max_log2_tile_cols);
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+void av1_update_tile_boundary_info(const struct AV1Common *cm,
+                                   const TileInfo *const tile_info, int mi_row,
+                                   int mi_col);
+int av1_disable_loopfilter_on_tile_boundary(const struct AV1Common *cm);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 3fccb0d..a2ae3b3 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2764,6 +2764,10 @@
     cm->tile_height = aom_rb_read_literal(rb, 6) + 1;
   }
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  cm->loop_filter_across_tiles_enabled = aom_rb_read_bit(rb);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
   cm->tile_width <<= cm->mib_size_log2;
   cm->tile_height <<= cm->mib_size_log2;
 
@@ -2799,6 +2803,10 @@
   cm->log2_tile_rows = aom_rb_read_bit(rb);
   if (cm->log2_tile_rows) cm->log2_tile_rows += aom_rb_read_bit(rb);
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  cm->loop_filter_across_tiles_enabled = aom_rb_read_bit(rb);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
   cm->tile_cols = 1 << cm->log2_tile_cols;
   cm->tile_rows = 1 << cm->log2_tile_rows;
 
@@ -3264,6 +3272,12 @@
 
         for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end;
              mi_col += cm->mib_size) {
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+          if (av1_disable_loopfilter_on_tile_boundary(cm)) {
+            av1_update_tile_boundary_info(cm, &tile_info, mi_row, mi_col);
+          }
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
+
           decode_partition(pbi, &td->xd,
 #if CONFIG_SUPERTX
                            0,
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index d721e53..0cb3bf1 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3382,6 +3382,10 @@
   aom_wb_write_bit(wb, cm->log2_tile_rows != 0);
   if (cm->log2_tile_rows != 0) aom_wb_write_bit(wb, cm->log2_tile_rows != 1);
 #endif  // CONFIG_EXT_TILE
+
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  aom_wb_write_bit(wb, cm->loop_filter_across_tiles_enabled);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 }
 
 static int get_refresh_mask(AV1_COMP *cpi) {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 01fe0b7..beb9126 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4380,6 +4380,11 @@
     MODE_INFO **mi = cm->mi_grid_visible + idx_str;
     PC_TREE *const pc_root = td->pc_root[cm->mib_size_log2 - MIN_MIB_SIZE_LOG2];
 
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+    if (av1_disable_loopfilter_on_tile_boundary(cm)) {
+      av1_update_tile_boundary_info(cm, tile_info, mi_row, mi_col);
+    }
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
     if (sf->adaptive_pred_interp_filter) {
       for (i = 0; i < leaf_nodes; ++i)
         td->leaf_tree[i].pred_interp_filter = SWITCHABLE;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 0ff8871..e9e7eb3 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -863,6 +863,11 @@
   cm->tile_width = ALIGN_POWER_OF_TWO(cm->tile_width, MAX_MIB_SIZE_LOG2);
   cm->tile_height = ALIGN_POWER_OF_TWO(cm->tile_height, MAX_MIB_SIZE_LOG2);
 #endif  // CONFIG_EXT_TILE
+
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  cm->loop_filter_across_tiles_enabled =
+      cpi->oxcf.loop_filter_across_tiles_enabled;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 }
 
 static void update_frame_size(AV1_COMP *cpi) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index ca5918a..e149bfb 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -238,6 +238,9 @@
 
   int tile_columns;
   int tile_rows;
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+  int loop_filter_across_tiles_enabled;
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
 
   int max_threads;
 
diff --git a/configure b/configure
index 6f6b6a6..1bc70ce 100755
--- a/configure
+++ b/configure
@@ -288,6 +288,7 @@
     adapt_scan
     filter_7bit
     parallel_deblocking
+    deblocking_across_tiles
     tile_groups
     ec_adapt
     rd_debug
diff --git a/test/ethread_test.cc b/test/ethread_test.cc
index 68ae42e..24d670d 100644
--- a/test/ethread_test.cc
+++ b/test/ethread_test.cc
@@ -83,6 +83,9 @@
       encoder->Control(AV1E_SET_TILE_COLUMNS, 2);
       encoder->Control(AV1E_SET_TILE_ROWS, 0);
 #endif  // CONFIG_AV1 && CONFIG_EXT_TILE
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+      encoder->Control(AV1E_SET_TILE_LOOPFILTER, 0);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
       encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
       if (encoding_mode_ != ::libaom_test::kRealTime) {
         encoder->Control(AOME_SET_ENABLEAUTOALTREF, 1);
diff --git a/test/superframe_test.cc b/test/superframe_test.cc
index d8eba75..843c8a6 100644
--- a/test/superframe_test.cc
+++ b/test/superframe_test.cc
@@ -52,6 +52,9 @@
       encoder->Control(AOME_SET_CPUUSED, 2);
       encoder->Control(AV1E_SET_TILE_COLUMNS, n_tile_cols_);
       encoder->Control(AV1E_SET_TILE_ROWS, n_tile_rows_);
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+      encoder->Control(AV1E_SET_TILE_LOOPFILTER, 0);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
     }
   }
 
diff --git a/test/tile_independence_test.cc b/test/tile_independence_test.cc
index 57f4a60..5f0e5ad 100644
--- a/test/tile_independence_test.cc
+++ b/test/tile_independence_test.cc
@@ -62,6 +62,9 @@
     if (video->frame() == 1) {
       encoder->Control(AV1E_SET_TILE_COLUMNS, n_tile_cols_);
       encoder->Control(AV1E_SET_TILE_ROWS, n_tile_rows_);
+#if CONFIG_DEBLOCKING_ACROSS_TILES
+      encoder->Control(AV1E_SET_TILE_LOOPFILTER, 0);
+#endif  // CONFIG_DEBLOCKING_ACROSS_TILES
       SetCpuUsed(encoder);
     }
   }