From f58f111fb3e36dfc395196f8dc8b16d69d6261c7 Mon Sep 17 00:00:00 2001
From: Dominic Symes <dominic.symes@arm.com>
Date: Mon, 25 Sep 2017 12:47:40 +0200
Subject: [PATCH] MAX_TILE experiment: add explicit tiles

This patch is designed to complete the CONFIG_MAX_TILE experiment.
It adds the following features:
- Explicit tiles of same width can be signalled with command line --tile_width
- Explicit tiles of same hieght can be signalled with command line --tile_height
- max_tile now works with the depenedent horizontal tiles experiment
- additional checking added to ensure maximum number of rows/columns <= 64
- one fix to the tile group code for when the number of tiles is not a power of two

Change-Id: I749a68fdb3dcdd8d1ced2b3558f3817e4b832c06
---
 aom/aomcx.h               | 25 +++++++++++++++++++++++++
 aomenc.c                  | 14 ++++++++++++++
 av1/av1_cx_iface.c        | 37 +++++++++++++++++++++++++++++++++++--
 av1/common/onyxc_int.h    |  3 +++
 av1/common/tile_common.c  | 28 +++++++++++++++++++++++-----
 av1/decoder/decodeframe.c |  8 ++++----
 av1/encoder/bitstream.c   |  4 ++--
 av1/encoder/encoder.c     | 28 ++++++++++++++++++++++++----
 av1/encoder/encoder.h     |  4 ++++
 9 files changed, 134 insertions(+), 17 deletions(-)

diff --git a/aom/aomcx.h b/aom/aomcx.h
index 5db659a16c..cc22b329af 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -492,6 +492,26 @@ enum aome_enc_control_id {
    */
   AV1E_SET_MTU,
 
+  /*!\brief Codec control function to set tile_width.
+   *
+   * In encoding this sets expilcit tiles of the given tile width
+   *
+   * By default, the value is 0 and explicit tiles are disabled.
+   *
+   * Experiment: MAX_TILE
+   */
+  AV1E_SET_TILE_WIDTH,
+
+  /*!\brief Codec control function to set tile_height.
+   *
+   * In encoding this sets expilcit tiles of the given tile height
+   *
+   * By default, the value is 0 and explicit tiles are disabled.
+   *
+   * Experiment: MAX_TILE
+   */
+  AV1E_SET_TILE_HEIGHT,
+
   /*!\brief Codec control function to set dependent_horz_tiles.
   *
   * In encoding and decoding, AV1 allows enabling dependent horizontal tile
@@ -688,6 +708,11 @@ AOM_CTRL_USE_TYPE(AV1E_SET_TILE_COLUMNS, int)
 AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, int)
 #define AOM_CTRL_AV1E_SET_TILE_ROWS
 
+AOM_CTRL_USE_TYPE(AV1E_SET_TILE_WIDTH, int)
+#define AOM_CTRL_AV1E_SET_TILE_WIDTH
+AOM_CTRL_USE_TYPE(AV1E_SET_TILE_HEIGHT, int)
+#define AOM_CTRL_AV1E_SET_TILE_HEIGHT
+
 AOM_CTRL_USE_TYPE(AV1E_SET_TILE_DEPENDENT_ROWS, int)
 #define AOM_CTRL_AV1E_SET_TILE_DEPENDENT_ROWS
 
diff --git a/aomenc.c b/aomenc.c
index fd334faa02..d3edb122a1 100644
--- a/aomenc.c
+++ b/aomenc.c
@@ -412,6 +412,12 @@ static const arg_def_t tile_cols =
 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_MAX_TILE
+static const arg_def_t tile_width =
+    ARG_DEF(NULL, "tile-width", 1, "Width of each tile");
+static const arg_def_t tile_height =
+    ARG_DEF(NULL, "tile-height", 1, "Height of each tile");
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
 static const arg_def_t tile_dependent_rows =
     ARG_DEF(NULL, "tile-dependent-rows", 1, "Enable dependent Tile rows");
@@ -547,6 +553,10 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
 #endif  // CONFIG_EXT_TILE
                                        &tile_cols,
                                        &tile_rows,
+#if CONFIG_MAX_TILE
+                                       &tile_width,
+                                       &tile_height,
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
                                        &tile_dependent_rows,
 #endif
@@ -604,6 +614,10 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
 #endif  // CONFIG_EXT_TILE
                                         AV1E_SET_TILE_COLUMNS,
                                         AV1E_SET_TILE_ROWS,
+#if CONFIG_MAX_TILE
+                                        AV1E_SET_TILE_WIDTH,
+                                        AV1E_SET_TILE_HEIGHT,
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
                                         AV1E_SET_TILE_DEPENDENT_ROWS,
 #endif
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 1a946ebf72..ec35ef2594 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -34,8 +34,12 @@ struct av1_extracfg {
   unsigned int noise_sensitivity;
   unsigned int sharpness;
   unsigned int static_thresh;
-  unsigned int tile_columns;
-  unsigned int tile_rows;
+  unsigned int tile_columns;  // log2 number of tile columns
+  unsigned int tile_rows;     // log2 number of tile rows
+#if CONFIG_MAX_TILE
+  unsigned int tile_width;   // tile width in superblocks  (if non zero)
+  unsigned int tile_height;  // tile height in superblocks (if non zero)
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
   unsigned int dependent_horz_tiles;
 #endif
@@ -101,6 +105,10 @@ static struct av1_extracfg default_extra_cfg = {
   0,    // static_thresh
   0,    // tile_columns
   0,    // tile_rows
+#if CONFIG_MAX_TILE
+  0,  // tile_width
+  0,  // tile_height
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
   0,  // Dependent Horizontal tiles
 #endif
@@ -308,6 +316,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
 #if CONFIG_MAX_TILE
     RANGE_CHECK_HI(extra_cfg, tile_columns, 6);
     RANGE_CHECK_HI(extra_cfg, tile_rows, 6);
+    RANGE_CHECK_HI(extra_cfg, tile_width, MAX_TILE_WIDTH_SB);
 #else   // CONFIG_MAX_TILE
   RANGE_CHECK_HI(extra_cfg, tile_columns, 6);
   RANGE_CHECK_HI(extra_cfg, tile_rows, 2);
@@ -629,6 +638,10 @@ static aom_codec_err_t set_encoder_config(
   }
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_MAX_TILE
+  oxcf->tile_width = extra_cfg->tile_width;
+  oxcf->tile_height = extra_cfg->tile_height;
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
   oxcf->dependent_horz_tiles =
 #if CONFIG_EXT_TILE
@@ -773,6 +786,22 @@ static aom_codec_err_t ctrl_set_tile_rows(aom_codec_alg_priv_t *ctx,
   extra_cfg.tile_rows = CAST(AV1E_SET_TILE_ROWS, args);
   return update_extra_cfg(ctx, &extra_cfg);
 }
+
+#if CONFIG_MAX_TILE
+static aom_codec_err_t ctrl_set_tile_width(aom_codec_alg_priv_t *ctx,
+                                           va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.tile_width = CAST(AV1E_SET_TILE_WIDTH, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+
+static aom_codec_err_t ctrl_set_tile_height(aom_codec_alg_priv_t *ctx,
+                                            va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.tile_height = CAST(AV1E_SET_TILE_HEIGHT, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
 static aom_codec_err_t ctrl_set_tile_dependent_rows(aom_codec_alg_priv_t *ctx,
                                                     va_list args) {
@@ -1551,6 +1580,10 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
   { 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_MAX_TILE
+  { AV1E_SET_TILE_WIDTH, ctrl_set_tile_width },
+  { AV1E_SET_TILE_HEIGHT, ctrl_set_tile_height },
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
   { AV1E_SET_TILE_DEPENDENT_ROWS, ctrl_set_tile_dependent_rows },
 #endif
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 795100e4aa..35b1b23781 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -431,6 +431,9 @@ typedef struct AV1Common {
   int log2_tile_rows;                        // only valid for uniform tiles
   int tile_col_start_sb[MAX_TILE_COLS + 1];  // valid for 0 <= i <= tile_cols
   int tile_row_start_sb[MAX_TILE_ROWS + 1];  // valid for 0 <= i <= tile_rows
+#if CONFIG_DEPENDENT_HORZTILES
+  int tile_row_independent[MAX_TILE_ROWS];  // valid for 0 <= i <  tile_rows
+#endif
 #else
   int log2_tile_cols, log2_tile_rows;  // Used in non-large_scale_tile_coding.
   int tile_width, tile_height;         // In MI units
diff --git a/av1/common/tile_common.c b/av1/common/tile_common.c
index f73c39cc3f..c3dedbf858 100644
--- a/av1/common/tile_common.c
+++ b/av1/common/tile_common.c
@@ -26,6 +26,11 @@ void av1_tile_set_tg_boundary(TileInfo *tile, const AV1_COMMON *const cm,
     tile->tg_horz_boundary =
         (row == cm->tile_group_start_row[row][col] ? 1 : 0);
   }
+#if CONFIG_MAX_TILE
+  if (cm->tile_row_independent[row]) {
+    tile->tg_horz_boundary = 1;  // this tile row is independent
+  }
+#endif
 }
 #endif
 void av1_tile_init(TileInfo *tile, const AV1_COMMON *cm, int row, int col) {
@@ -53,8 +58,8 @@ void av1_get_tile_limits(AV1_COMMON *const cm) {
   int sb_rows = mi_rows >> MAX_MIB_SIZE_LOG2;
 
   cm->min_log2_tile_cols = tile_log2(MAX_TILE_WIDTH_SB, sb_cols);
-  cm->max_log2_tile_cols = tile_log2(1, sb_cols);
-  cm->max_log2_tile_rows = tile_log2(1, sb_rows);
+  cm->max_log2_tile_cols = tile_log2(1, AOMMIN(sb_cols, MAX_TILE_COLS));
+  cm->max_log2_tile_rows = tile_log2(1, AOMMIN(sb_rows, MAX_TILE_ROWS));
   cm->min_log2_tiles = tile_log2(MAX_TILE_AREA_SB, sb_cols * sb_rows);
   cm->min_log2_tiles = AOMMAX(cm->min_log2_tiles, cm->min_log2_tile_cols);
   // TODO(dominic.symes@arm.com):
@@ -78,11 +83,13 @@ void av1_calculate_tile_cols(AV1_COMMON *const cm) {
       start_sb += size_sb;
     }
     cm->tile_cols = i;
-    cm->tile_col_start_sb[i] = start_sb;
+    cm->tile_col_start_sb[i] = sb_cols;
     cm->min_log2_tile_rows = AOMMAX(cm->min_log2_tiles - cm->log2_tile_cols, 0);
+    cm->max_tile_height_sb = sb_rows >> cm->min_log2_tile_rows;
   } else {
     int max_tile_area_sb = (sb_rows * sb_cols);
     int max_tile_width_sb = 0;
+    cm->log2_tile_cols = tile_log2(1, cm->tile_cols);
     for (i = 0; i < cm->tile_cols; i++) {
       int size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i];
       max_tile_width_sb = AOMMAX(max_tile_width_sb, size_sb);
@@ -108,10 +115,21 @@ void av1_calculate_tile_rows(AV1_COMMON *const cm) {
       start_sb += size_sb;
     }
     cm->tile_rows = i;
-    cm->tile_row_start_sb[i] = start_sb;
+    cm->tile_row_start_sb[i] = sb_rows;
   } else {
-    // No action
+    cm->log2_tile_rows = tile_log2(1, cm->tile_rows);
+  }
+
+#if CONFIG_DEPENDENT_HORZTILES
+  // Record which tile rows must be indpendent for parallelism
+  for (i = 0, start_sb = 0; i < cm->tile_rows; i++) {
+    cm->tile_row_independent[i] = 0;
+    if (cm->tile_row_start_sb[i + 1] - start_sb > cm->max_tile_height_sb) {
+      cm->tile_row_independent[i] = 1;
+      start_sb = cm->tile_row_start_sb[i];
+    }
   }
+#endif
 }
 
 void av1_tile_set_row(TileInfo *tile, const AV1_COMMON *cm, int row) {
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index c03dff9770..471625818e 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -3246,14 +3246,14 @@ static void read_tile_info_max_tile(AV1_COMMON *const cm,
       cm->log2_tile_cols++;
     }
   } else {
-    for (i = 0, start_sb = 0; width_sb > 0; i++) {
+    for (i = 0, start_sb = 0; width_sb > 0 && i < MAX_TILE_COLS; i++) {
       size_sb = 1 + rb_read_uniform(rb, AOMMIN(width_sb, MAX_TILE_WIDTH_SB));
       cm->tile_col_start_sb[i] = start_sb;
       start_sb += size_sb;
       width_sb -= size_sb;
     }
     cm->tile_cols = i;
-    cm->tile_col_start_sb[i] = start_sb;
+    cm->tile_col_start_sb[i] = start_sb + width_sb;
   }
   av1_calculate_tile_cols(cm);
 
@@ -3267,7 +3267,7 @@ static void read_tile_info_max_tile(AV1_COMMON *const cm,
       cm->log2_tile_rows++;
     }
   } else {
-    for (i = 0, start_sb = 0; height_sb > 0; i++) {
+    for (i = 0, start_sb = 0; height_sb > 0 && i < MAX_TILE_ROWS; i++) {
       size_sb =
           1 + rb_read_uniform(rb, AOMMIN(height_sb, cm->max_tile_height_sb));
       cm->tile_row_start_sb[i] = start_sb;
@@ -3275,7 +3275,7 @@ static void read_tile_info_max_tile(AV1_COMMON *const cm,
       height_sb -= size_sb;
     }
     cm->tile_rows = i;
-    cm->tile_row_start_sb[i] = start_sb;
+    cm->tile_row_start_sb[i] = start_sb + height_sb;
   }
   av1_calculate_tile_rows(cm);
 }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index ebf2e68f0e..1fe6cbf801 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -4180,8 +4180,8 @@ static uint32_t write_tiles(AV1_COMP *const cpi, uint8_t *const dst,
     }
     // Write the final tile group size
     if (n_log2_tiles) {
-      aom_wb_overwrite_literal(&tg_params_wb, (1 << n_log2_tiles) - tile_count,
-                               n_log2_tiles);
+      aom_wb_overwrite_literal(
+          &tg_params_wb, (tile_cols * tile_rows) - tile_count, n_log2_tiles);
       aom_wb_overwrite_literal(&tg_params_wb, tile_count - 1, n_log2_tiles);
     }
     // Remux if possible. TODO (Thomas Davies): do this for more than one tile
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index fa4093e079..9787097708 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -866,16 +866,26 @@ void av1_new_framerate(AV1_COMP *cpi, double framerate) {
 
 static void set_tile_info_max_tile(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
+  int i, start_sb;
 
   av1_get_tile_limits(cm);
-  // Configure uniform spaced tiles
-  // (API is not yet upgraded to general tiles)
-  cm->uniform_tile_spacing_flag = 1;
 
   // configure tile columns
-  if (cm->uniform_tile_spacing_flag) {
+  if (cpi->oxcf.tile_width == 0 || cpi->oxcf.tile_height == 0) {
+    cm->uniform_tile_spacing_flag = 1;
     cm->log2_tile_cols = AOMMAX(cpi->oxcf.tile_columns, cm->min_log2_tile_cols);
     cm->log2_tile_cols = AOMMIN(cm->log2_tile_cols, cm->max_log2_tile_cols);
+  } else {
+    int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2);
+    int sb_cols = mi_cols >> MAX_MIB_SIZE_LOG2;
+    int size_sb = AOMMIN(cpi->oxcf.tile_width, MAX_TILE_WIDTH_SB);
+    cm->uniform_tile_spacing_flag = 0;
+    for (i = 0, start_sb = 0; start_sb < sb_cols && i < MAX_TILE_COLS; i++) {
+      cm->tile_col_start_sb[i] = start_sb;
+      start_sb += size_sb;
+    }
+    cm->tile_cols = i;
+    cm->tile_col_start_sb[i] = sb_cols;
   }
   av1_calculate_tile_cols(cm);
 
@@ -883,6 +893,16 @@ static void set_tile_info_max_tile(AV1_COMP *cpi) {
   if (cm->uniform_tile_spacing_flag) {
     cm->log2_tile_rows = AOMMAX(cpi->oxcf.tile_rows, cm->min_log2_tile_rows);
     cm->log2_tile_rows = AOMMIN(cm->log2_tile_rows, cm->max_log2_tile_rows);
+  } else {
+    int mi_rows = ALIGN_POWER_OF_TWO(cm->mi_rows, MAX_MIB_SIZE_LOG2);
+    int sb_rows = mi_rows >> MAX_MIB_SIZE_LOG2;
+    int size_sb = AOMMIN(cpi->oxcf.tile_height, cm->max_tile_height_sb);
+    for (i = 0, start_sb = 0; start_sb < sb_rows && i < MAX_TILE_ROWS; i++) {
+      cm->tile_row_start_sb[i] = start_sb;
+      start_sb += size_sb;
+    }
+    cm->tile_rows = i;
+    cm->tile_row_start_sb[i] = sb_rows;
   }
   av1_calculate_tile_rows(cm);
 }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index df681fbee1..889d48af25 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -269,6 +269,10 @@ typedef struct AV1EncoderConfig {
 
   int tile_columns;
   int tile_rows;
+#if CONFIG_MAX_TILE
+  int tile_width;
+  int tile_height;
+#endif
 #if CONFIG_DEPENDENT_HORZTILES
   int dependent_horz_tiles;
 #endif
-- 
GitLab