add horizontal tile dependence support

Change-Id: I1050b69045407381d4626b65a0bf6f35957a66f4
diff --git a/aom/aomcx.h b/aom/aomcx.h
index ef9d6ca..9003dca 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -286,7 +286,6 @@
    * By default, the value is 0, i.e. one single row tile for entire image.
    */
   AV1E_SET_TILE_ROWS,
-
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   /*!\brief Codec control function to set loop_filter_across_tiles_enabled.
    *
@@ -482,6 +481,20 @@
    */
   AV1E_SET_MTU,
 
+  /*!\brief Codec control function to set dependent_horz_tiles.
+  *
+  * In encoding and decoding, AV1 allows enabling dependent horizontal tile
+  * The parameter for this control describes the value of this flag,
+  * which has a valid range [0, 1]:
+  *            0 = disable dependent horizontal tile
+  *            1 = enable dependent horizontal tile,
+  *
+  * By default, the value is 0, i.e. disable dependent horizontal tile.
+  *
+  * Supported in codecs: AV1
+  */
+  AV1E_SET_TILE_DEPENDENT_ROWS,
+
   /*!\brief Codec control function to set the number of symbols in an ANS data
    * window.
    *
@@ -606,6 +619,12 @@
 #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_DEPENDENT_HORZTILES
+AOM_CTRL_USE_TYPE(AV1E_SET_TILE_DEPENDENT_ROWS, int)
+#define AOM_CTRL_AV1E_SET_TILE_DEPENDENT_ROWS
+#endif
+
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
 AOM_CTRL_USE_TYPE(AV1E_SET_TILE_LOOPFILTER, int)
 #define AOM_CTRL_AV1E_SET_TILE_LOOPFILTER
diff --git a/aomenc.c b/aomenc.c
index bbbf5c1..e667348 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_DEPENDENT_HORZTILES
+static const arg_def_t tile_dependent_rows =
+    ARG_DEF(NULL, "tile-dependent-rows", 1, "Enable dependent Tile rows");
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
 static const arg_def_t tile_loopfilter = ARG_DEF(
     NULL, "tile-loopfilter", 1, "Enable loop filter across tile boundary");
@@ -476,6 +480,9 @@
                                        &static_thresh,
                                        &tile_cols,
                                        &tile_rows,
+#if CONFIG_DEPENDENT_HORZTILES
+                                       &tile_dependent_rows,
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
                                        &tile_loopfilter,
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -521,6 +528,9 @@
                                         AOME_SET_STATIC_THRESHOLD,
                                         AV1E_SET_TILE_COLUMNS,
                                         AV1E_SET_TILE_ROWS,
+#if CONFIG_DEPENDENT_HORZTILES
+                                        AV1E_SET_TILE_DEPENDENT_ROWS,
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
                                         AV1E_SET_TILE_LOOPFILTER,
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index a8f975b..ee5e2c5 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_DEPENDENT_HORZTILES
+  unsigned int dependent_horz_tiles;
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   unsigned int loop_filter_across_tiles_enabled;
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -90,6 +93,9 @@
   0,  // tile_columns
   0,  // tile_rows
 #endif  // CONFIG_EXT_TILE
+#if CONFIG_DEPENDENT_HORZTILES
+  0,  // Depdendent Horizontal tiles
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   1,              // loop_filter_across_tiles_enabled
 #endif            // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -268,6 +274,9 @@
   RANGE_CHECK_HI(extra_cfg, tile_columns, 6);
   RANGE_CHECK_HI(extra_cfg, tile_rows, 2);
 #endif  // CONFIG_EXT_TILE
+#if CONFIG_DEPENDENT_HORZTILES
+  RANGE_CHECK_HI(extra_cfg, dependent_horz_tiles, 1);
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   RANGE_CHECK_HI(extra_cfg, loop_filter_across_tiles_enabled, 1);
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -512,12 +521,13 @@
   oxcf->tile_columns = extra_cfg->tile_columns;
   oxcf->tile_rows = extra_cfg->tile_rows;
 #endif  // CONFIG_EXT_TILE
-
+#if CONFIG_DEPENDENT_HORZTILES
+  oxcf->dependent_horz_tiles = extra_cfg->dependent_horz_tiles;
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   oxcf->loop_filter_across_tiles_enabled =
       extra_cfg->loop_filter_across_tiles_enabled;
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
-
   oxcf->error_resilient_mode = cfg->g_error_resilient;
   oxcf->frame_parallel_decoding_mode = extra_cfg->frame_parallel_decoding_mode;
 
@@ -679,7 +689,14 @@
   extra_cfg.tile_rows = CAST(AV1E_SET_TILE_ROWS, args);
   return update_extra_cfg(ctx, &extra_cfg);
 }
-
+#if CONFIG_DEPENDENT_HORZTILES
+static aom_codec_err_t ctrl_set_tile_dependent_rows(aom_codec_alg_priv_t *ctx,
+                                                    va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.dependent_horz_tiles = CAST(AV1E_SET_TILE_DEPENDENT_ROWS, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
 static aom_codec_err_t ctrl_set_tile_loopfilter(aom_codec_alg_priv_t *ctx,
                                                 va_list args) {
@@ -1390,6 +1407,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_DEPENDENT_HORZTILES
+  { AV1E_SET_TILE_DEPENDENT_ROWS, ctrl_set_tile_dependent_rows },
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   { AV1E_SET_TILE_LOOPFILTER, ctrl_set_tile_loopfilter },
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 297cba0..f83f98d 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -191,7 +191,12 @@
 
     mi_pos.row = row_offset;
     mi_pos.col = i;
+#if CONFIG_DEPENDENT_HORZTILES
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                  &mi_pos)) {
+#else
     if (is_inside(tile, mi_col, mi_row, &mi_pos)) {
+#endif
       const MODE_INFO *const candidate_mi =
           xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
       const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
@@ -238,7 +243,12 @@
 
     mi_pos.row = i;
     mi_pos.col = col_offset;
+#if CONFIG_DEPENDENT_HORZTILES
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                  &mi_pos)) {
+#else
     if (is_inside(tile, mi_col, mi_row, &mi_pos)) {
+#endif
       const MODE_INFO *const candidate_mi =
           xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
       const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
@@ -271,8 +281,14 @@
   mi_pos.row = row_offset;
   mi_pos.col = col_offset;
 
+#if CONFIG_DEPENDENT_HORZTILES
+  if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                &mi_pos) &&
+      *refmv_count < MAX_REF_MV_STACK_SIZE) {
+#else
   if (is_inside(tile, mi_col, mi_row, &mi_pos) &&
       *refmv_count < MAX_REF_MV_STACK_SIZE) {
+#endif
     const MODE_INFO *const candidate_mi =
         xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col];
     const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
@@ -348,7 +364,13 @@
   mi_pos.row = blk_row;
   mi_pos.col = blk_col;
 
+#if CONFIG_DEPENDENT_HORZTILES
+  if (!is_inside(&xd->tile, mi_col, mi_row, cm->mi_rows,
+                 cm->dependent_horz_tiles, &mi_pos))
+    return coll_blk_count;
+#else
   if (!is_inside(&xd->tile, mi_col, mi_row, &mi_pos)) return coll_blk_count;
+#endif
 
   for (ref = 0; ref < 2; ++ref) {
     if (prev_frame_mvs->ref_frame[ref] == ref_frame) {
@@ -607,7 +629,12 @@
   // and we also need to keep a mode count.
   for (i = 0; i < 2; ++i) {
     const POSITION *const mv_ref = &mv_ref_search[i];
+#if CONFIG_DEPENDENT_HORZTILES
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                  mv_ref)) {
+#else
     if (is_inside(tile, mi_col, mi_row, mv_ref)) {
+#endif
       const MODE_INFO *const candidate_mi =
           xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
       const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
@@ -629,7 +656,12 @@
   // mode counts.
   for (; i < MVREF_NEIGHBOURS; ++i) {
     const POSITION *const mv_ref = &mv_ref_search[i];
+#if CONFIG_DEPENDENT_HORZTILES
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                  mv_ref)) {
+#else
     if (is_inside(tile, mi_col, mi_row, mv_ref)) {
+#endif
       const MB_MODE_INFO *const candidate =
           !xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]
               ? NULL
@@ -683,7 +715,12 @@
   if (different_ref_found) {
     for (i = 0; i < MVREF_NEIGHBOURS; ++i) {
       const POSITION *mv_ref = &mv_ref_search[i];
+#if CONFIG_DEPENDENT_HORZTILES
+      if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                    mv_ref)) {
+#else
       if (is_inside(tile, mi_col, mi_row, mv_ref)) {
+#endif
         const MB_MODE_INFO *const candidate =
             !xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride]
                 ? NULL
@@ -793,7 +830,12 @@
   // If the size < 8x8, we get the mv from the bmi substructure;
   for (i = 0; i < 2; ++i) {
     const POSITION *const mv_ref = &mv_ref_search[i];
+#if CONFIG_DEPENDENT_HORZTILES
+    if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm->dependent_horz_tiles,
+                  mv_ref)) {
+#else
     if (is_inside(tile, mi_col, mi_row, mv_ref)) {
+#endif
       const MODE_INFO *const candidate_mi =
           xd->mi[mv_ref->col + mv_ref->row * xd->mi_stride];
       const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index 930abaa..6b83097 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -345,6 +345,23 @@
 
 // Checks that the given mi_row, mi_col and search point
 // are inside the borders of the tile.
+#if CONFIG_DEPENDENT_HORZTILES
+static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
+                            int mi_rows, int dependent_horz_tile_flag,
+                            const POSITION *mi_pos) {
+  if (dependent_horz_tile_flag) {
+    return !(mi_row + mi_pos->row < 0 ||
+             mi_col + mi_pos->col < tile->mi_col_start ||
+             mi_row + mi_pos->row >= mi_rows ||
+             mi_col + mi_pos->col >= tile->mi_col_end);
+  } else {
+    return !(mi_row + mi_pos->row < tile->mi_row_start ||
+             mi_col + mi_pos->col < tile->mi_col_start ||
+             mi_row + mi_pos->row >= tile->mi_row_end ||
+             mi_col + mi_pos->col >= tile->mi_col_end);
+  }
+}
+#else
 static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
                             const POSITION *mi_pos) {
   return !(mi_row + mi_pos->row < tile->mi_row_start ||
@@ -352,6 +369,7 @@
            mi_row + mi_pos->row >= tile->mi_row_end ||
            mi_col + mi_pos->col >= tile->mi_col_end);
 }
+#endif
 
 static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
   if (!allow_hp) {
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 2e024e3..c1c2982 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -368,6 +368,9 @@
   int tile_cols, tile_rows;
   int tile_width, tile_height;  // In MI units
 
+#if CONFIG_DEPENDENT_HORZTILES
+  int dependent_horz_tiles;
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   int loop_filter_across_tiles_enabled;
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -580,6 +583,54 @@
   }
 }
 
+#if CONFIG_DEPENDENT_HORZTILES
+static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
+                                  int mi_row, int bh, int mi_col, int bw,
+                                  int mi_rows, int mi_cols,
+                                  int dependent_horz_tile_flag) {
+  xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
+  xd->mb_to_bottom_edge = ((mi_rows - bh - mi_row) * MI_SIZE) * 8;
+  xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
+  xd->mb_to_right_edge = ((mi_cols - bw - mi_col) * MI_SIZE) * 8;
+
+  if (dependent_horz_tile_flag) {
+    xd->up_available = (mi_row > 0);
+  } else {
+    // Are edges available for intra prediction?
+    xd->up_available = (mi_row > tile->mi_row_start);
+  }
+
+  xd->left_available = (mi_col > tile->mi_col_start);
+  if (xd->up_available) {
+    xd->above_mi = xd->mi[-xd->mi_stride];
+    // above_mi may be NULL in encoder's first pass.
+    xd->above_mbmi = xd->above_mi ? &xd->above_mi->mbmi : NULL;
+  } else {
+    xd->above_mi = NULL;
+    xd->above_mbmi = NULL;
+  }
+
+  if (xd->left_available) {
+    xd->left_mi = xd->mi[-1];
+    // left_mi may be NULL in encoder's first pass.
+    xd->left_mbmi = xd->left_mi ? &xd->left_mi->mbmi : NULL;
+  } else {
+    xd->left_mi = NULL;
+    xd->left_mbmi = NULL;
+  }
+
+  xd->n8_h = bh;
+  xd->n8_w = bw;
+#if CONFIG_REF_MV
+  xd->is_sec_rect = 0;
+  if (xd->n8_w < xd->n8_h)
+    if (mi_col & (xd->n8_h - 1)) xd->is_sec_rect = 1;
+
+  if (xd->n8_w > xd->n8_h)
+    if (mi_row & (xd->n8_w - 1)) xd->is_sec_rect = 1;
+#endif
+}
+#else
 static INLINE void set_mi_row_col(MACROBLOCKD *xd, const TileInfo *const tile,
                                   int mi_row, int bh, int mi_col, int bw,
                                   int mi_rows, int mi_cols) {
@@ -620,6 +671,7 @@
     if (mi_row & (xd->n8_w - 1)) xd->is_sec_rect = 1;
 #endif
 }
+#endif
 
 static INLINE const aom_prob *get_y_mode_probs(const AV1_COMMON *cm,
                                                const MODE_INFO *mi,
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 2823d1f..78df99c 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -641,9 +641,14 @@
   xd->max_tx_size = max_txsize_lookup[bsize];
 #endif
 
-  // Distance of Mb to the various image edges. These are specified to 8th pel
-  // as they are always compared to values that are in 1/8th pel units
+// Distance of Mb to the various image edges. These are specified to 8th pel
+// as they are always compared to values that are in 1/8th pel units
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
 
   av1_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), mi_row, mi_col);
   return &xd->mi[0]->mbmi;
@@ -664,8 +669,13 @@
   const int offset = mi_row_ori * cm->mi_stride + mi_col_ori;
   xd->mi = cm->mi_grid_visible + offset;
   xd->mi[0] = cm->mi + offset;
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row_pred, bh, mi_col_pred, bw, cm->mi_rows,
+                 cm->mi_cols, cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row_pred, bh, mi_col_pred, bw, cm->mi_rows,
                  cm->mi_cols);
+#endif
 
   xd->up_available = (mi_row_ori > tile->mi_row_start);
   xd->left_available = (mi_col_ori > tile->mi_col_start);
@@ -688,7 +698,12 @@
   for (y = 0; y < y_mis; ++y)
     for (x = !y; x < x_mis; ++x) xd->mi[y * cm->mi_stride + x] = xd->mi[0];
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
   return &xd->mi[0]->mbmi;
 }
 
@@ -704,7 +719,12 @@
 
   set_plane_n4(xd, bw, bh);
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
 
   av1_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), mi_row, mi_col);
 }
@@ -2173,8 +2193,14 @@
 
     xd->mi = cm->mi_grid_visible + offset;
     xd->mi[0] = cm->mi + offset;
+#if CONFIG_DEPENDENT_HORZTILES
+    set_mi_row_col(xd, tile, mi_row, mi_size_high[bsize], mi_col,
+                   mi_size_wide[bsize], cm->mi_rows, cm->mi_cols,
+                   cm->dependent_horz_tiles);
+#else
     set_mi_row_col(xd, tile, mi_row, mi_size_high[bsize], mi_col,
                    mi_size_wide[bsize], cm->mi_rows, cm->mi_cols);
+#endif
     set_skip_context(xd, mi_row, mi_col);
     skip = read_skip(cm, xd, xd->mi[0]->mbmi.segment_id_supertx, r);
     if (skip) {
@@ -2990,6 +3016,13 @@
     pbi->tile_col_size_bytes = aom_rb_read_literal(rb, 2) + 1;
     pbi->tile_size_bytes = aom_rb_read_literal(rb, 2) + 1;
   }
+
+#if CONFIG_DEPENDENT_HORZTILES
+  if (cm->tile_rows <= 1)
+    cm->dependent_horz_tiles = aom_rb_read_bit(rb);
+  else
+    cm->dependent_horz_tiles = 0;
+#endif
 #else
   int min_log2_tile_cols, max_log2_tile_cols, max_ones;
   av1_get_tile_n_bits(cm->mi_cols, &min_log2_tile_cols, &max_log2_tile_cols);
@@ -3006,7 +3039,12 @@
   // rows
   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_DEPENDENT_HORZTILES
+  if (cm->log2_tile_rows != 0)
+    cm->dependent_horz_tiles = aom_rb_read_bit(rb);
+  else
+    cm->dependent_horz_tiles = 0;
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   cm->loop_filter_across_tiles_enabled = aom_rb_read_bit(rb);
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
@@ -3479,7 +3517,14 @@
 
       av1_tile_set_col(&tile_info, cm, col);
 
+#if CONFIG_DEPENDENT_HORZTILES
+      if (!cm->dependent_horz_tiles || tile_row == 0) {
+        av1_zero_above_context(cm, tile_info.mi_col_start,
+                               tile_info.mi_col_end);
+      }
+#else
       av1_zero_above_context(cm, tile_info.mi_col_start, tile_info.mi_col_end);
+#endif
 
       for (mi_row = tile_info.mi_row_start; mi_row < tile_info.mi_row_end;
            mi_row += cm->mib_size) {
@@ -3490,7 +3535,6 @@
         for (mi_col = tile_info.mi_col_start; mi_col < tile_info.mi_col_end;
              mi_col += cm->mib_size) {
           av1_update_boundary_info(cm, &tile_info, mi_row, mi_col);
-
           decode_partition(pbi, &td->xd,
 #if CONFIG_SUPERTX
                            0,
@@ -3625,8 +3669,13 @@
 
   tile_data->error_info.setjmp = 1;
   tile_data->xd.error_info = &tile_data->error_info;
-
+#if CONFIG_DEPENDENT_HORZTILES
+  if (!cm->dependent_horz_tiles) {
+    av1_zero_above_context(&pbi->common, tile->mi_col_start, tile->mi_col_end);
+  }
+#else
   av1_zero_above_context(&pbi->common, tile->mi_col_start, tile->mi_col_end);
+#endif
 
   for (mi_row = tile->mi_row_start; mi_row < tile->mi_row_end;
        mi_row += cm->mib_size) {
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index af96f43..6a002d8 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1927,7 +1927,12 @@
 
   cpi->td.mb.mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col);
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
 
   if (frame_is_intra_only(cm)) {
     write_mb_modes_kf(cm, xd, xd->mi, w);
@@ -1998,10 +2003,15 @@
 
   bh = mi_size_high[m->mbmi.sb_type];
   bw = mi_size_wide[m->mbmi.sb_type];
-
   cpi->td.mb.mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col);
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
+
 #if CONFIG_PVQ
   mbmi = &m->mbmi;
   bsize = mbmi->sb_type;
@@ -2474,8 +2484,14 @@
 #if CONFIG_SUPERTX
   mbmi = &cm->mi_grid_visible[mi_offset]->mbmi;
   xd->mi = cm->mi_grid_visible + mi_offset;
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, mi_size_high[bsize], mi_col,
+                 mi_size_wide[bsize], cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, mi_size_high[bsize], mi_col,
                  mi_size_wide[bsize], cm->mi_rows, cm->mi_cols);
+#endif
   if (!supertx_enabled && !frame_is_intra_only(cm) &&
       partition != PARTITION_NONE && bsize <= MAX_SUPERTX_BLOCK_SIZE &&
       !xd->lossless[0]) {
@@ -2564,8 +2580,13 @@
     const int bsh = mi_size_high[bsize];
     xd->mi = cm->mi_grid_visible + mi_offset;
     supertx_size = mbmi->tx_size;
+#if CONFIG_DEPENDENT_HORZTILES
+    set_mi_row_col(xd, tile, mi_row, bsh, mi_col, bsw, cm->mi_rows, cm->mi_cols,
+                   cm->dependent_horz_tiles);
+#else
     set_mi_row_col(xd, tile, mi_row, bsh, mi_col, bsw, cm->mi_rows,
                    cm->mi_cols);
+#endif
 
     assert(IMPLIES(!cm->seg.enabled, mbmi->segment_id_supertx == 0));
     assert(mbmi->segment_id_supertx < MAX_SEGMENTS);
@@ -2737,7 +2758,14 @@
   const int mi_col_start = tile->mi_col_start;
   const int mi_col_end = tile->mi_col_end;
   int mi_row, mi_col;
+
+#if CONFIG_DEPENDENT_HORZTILES
+  if (!cm->dependent_horz_tiles || mi_row_start == 0) {
+    av1_zero_above_context(cm, mi_col_start, mi_col_end);
+  }
+#else
   av1_zero_above_context(cm, mi_col_start, mi_col_end);
+#endif
 #if CONFIG_PVQ
   assert(cpi->td.mb.pvq_q->curr_pos == 0);
 #endif
@@ -3667,6 +3695,10 @@
   if (cm->log2_tile_rows != 0) aom_wb_write_bit(wb, cm->log2_tile_rows != 1);
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_DEPENDENT_HORZTILES
+  if (cm->log2_tile_rows != 0) aom_wb_write_bit(wb, cm->dependent_horz_tiles);
+#endif
+
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   aom_wb_write_bit(wb, cm->loop_filter_across_tiles_enabled);
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index c6a7c8a..754a472 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -293,8 +293,13 @@
 
   // Set up distance of MB to edge of frame in 1/8th pel units.
   assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1)));
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, cm->mi_rows,
+                 cm->mi_cols, cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, cm->mi_rows,
                  cm->mi_cols);
+#endif
 
   // Set up source buffers.
   av1_setup_src_planes(x, cpi->Source, mi_row, mi_col);
@@ -345,8 +350,11 @@
   MACROBLOCKD *const xd = &x->e_mbd;
   const int mi_width = mi_size_wide[bsize];
   const int mi_height = mi_size_high[bsize];
-
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mode_info_offsets(cpi, x, xd, mi_row, mi_col, cm->dependent_horz_tiles);
+#else
   set_mode_info_offsets(cpi, x, xd, mi_row, mi_col);
+#endif
 
   // Set up distance of MB to edge of frame in 1/8th pel units.
   assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1)));
@@ -367,7 +375,12 @@
   const int mi_width = mi_size_wide[bsize_pred];
   const int mi_height = mi_size_high[bsize_pred];
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mode_info_offsets(cpi, x, xd, mi_row_ori, mi_col_ori,
+                        cm->dependent_horz_tiles);
+#else
   set_mode_info_offsets(cpi, x, xd, mi_row_ori, mi_col_ori);
+#endif
 
   // Set up limit values for MV components.
   // Mv beyond the range do not produce new/different prediction block.
@@ -4817,8 +4830,13 @@
 #if CONFIG_PVQ
   od_adapt_ctx *adapt;
 #endif
-
+#if CONFIG_DEPENDENT_HORZTILES
+  if ((!cm->dependent_horz_tiles) || (tile_row == 0)) {
+    av1_zero_above_context(cm, tile_info->mi_col_start, tile_info->mi_col_end);
+  }
+#else
   av1_zero_above_context(cm, tile_info->mi_col_start, tile_info->mi_col_end);
+#endif
 
   // Set up pointers to per thread motion search counters.
   this_tile->m_search_count = 0;   // Count of motion search hits.
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index d119268..f4e7531 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -868,6 +868,11 @@
   cm->tile_height = ALIGN_POWER_OF_TWO(cm->tile_height, MAX_MIB_SIZE_LOG2);
 #endif  // CONFIG_EXT_TILE
 
+#if CONFIG_DEPENDENT_HORZTILES
+  cm->dependent_horz_tiles = cpi->oxcf.dependent_horz_tiles;
+  if (cm->log2_tile_rows == 0) cm->dependent_horz_tiles = 0;
+#endif
+
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   cm->loop_filter_across_tiles_enabled =
       cpi->oxcf.loop_filter_across_tiles_enabled;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index cb83027..63b8497 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -242,6 +242,9 @@
 
   int tile_columns;
   int tile_rows;
+#if CONFIG_DEPENDENT_HORZTILES
+  int dependent_horz_tiles;
+#endif
 #if CONFIG_LOOPFILTERING_ACROSS_TILES
   int loop_filter_across_tiles_enabled;
 #endif  // CONFIG_LOOPFILTERING_ACROSS_TILES
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 28eaf94..8b80797 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -633,9 +633,16 @@
       xd->left_available = (mb_col != 0);
       xd->mi[0]->mbmi.sb_type = bsize;
       xd->mi[0]->mbmi.ref_frame[0] = INTRA_FRAME;
+#if CONFIG_DEPENDENT_HORZTILES
+      set_mi_row_col(xd, &tile, mb_row * mb_scale, mi_size_high[bsize],
+                     mb_col * mb_scale, mi_size_wide[bsize], cm->mi_rows,
+                     cm->mi_cols, cm->dependent_horz_tiles);
+#else
       set_mi_row_col(xd, &tile, mb_row * mb_scale, mi_size_high[bsize],
                      mb_col * mb_scale, mi_size_wide[bsize], cm->mi_rows,
                      cm->mi_cols);
+#endif
+
       set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize]);
 
       // Do intra 16x16 prediction.
diff --git a/av1/encoder/segmentation.c b/av1/encoder/segmentation.c
index b291b29..1b28f41 100644
--- a/av1/encoder/segmentation.c
+++ b/av1/encoder/segmentation.c
@@ -129,7 +129,12 @@
   xd->mi = mi;
   segment_id = xd->mi[0]->mbmi.segment_id;
 
+#if CONFIG_DEPENDENT_HORZTILES
+  set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols,
+                 cm->dependent_horz_tiles);
+#else
   set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols);
+#endif
 
   // Count the number of hits on each segment with no prediction
   no_pred_segcounts[segment_id]++;
diff --git a/configure b/configure
index 6a86f05..dadedcc 100755
--- a/configure
+++ b/configure
@@ -300,6 +300,7 @@
     coef_interleave
     entropy_stats
     masked_tx
+    dependent_horztiles
     daala_dist
     tripred
 "