Refactor memory alloc/dealloc of mb_wiener_var buffers

The temporary 'pred_buffer' used during the wiener variance
computation was allocated and deallocated for every row  in
av1_calc_mb_wiener_var_row(). This CL introduces a pointer to
a temporary pred buffer (wiener_tmp_pred_buf) in ThreadData
structure which is allocated/deallocated once per frame.
Also added the necessary calls to free weiner variance buffers
in encoder destroy to avoid memory leaks in case of early
termination.

Bug: aomedia:3276
Change-Id: I56227f1f5dab916db77349b522a6216b359ec6f7
diff --git a/av1/encoder/allintra_vis.c b/av1/encoder/allintra_vis.c
index 236b296..a59d0d7 100644
--- a/av1/encoder/allintra_vis.c
+++ b/av1/encoder/allintra_vis.c
@@ -29,6 +29,26 @@
 #include "av1/encoder/model_rd.h"
 #include "av1/encoder/rdopt_utils.h"
 
+#define MB_WIENER_PRED_BLOCK_SIZE BLOCK_128X128
+#define MB_WIENER_PRED_BUF_STRIDE 128
+
+void av1_alloc_mb_wiener_var_pred_buf(AV1_COMMON *cm, ThreadData *td) {
+  const int is_high_bitdepth = is_cur_buf_hbd(&td->mb.e_mbd);
+  assert(MB_WIENER_PRED_BLOCK_SIZE < BLOCK_SIZES_ALL);
+  const int buf_width = block_size_wide[MB_WIENER_PRED_BLOCK_SIZE];
+  const int buf_height = block_size_high[MB_WIENER_PRED_BLOCK_SIZE];
+  assert(buf_width == MB_WIENER_PRED_BUF_STRIDE);
+  const size_t buf_size =
+      (buf_width * buf_height * sizeof(*td->wiener_tmp_pred_buf))
+      << is_high_bitdepth;
+  CHECK_MEM_ERROR(cm, td->wiener_tmp_pred_buf, aom_memalign(32, buf_size));
+}
+
+void av1_dealloc_mb_wiener_var_pred_buf(ThreadData *td) {
+  aom_free(td->wiener_tmp_pred_buf);
+  td->wiener_tmp_pred_buf = NULL;
+}
+
 void av1_init_mb_wiener_var_buffer(AV1_COMP *cpi) {
   AV1_COMMON *cm = &cpi->common;
 
@@ -236,7 +256,7 @@
                                 int16_t *src_diff, tran_low_t *coeff,
                                 tran_low_t *qcoeff, tran_low_t *dqcoeff,
                                 double *sum_rec_distortion,
-                                double *sum_est_rate) {
+                                double *sum_est_rate, uint8_t *pred_buffer) {
   AV1_COMMON *const cm = &cpi->common;
   uint8_t *buffer = cpi->source->y_buffer;
   int buf_stride = cpi->source->y_stride;
@@ -261,16 +281,9 @@
   int mt_unit_col = 0;
   const int is_high_bitdepth = is_cur_buf_hbd(xd);
 
-  // We use a scratch buffer to store the prediction.
-  // The stride is the max block size (128).
-  uint8_t *pred_buffer;
-  const int dst_buffer_stride = 128;
-  const int buf_width = 128;
-  const int buf_height = 128;
-  const size_t buf_size = (buf_width * buf_height * sizeof(*pred_buffer))
-                          << is_high_bitdepth;
-  CHECK_MEM_ERROR(cm, pred_buffer, aom_memalign(32, buf_size));
   uint8_t *dst_buffer = pred_buffer;
+  const int dst_buffer_stride = MB_WIENER_PRED_BUF_STRIDE;
+
   if (is_high_bitdepth) {
     uint16_t *pred_buffer_16 = (uint16_t *)pred_buffer;
     dst_buffer = CONVERT_TO_BYTEPTR(pred_buffer_16);
@@ -434,7 +447,6 @@
   }
   // Set the pointer to null since mbmi is only allocated inside this function.
   xd->mi = NULL;
-  aom_free(pred_buffer);
 }
 
 static void calc_mb_wiener_var(AV1_COMP *const cpi, double *sum_rec_distortion,
@@ -449,7 +461,8 @@
   DECLARE_ALIGNED(32, tran_low_t, dqcoeff[32 * 32]);
   for (int mi_row = 0; mi_row < cpi->frame_info.mi_rows; mi_row += mb_step) {
     av1_calc_mb_wiener_var_row(cpi, x, xd, mi_row, src_diff, coeff, qcoeff,
-                               dqcoeff, sum_rec_distortion, sum_est_rate);
+                               dqcoeff, sum_rec_distortion, sum_est_rate,
+                               cpi->td.wiener_tmp_pred_buf);
   }
 }
 
@@ -565,6 +578,7 @@
           NULL, cpi->image_pyramid_levels, 0))
     aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate frame buffer");
+  av1_alloc_mb_wiener_var_pred_buf(&cpi->common, &cpi->td);
   cpi->norm_wiener_variance = 0;
 
   MACROBLOCK *x = &cpi->td.mb;
@@ -647,6 +661,7 @@
   // Set the pointer to null since mbmi is only allocated inside this function.
   xd->mi = NULL;
   aom_free_frame_buffer(&cm->cur_frame->buf);
+  av1_dealloc_mb_wiener_var_pred_buf(&cpi->td);
 }
 
 static int get_rate_guided_quantizer(AV1_COMP *const cpi, BLOCK_SIZE bsize,
diff --git a/av1/encoder/allintra_vis.h b/av1/encoder/allintra_vis.h
index 9e10566..ab39968 100644
--- a/av1/encoder/allintra_vis.h
+++ b/av1/encoder/allintra_vis.h
@@ -27,7 +27,7 @@
                                 int16_t *src_diff, tran_low_t *coeff,
                                 tran_low_t *qcoeff, tran_low_t *dqcoeff,
                                 double *sum_rec_distortion,
-                                double *sum_est_rate);
+                                double *sum_est_rate, uint8_t *pred_buffer);
 
 void av1_set_mb_wiener_variance(AV1_COMP *cpi);
 
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 3c00553..6a4332c 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1727,6 +1727,7 @@
   av1_row_mt_mem_dealloc(cpi);
 
   if (mt_info->num_workers > 1) {
+    av1_row_mt_sync_mem_dealloc(&cpi->ppi->intra_row_mt_sync);
     av1_loop_filter_dealloc(&mt_info->lf_row_sync);
     av1_cdef_mt_dealloc(&mt_info->cdef_sync);
 #if !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 04c2d87..92d0840 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1456,6 +1456,7 @@
   CONV_BUF_TYPE *tmp_conv_dst;
   uint64_t abs_sum_level;
   uint8_t *tmp_pred_bufs[2];
+  uint8_t *wiener_tmp_pred_buf;
   int intrabc_used;
   int deltaq_used;
   int coefficient_size;
@@ -3804,6 +3805,10 @@
 
 int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *input_size);
 
+void av1_alloc_mb_wiener_var_pred_buf(AV1_COMMON *cm, ThreadData *td);
+
+void av1_dealloc_mb_wiener_var_pred_buf(ThreadData *td);
+
 // Set screen content options.
 // This function estimates whether to use screen content tools, by counting
 // the portion of blocks that have few luma colors.
diff --git a/av1/encoder/encoder_alloc.h b/av1/encoder/encoder_alloc.h
index 3ed5dc2..def0069 100644
--- a/av1/encoder/encoder_alloc.h
+++ b/av1/encoder/encoder_alloc.h
@@ -290,6 +290,8 @@
 
   av1_dealloc_mb_data(&cpi->td.mb, av1_num_planes(cm));
 
+  av1_dealloc_mb_wiener_var_pred_buf(&cpi->td);
+
   av1_free_txb_buf(cpi);
   av1_free_context_buffers(cm);
 
@@ -502,6 +504,7 @@
     av1_free_pc_tree_recursive(thread_data->td->pc_root, num_planes, 0, 0,
                                SEARCH_PARTITION);
     thread_data->td->pc_root = NULL;
+    av1_dealloc_mb_wiener_var_pred_buf(thread_data->td);
     aom_free(thread_data->td);
   }
 }
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index 2bb546f..b878797 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -196,7 +196,7 @@
 }
 
 // Deallocate row based multi-threading synchronization related mutex and data
-static void row_mt_sync_mem_dealloc(AV1EncRowMultiThreadSync *row_mt_sync) {
+void av1_row_mt_sync_mem_dealloc(AV1EncRowMultiThreadSync *row_mt_sync) {
   if (row_mt_sync != NULL) {
 #if CONFIG_MULTITHREAD
     int i;
@@ -282,7 +282,7 @@
       int tile_index = tile_row * tile_cols + tile_col;
       TileDataEnc *const this_tile = &cpi->tile_data[tile_index];
 
-      row_mt_sync_mem_dealloc(&this_tile->row_mt_sync);
+      av1_row_mt_sync_mem_dealloc(&this_tile->row_mt_sync);
 
       if (cpi->oxcf.algo_cfg.cdf_update_mode) aom_free(this_tile->row_ctx);
     }
@@ -2696,6 +2696,7 @@
 
     if (thread_data->td != &cpi->td) {
       thread_data->td->mb = cpi->td.mb;
+      av1_alloc_mb_wiener_var_pred_buf(&cpi->common, thread_data->td);
     }
   }
 }
@@ -2737,7 +2738,8 @@
     // TODO(chengchen): properly accumulate the distortion and rate.
     av1_calc_mb_wiener_var_row(cpi, x, xd, current_mi_row, src_diff, coeff,
                                qcoeff, dqcoeff, &sum_rec_distortion,
-                               &sum_est_rate);
+                               &sum_est_rate,
+                               thread_data->td->wiener_tmp_pred_buf);
 #if CONFIG_MULTITHREAD
     pthread_mutex_lock(enc_row_mt_mutex_);
 #endif
@@ -2749,6 +2751,17 @@
   return 1;
 }
 
+static void dealloc_mb_wiener_var_mt_data(AV1_COMP *cpi, int num_workers) {
+  av1_row_mt_sync_mem_dealloc(&cpi->ppi->intra_row_mt_sync);
+
+  MultiThreadInfo *mt_info = &cpi->mt_info;
+  for (int j = 0; j < num_workers; ++j) {
+    EncWorkerData *thread_data = &mt_info->tile_thr_data[j];
+    ThreadData *td = thread_data->td;
+    if (td != &cpi->td) av1_dealloc_mb_wiener_var_pred_buf(td);
+  }
+}
+
 // This function is the multi-threading version of computing the wiener
 // variance.
 // Note that the wiener variance is used for allintra mode (1 pass) and its
@@ -2778,8 +2791,7 @@
   prepare_wiener_var_workers(cpi, cal_mb_wiener_var_hook, num_workers);
   launch_workers(mt_info, num_workers);
   sync_enc_workers(mt_info, cm, num_workers);
-
-  row_mt_sync_mem_dealloc(intra_row_mt_sync);
+  dealloc_mb_wiener_var_mt_data(cpi, num_workers);
 }
 
 // Compare and order tiles based on absolute sum of tx coeffs.
diff --git a/av1/encoder/ethread.h b/av1/encoder/ethread.h
index fc9150c..4f4c232 100644
--- a/av1/encoder/ethread.h
+++ b/av1/encoder/ethread.h
@@ -53,6 +53,8 @@
 
 void av1_row_mt_mem_dealloc(AV1_COMP *cpi);
 
+void av1_row_mt_sync_mem_dealloc(AV1EncRowMultiThreadSync *row_mt_sync);
+
 void av1_global_motion_estimation_mt(AV1_COMP *cpi);
 
 #if !CONFIG_REALTIME_ONLY