shithub: libvpx

Download patch

ref: 10a497bd3823d88cf4c2f816a648ca0e79bd07be
parent: c530208ae3cc0cb6835aeaa8e9ceb7edb37f40f0
author: Yunqing Wang <[email protected]>
date: Mon Apr 24 08:06:49 EDT 2017

Make the row based multi-threaded encoder deterministic

This patch followed allow_exhaustive_searches feature modification and
continued to modify the encoder to achieve the determinism in the row
based multi-threaded encoding. While row-mt = 1 and using multiple
threads, the adaptive feature in encoder was disabled, which gave
BDRate gain(at speed 1, -0.6% ~ -0.7%; at speed 2, -0.46% ~ -0.59%),
but some encoder speed losses(7% ~ 10% at speed 1 and 3% ~ 6% at
speed 2). These speed losses were acceptable considering the speed
gains obtained from row-mt.

Change-Id: I60d87a25346ebc487a864b57d559f560b7e398bb

--- a/test/vp9_ethread_test.cc
+++ b/test/vp9_ethread_test.cc
@@ -40,7 +40,6 @@
     init_flags_ = VPX_CODEC_USE_PSNR;
 
     row_mt_mode_ = 1;
-    bit_exact_mode_ = 0;
     first_pass_only_ = true;
     firstpass_stats_.buf = NULL;
     firstpass_stats_.sz = 0;
@@ -85,8 +84,6 @@
       if (encoding_mode_ == ::libvpx_test::kTwoPassGood)
         encoder->Control(VP9E_SET_ROW_MT, row_mt_mode_);
 
-      encoder->Control(VP9E_ENABLE_ROW_MT_BIT_EXACT, bit_exact_mode_);
-
       encoder_initialized_ = true;
     }
   }
@@ -112,12 +109,11 @@
   ::libvpx_test::TestMode encoding_mode_;
   int set_cpu_used_;
   int row_mt_mode_;
-  int bit_exact_mode_;
   bool first_pass_only_;
   vpx_fixed_buf_t firstpass_stats_;
 };
 
-static void compare_fp_stats(vpx_fixed_buf_t *fp_stats) {
+static void compare_fp_stats(vpx_fixed_buf_t *fp_stats, double factor) {
   // fp_stats consists of 2 set of first pass encoding stats. These 2 set of
   // stats are compared to check if the stats match or at least are very close.
   FIRSTPASS_STATS *stats1 = reinterpret_cast<FIRSTPASS_STATS *>(fp_stats->buf);
@@ -133,7 +129,7 @@
 
     for (j = 0; j < kDbl; ++j) {
       EXPECT_LE(fabs(*frame_stats1 - *frame_stats2),
-                fabs(*frame_stats1) / 10000.0);
+                fabs(*frame_stats1) / factor);
       frame_stats1++;
       frame_stats2++;
     }
@@ -175,8 +171,7 @@
   first_pass_only_ = true;
   cfg_.rc_target_bitrate = 1000;
 
-  // Test row_mt_mode: 0 vs 1 (threads = 1, tiles_ = 0)
-  bit_exact_mode_ = 0;
+  // Test row_mt_mode: 0 vs 1 at single thread case(threads = 1, tiles_ = 0)
   tiles_ = 0;
   cfg_.g_threads = 1;
 
@@ -187,12 +182,12 @@
   row_mt_mode_ = 1;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 
-  // Compare to check if using or not using row-mt generates matching stats.
-  compare_fp_stats(&firstpass_stats_);
+  // Compare to check if using or not using row-mt generates close stats.
+  compare_fp_stats(&firstpass_stats_, 1000.0);
 
-  // Test multi-threads: single thread vs 4 threads
+  // Test single thread vs multiple threads
   row_mt_mode_ = 1;
-  tiles_ = 2;
+  tiles_ = 0;
 
   cfg_.g_threads = 1;
   init_flags_ = VPX_CODEC_USE_PSNR;
@@ -201,19 +196,20 @@
   cfg_.g_threads = 4;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 
-  // Compare to check if single-thread and multi-thread stats matches.
-  compare_fp_stats(&firstpass_stats_);
+  // Compare to check if single-thread and multi-thread stats are close enough.
+  compare_fp_stats(&firstpass_stats_, 1000.0);
 
-  // Test row_mt_mode: 0 vs 1 (threads = 8, tiles_ = 2)
-  bit_exact_mode_ = 1;
+  // Bit exact test in row_mt mode.
+  // When row_mt_mode_=1 and using >1 threads, the encoder generates bit exact
+  // result.
+  row_mt_mode_ = 1;
   tiles_ = 2;
-  cfg_.g_threads = 8;
 
-  row_mt_mode_ = 0;
+  cfg_.g_threads = 2;
   init_flags_ = VPX_CODEC_USE_PSNR;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 
-  row_mt_mode_ = 1;
+  cfg_.g_threads = 8;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 
   // Compare to check if stats match with row-mt=0/1.
@@ -232,7 +228,6 @@
     init_flags_ = VPX_CODEC_USE_PSNR;
     md5_.clear();
     row_mt_mode_ = 1;
-    bit_exact_mode_ = 0;
     psnr_ = 0.0;
     nframes_ = 0;
   }
@@ -279,10 +274,7 @@
         encoder->Control(VP9E_SET_AQ_MODE, 3);
       }
       encoder->Control(VP9E_SET_ROW_MT, row_mt_mode_);
-      // While row_mt = 1, several speed features that would adaptively adjust
-      // encoding parameters have to be disabled to guarantee the bit exactness
-      // of the resulting bitstream.
-      encoder->Control(VP9E_ENABLE_ROW_MT_BIT_EXACT, bit_exact_mode_);
+
       encoder_initialized_ = true;
     }
   }
@@ -318,7 +310,6 @@
   ::libvpx_test::TestMode encoding_mode_;
   int set_cpu_used_;
   int row_mt_mode_;
-  int bit_exact_mode_;
   double psnr_;
   unsigned int nframes_;
   std::vector<std::string> md5_;
@@ -331,7 +322,6 @@
   // Part 1: Bit exact test for row_mt_mode_ = 0.
   // This part keeps original unit tests done before row-mt code is checked in.
   row_mt_mode_ = 0;
-  bit_exact_mode_ = 0;
 
   // Encode using single thread.
   cfg_.g_threads = 1;
@@ -353,7 +343,6 @@
   // The first-pass stats are not bit exact here, but that difference doesn't
   // cause a mismatch between the final bitstreams.
   row_mt_mode_ = 1;
-  bit_exact_mode_ = 0;
 
   // Encode using single thread
   cfg_.g_threads = 1;
@@ -365,12 +354,13 @@
   ASSERT_EQ(single_thr_md5, row_mt_single_thr_md5);
 
   // Part 3: Bit exact test with row-mt on
+  // When row_mt_mode_=1 and using >1 threads, the encoder generates bit exact
+  // result.
   row_mt_mode_ = 1;
-  bit_exact_mode_ = 1;
   row_mt_single_thr_md5.clear();
 
-  // Encode using single thread.
-  cfg_.g_threads = 1;
+  // Encode using 2 threads.
+  cfg_.g_threads = 2;
   init_flags_ = VPX_CODEC_USE_PSNR;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
   row_mt_single_thr_md5 = md5_;
@@ -387,7 +377,6 @@
 
   // Part 4: PSNR test with bit_match_mode_ = 0
   row_mt_mode_ = 1;
-  bit_exact_mode_ = 0;
 
   // Encode using single thread.
   cfg_.g_threads = 1;
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -4341,7 +4341,6 @@
           }
         }
 #if CONFIG_MULTITHREAD
-        tile_data->enc_row_mt_mutex = NULL;
         tile_data->row_base_thresh_freq_fact = NULL;
 #endif
       }
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -5281,4 +5281,9 @@
   if (cpi->oxcf.mode == REALTIME && cpi->oxcf.speed >= 5 && cpi->oxcf.row_mt) {
     cpi->row_mt = 1;
   }
+
+  if (cpi->row_mt && cpi->oxcf.max_threads > 1)
+    cpi->row_mt_bit_exact = 1;
+  else
+    cpi->row_mt_bit_exact = 0;
 }
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -268,7 +268,6 @@
   VP9E_TEMPORAL_LAYERING_MODE temporal_layering_mode;
 
   int row_mt;
-  unsigned int row_mt_bit_exact;
   unsigned int motion_vector_unit_test;
 } VP9EncoderConfig;
 
@@ -286,9 +285,6 @@
 
   // Used for adaptive_rd_thresh with row multithreading
   int *row_base_thresh_freq_fact;
-#if CONFIG_MULTITHREAD
-  pthread_mutex_t *enc_row_mt_mutex;
-#endif
 } TileDataEnc;
 
 typedef struct RowMTInfo {
@@ -692,7 +688,9 @@
   void (*row_mt_sync_read_ptr)(VP9RowMTSync *const, int, int);
   void (*row_mt_sync_write_ptr)(VP9RowMTSync *const, int, int, const int);
   ARNRFilterData arnr_filter_data;
+
   int row_mt;
+  unsigned int row_mt_bit_exact;
 
   // Previous Partition Info
   BLOCK_SIZE *prev_partition;
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -979,12 +979,12 @@
     if (log_intra < 10.0) {
       mb_intra_factor = 1.0 + ((10.0 - log_intra) * 0.05);
       fp_acc_data->intra_factor += mb_intra_factor;
-      if (cpi->oxcf.row_mt_bit_exact)
+      if (cpi->row_mt_bit_exact)
         cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_intra_factor =
             mb_intra_factor;
     } else {
       fp_acc_data->intra_factor += 1.0;
-      if (cpi->oxcf.row_mt_bit_exact)
+      if (cpi->row_mt_bit_exact)
         cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_intra_factor = 1.0;
     }
 
@@ -999,12 +999,12 @@
     if ((level_sample < DARK_THRESH) && (log_intra < 9.0)) {
       mb_brightness_factor = 1.0 + (0.01 * (DARK_THRESH - level_sample));
       fp_acc_data->brightness_factor += mb_brightness_factor;
-      if (cpi->oxcf.row_mt_bit_exact)
+      if (cpi->row_mt_bit_exact)
         cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_brightness_factor =
             mb_brightness_factor;
     } else {
       fp_acc_data->brightness_factor += 1.0;
-      if (cpi->oxcf.row_mt_bit_exact)
+      if (cpi->row_mt_bit_exact)
         cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_brightness_factor =
             1.0;
     }
@@ -1166,7 +1166,7 @@
         if (((this_error - intrapenalty) * 9 <= motion_error * 10) &&
             (this_error < (2 * intrapenalty))) {
           fp_acc_data->neutral_count += 1.0;
-          if (cpi->oxcf.row_mt_bit_exact)
+          if (cpi->row_mt_bit_exact)
             cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_neutral_count =
                 1.0;
           // Also track cases where the intra is not much worse than the inter
@@ -1176,7 +1176,7 @@
           mb_neutral_count =
               (double)motion_error / DOUBLE_DIVIDE_CHECK((double)this_error);
           fp_acc_data->neutral_count += mb_neutral_count;
-          if (cpi->oxcf.row_mt_bit_exact)
+          if (cpi->row_mt_bit_exact)
             cpi->twopass.fp_mb_float_stats[mb_index].frame_mb_neutral_count =
                 mb_neutral_count;
         }
@@ -1424,7 +1424,7 @@
 
   cm->log2_tile_rows = 0;
 
-  if (cpi->oxcf.row_mt_bit_exact && cpi->twopass.fp_mb_float_stats == NULL)
+  if (cpi->row_mt_bit_exact && cpi->twopass.fp_mb_float_stats == NULL)
     CHECK_MEM_ERROR(
         cm, cpi->twopass.fp_mb_float_stats,
         vpx_calloc(cm->MBs * sizeof(*cpi->twopass.fp_mb_float_stats), 1));
@@ -1441,13 +1441,13 @@
     } else {
       cpi->row_mt_sync_read_ptr = vp9_row_mt_sync_read;
       cpi->row_mt_sync_write_ptr = vp9_row_mt_sync_write;
-      if (cpi->oxcf.row_mt_bit_exact) {
+      if (cpi->row_mt_bit_exact) {
         cm->log2_tile_cols = 0;
         vp9_zero_array(cpi->twopass.fp_mb_float_stats, cm->MBs);
       }
       vp9_encode_fp_row_mt(cpi);
       first_tile_col = &cpi->tile_data[0];
-      if (cpi->oxcf.row_mt_bit_exact)
+      if (cpi->row_mt_bit_exact)
         accumulate_floating_point_stats(cpi, first_tile_col);
       first_pass_stat_calc(cpi, &fps, &(first_tile_col->fp_data));
     }
--- a/vp9/encoder/vp9_multi_thread.c
+++ b/vp9/encoder/vp9_multi_thread.c
@@ -110,19 +110,6 @@
     multi_thread_ctxt->num_tile_vert_sbs[tile_row] =
         get_num_vert_units(*tile_info, MI_BLOCK_SIZE_LOG2);
   }
-
-#if CONFIG_MULTITHREAD
-  for (tile_row = 0; tile_row < tile_rows; tile_row++) {
-    for (tile_col = 0; tile_col < tile_cols; tile_col++) {
-      TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
-
-      CHECK_MEM_ERROR(cm, this_tile->enc_row_mt_mutex,
-                      vpx_malloc(sizeof(*this_tile->enc_row_mt_mutex)));
-
-      pthread_mutex_init(this_tile->enc_row_mt_mutex, NULL);
-    }
-  }
-#endif
 }
 
 void vp9_row_mt_mem_dealloc(VP9_COMP *cpi) {
@@ -165,9 +152,6 @@
           this_tile->row_base_thresh_freq_fact = NULL;
         }
       }
-      pthread_mutex_destroy(this_tile->enc_row_mt_mutex);
-      vpx_free(this_tile->enc_row_mt_mutex);
-      this_tile->enc_row_mt_mutex = NULL;
     }
   }
 #endif
--- a/vp9/encoder/vp9_pickmode.c
+++ b/vp9/encoder/vp9_pickmode.c
@@ -1720,15 +1720,8 @@
          rd_less_than_thresh_row_mt(best_rdc.rdcost, mode_rd_thresh,
                                     &rd_thresh_freq_fact[mode_index])) ||
         (!cpi->sf.adaptive_rd_thresh_row_mt &&
-         rd_less_than_thresh(
-             best_rdc.rdcost, mode_rd_thresh,
-#if CONFIG_MULTITHREAD
-             // Synchronization of this function
-             // is only necessary when
-             // adaptive_rd_thresh is > 0.
-             cpi->sf.adaptive_rd_thresh ? tile_data->enc_row_mt_mutex : NULL,
-#endif
-             &rd_thresh_freq_fact[mode_index])))
+         rd_less_than_thresh(best_rdc.rdcost, mode_rd_thresh,
+                             &rd_thresh_freq_fact[mode_index])))
       continue;
 
     if (this_mode == NEWMV) {
@@ -2098,15 +2091,8 @@
            rd_less_than_thresh_row_mt(best_rdc.rdcost, mode_rd_thresh,
                                       &rd_thresh_freq_fact[mode_index])) ||
           (!cpi->sf.adaptive_rd_thresh_row_mt &&
-           rd_less_than_thresh(
-               best_rdc.rdcost, mode_rd_thresh,
-#if CONFIG_MULTITHREAD
-               // Synchronization of this function
-               // is only necessary when
-               // adaptive_rd_thresh is > 0.
-               cpi->sf.adaptive_rd_thresh ? tile_data->enc_row_mt_mutex : NULL,
-#endif
-               &rd_thresh_freq_fact[mode_index])))
+           rd_less_than_thresh(best_rdc.rdcost, mode_rd_thresh,
+                               &rd_thresh_freq_fact[mode_index])))
         continue;
 
       mi->mode = this_mode;
--- a/vp9/encoder/vp9_rd.c
+++ b/vp9/encoder/vp9_rd.c
@@ -650,15 +650,7 @@
 }
 
 void vp9_update_rd_thresh_fact(int (*factor_buf)[MAX_MODES], int rd_thresh,
-                               int bsize,
-#if CONFIG_MULTITHREAD
-                               pthread_mutex_t *enc_row_mt_mutex,
-#endif
-                               int best_mode_index) {
-#if CONFIG_MULTITHREAD
-  if (NULL != enc_row_mt_mutex) pthread_mutex_lock(enc_row_mt_mutex);
-#endif
-
+                               int bsize, int best_mode_index) {
   if (rd_thresh > 0) {
     const int top_mode = bsize < BLOCK_8X8 ? MAX_REFS : MAX_MODES;
     int mode;
@@ -676,10 +668,6 @@
       }
     }
   }
-
-#if CONFIG_MULTITHREAD
-  if (NULL != enc_row_mt_mutex) pthread_mutex_unlock(enc_row_mt_mutex);
-#endif
 }
 
 int vp9_get_intra_cost_penalty(int qindex, int qdelta,
--- a/vp9/encoder/vp9_rd.h
+++ b/vp9/encoder/vp9_rd.h
@@ -170,32 +170,11 @@
 void vp9_set_rd_speed_thresholds_sub8x8(struct VP9_COMP *cpi);
 
 void vp9_update_rd_thresh_fact(int (*fact)[MAX_MODES], int rd_thresh, int bsize,
-#if CONFIG_MULTITHREAD
-                               pthread_mutex_t *enc_row_mt_mutex,
-#endif
                                int best_mode_index);
 
 static INLINE int rd_less_than_thresh(int64_t best_rd, int thresh,
-#if CONFIG_MULTITHREAD
-                                      pthread_mutex_t *enc_row_mt_mutex,
-#endif
                                       const int *const thresh_fact) {
-  int is_rd_less_than_thresh;
-
-#if CONFIG_MULTITHREAD
-  // Synchronize to ensure data coherency as thresh_freq_fact is maintained at
-  // tile level and not thread-safe with row based multi-threading
-  if (NULL != enc_row_mt_mutex) pthread_mutex_lock(enc_row_mt_mutex);
-#endif
-
-  is_rd_less_than_thresh =
-      best_rd < ((int64_t)thresh * (*thresh_fact) >> 5) || thresh == INT_MAX;
-
-#if CONFIG_MULTITHREAD
-  if (NULL != enc_row_mt_mutex) pthread_mutex_unlock(enc_row_mt_mutex);
-#endif
-
-  return is_rd_less_than_thresh;
+  return best_rd < ((int64_t)thresh * (*thresh_fact) >> 5) || thresh == INT_MAX;
 }
 
 static INLINE void set_error_per_bit(MACROBLOCK *x, int rdmult) {
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -3161,11 +3161,6 @@
 
   for (i = 0; i <= LAST_NEW_MV_INDEX; ++i) mode_threshold[i] = 0;
 
-#if CONFIG_MULTITHREAD
-  if (NULL != tile_data->enc_row_mt_mutex)
-    pthread_mutex_lock(tile_data->enc_row_mt_mutex);
-#endif
-
   for (i = LAST_NEW_MV_INDEX + 1; i < MAX_MODES; ++i)
     mode_threshold[i] = ((int64_t)rd_threshes[i] * rd_thresh_freq_fact[i]) >> 5;
 
@@ -3187,11 +3182,6 @@
 
   memcpy(mode_map, tile_mode_map, sizeof(mode_map));
 
-#if CONFIG_MULTITHREAD
-  if (NULL != tile_data->enc_row_mt_mutex)
-    pthread_mutex_unlock(tile_data->enc_row_mt_mutex);
-#endif
-
   for (midx = 0; midx < MAX_MODES; ++midx) {
     int mode_index = mode_map[midx];
     int mode_excluded = 0;
@@ -3628,11 +3618,7 @@
 
   if (!cpi->rc.is_src_frame_alt_ref)
     vp9_update_rd_thresh_fact(tile_data->thresh_freq_fact,
-                              sf->adaptive_rd_thresh, bsize,
-#if CONFIG_MULTITHREAD
-                              tile_data->enc_row_mt_mutex,
-#endif
-                              best_mode_index);
+                              sf->adaptive_rd_thresh, bsize, best_mode_index);
 
   // macroblock modes
   *mi = best_mbmode;
@@ -3772,11 +3758,7 @@
          (cm->interp_filter == mi->interp_filter));
 
   vp9_update_rd_thresh_fact(tile_data->thresh_freq_fact,
-                            cpi->sf.adaptive_rd_thresh, bsize,
-#if CONFIG_MULTITHREAD
-                            tile_data->enc_row_mt_mutex,
-#endif
-                            THR_ZEROMV);
+                            cpi->sf.adaptive_rd_thresh, bsize, THR_ZEROMV);
 
   vp9_zero(best_pred_diff);
   vp9_zero(best_filter_diff);
@@ -3922,9 +3904,6 @@
     if (!internal_active_edge &&
         rd_less_than_thresh(best_rd,
                             rd_opt->threshes[segment_id][bsize][ref_index],
-#if CONFIG_MULTITHREAD
-                            tile_data->enc_row_mt_mutex,
-#endif
                             &rd_thresh_freq_fact[ref_index]))
       continue;
 
@@ -4374,11 +4353,7 @@
          !is_inter_block(&best_mbmode));
 
   vp9_update_rd_thresh_fact(tile_data->thresh_freq_fact, sf->adaptive_rd_thresh,
-                            bsize,
-#if CONFIG_MULTITHREAD
-                            tile_data->enc_row_mt_mutex,
-#endif
-                            best_ref_index);
+                            bsize, best_ref_index);
 
   // macroblock modes
   *mi = best_mbmode;
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -639,10 +639,7 @@
   // With row based multi-threading, the following speed features
   // have to be disabled to guarantee that bitstreams encoded with single thread
   // and multiple threads match
-  if (cpi->oxcf.row_mt_bit_exact) {
-    sf->adaptive_rd_thresh = 0;
-    sf->adaptive_pred_interp_filter = 0;
-  }
+  if (cpi->row_mt_bit_exact) sf->adaptive_rd_thresh = 0;
 
   // This is only used in motion vector unit test.
   if (cpi->oxcf.motion_vector_unit_test == 1)
@@ -796,10 +793,7 @@
   // With row based multi-threading, the following speed features
   // have to be disabled to guarantee that bitstreams encoded with single thread
   // and multiple threads match
-  if (cpi->oxcf.row_mt_bit_exact) {
-    sf->adaptive_rd_thresh = 0;
-    sf->adaptive_pred_interp_filter = 0;
-  }
+  if (cpi->row_mt_bit_exact) sf->adaptive_rd_thresh = 0;
 
   // This is only used in motion vector unit test.
   if (cpi->oxcf.motion_vector_unit_test == 1)
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -52,7 +52,6 @@
   int render_width;
   int render_height;
   unsigned int row_mt;
-  unsigned int row_mt_bit_exact;
   unsigned int motion_vector_unit_test;
 };
 
@@ -86,7 +85,6 @@
   0,                     // render width
   0,                     // render height
   0,                     // row_mt
-  0,                     // row_mt_bit_exact
   0,                     // motion_vector_unit_test
 };
 
@@ -252,7 +250,6 @@
         "or kf_max_dist instead.");
 
   RANGE_CHECK(extra_cfg, row_mt, 0, 1);
-  RANGE_CHECK(extra_cfg, row_mt_bit_exact, 0, 1);
   RANGE_CHECK(extra_cfg, motion_vector_unit_test, 0, 2);
   RANGE_CHECK(extra_cfg, enable_auto_alt_ref, 0, 2);
   RANGE_CHECK(extra_cfg, cpu_used, -8, 8);
@@ -564,7 +561,6 @@
   oxcf->target_level = extra_cfg->target_level;
 
   oxcf->row_mt = extra_cfg->row_mt;
-  oxcf->row_mt_bit_exact = extra_cfg->row_mt_bit_exact;
   oxcf->motion_vector_unit_test = extra_cfg->motion_vector_unit_test;
 
   for (sl = 0; sl < oxcf->ss_number_layers; ++sl) {
@@ -862,13 +858,6 @@
   return update_extra_cfg(ctx, &extra_cfg);
 }
 
-static vpx_codec_err_t ctrl_enable_row_mt_bit_exact(vpx_codec_alg_priv_t *ctx,
-                                                    va_list args) {
-  struct vp9_extracfg extra_cfg = ctx->extra_cfg;
-  extra_cfg.row_mt_bit_exact = CAST(VP9E_ENABLE_ROW_MT_BIT_EXACT, args);
-  return update_extra_cfg(ctx, &extra_cfg);
-}
-
 static vpx_codec_err_t ctrl_enable_motion_vector_unit_test(
     vpx_codec_alg_priv_t *ctx, va_list args) {
   struct vp9_extracfg extra_cfg = ctx->extra_cfg;
@@ -1633,7 +1622,6 @@
   { VP9E_SET_RENDER_SIZE, ctrl_set_render_size },
   { VP9E_SET_TARGET_LEVEL, ctrl_set_target_level },
   { VP9E_SET_ROW_MT, ctrl_set_row_mt },
-  { VP9E_ENABLE_ROW_MT_BIT_EXACT, ctrl_enable_row_mt_bit_exact },
   { VP9E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
 
   // Getters
--- a/vpx/vp8cx.h
+++ b/vpx/vp8cx.h
@@ -555,15 +555,6 @@
   */
   VP9E_SET_ROW_MT,
 
-  /*!\brief Codec control function to enable bit-exact bitstream when row level
-   * multi-threading is enabled.
-   *
-   * 0 : off, 1 : on
-   *
-   * Supported in codecs: VP9
-   */
-  VP9E_ENABLE_ROW_MT_BIT_EXACT,
-
   /*!\brief Codec control function to get bitstream level.
    *
    * Supported in codecs: VP9
@@ -866,9 +857,6 @@
 
 VPX_CTRL_USE_TYPE(VP9E_SET_ROW_MT, unsigned int)
 #define VPX_CTRL_VP9E_SET_ROW_MT
-
-VPX_CTRL_USE_TYPE(VP9E_ENABLE_ROW_MT_BIT_EXACT, unsigned int)
-#define VPX_CTRL_VP9E_ENABLE_ROW_MT_BIT_EXACT
 
 VPX_CTRL_USE_TYPE(VP9E_GET_LEVEL, int *)
 #define VPX_CTRL_VP9E_GET_LEVEL