Add tiled version of UV wiener restoration

Slight improvement in midres and hdres sets of 0.02% and 0.0.9%
respectively.

This is also a better design anyways.

Change-Id: I15b60b8836070a2132641e5b1d8e9f68df426c08
diff --git a/av1/common/restoration.c b/av1/common/restoration.c
index 8228170..50a1eec 100644
--- a/av1/common/restoration.c
+++ b/av1/common/restoration.c
@@ -146,7 +146,7 @@
   DECLARE_ALIGNED(16, InterpKernel, hkernel);
   DECLARE_ALIGNED(16, InterpKernel, vkernel);
 
-  if (rst->rsi->wiener_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                    dst_stride);
     return;
@@ -632,7 +632,7 @@
   int h_start, h_end, v_start, v_end;
   uint8_t *data_p, *dst_p;
 
-  if (rst->rsi->sgrproj_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                    dst_stride);
     return;
@@ -791,7 +791,7 @@
   int h_start, h_end, v_start, v_end;
   int32_t *tmpbuf = (int32_t *)rst->tmpbuf;
 
-  if (rst->rsi->domaintxfmrf_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                    dst_stride);
     return;
@@ -886,7 +886,7 @@
   DECLARE_ALIGNED(16, InterpKernel, hkernel);
   DECLARE_ALIGNED(16, InterpKernel, vkernel);
 
-  if (rst->rsi->wiener_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                           dst_stride);
     return;
@@ -979,7 +979,7 @@
   int h_start, h_end, v_start, v_end;
   uint16_t *data_p, *dst_p;
 
-  if (rst->rsi->sgrproj_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                           dst_stride);
     return;
@@ -1109,7 +1109,7 @@
   int h_start, h_end, v_start, v_end;
   int32_t *tmpbuf = (int32_t *)rst->tmpbuf;
 
-  if (rst->rsi->domaintxfmrf_info[tile_idx].level == 0) {
+  if (rst->rsi->restoration_type[tile_idx] == RESTORE_NONE) {
     loop_copy_tile_highbd(data, tile_idx, 0, 0, width, height, stride, rst, dst,
                           dst_stride);
     return;
diff --git a/av1/common/restoration.h b/av1/common/restoration.h
index cb596c6..ecc6276 100644
--- a/av1/common/restoration.h
+++ b/av1/common/restoration.h
@@ -114,10 +114,7 @@
 // Max of SGRPROJ_EXTBUF_SIZE, DOMAINTXFMRF_EXTBUF_SIZE, WIENER_EXTBUF_SIZE
 #define RESTORATION_EXTBUF_SIZE (DOMAINTXFMRF_EXTBUF_SIZE)
 
-typedef struct {
-  int level;
-  int vfilter[WIENER_WIN], hfilter[WIENER_WIN];
-} WienerInfo;
+typedef struct { int vfilter[WIENER_WIN], hfilter[WIENER_WIN]; } WienerInfo;
 
 typedef struct {
   int r1;
@@ -127,15 +124,11 @@
 } sgr_params_type;
 
 typedef struct {
-  int level;
   int ep;
   int xqd[2];
 } SgrprojInfo;
 
-typedef struct {
-  int level;
-  int sigma_r;
-} DomaintxfmrfInfo;
+typedef struct { int sigma_r; } DomaintxfmrfInfo;
 
 typedef struct {
   RestorationType frame_restoration_type;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index b946ddb..cf0d4d5 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2359,7 +2359,7 @@
   const int ntiles =
       av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
   const int ntiles_uv = av1_get_rest_ntiles(cm->width >> cm->subsampling_x,
-                                            cm->height >> cm->subsampling_x,
+                                            cm->height >> cm->subsampling_y,
                                             NULL, NULL, NULL, NULL);
   RestorationInfo *rsi = &cm->rst_info[0];
   if (rsi->frame_restoration_type != RESTORE_NONE) {
@@ -2369,13 +2369,10 @@
             aom_read_tree(rb, av1_switchable_restore_tree,
                           cm->fc->switchable_restore_prob, ACCT_STR);
         if (rsi->restoration_type[i] == RESTORE_WIENER) {
-          rsi->wiener_info[i].level = 1;
           read_wiener_filter(&rsi->wiener_info[i], rb);
         } else if (rsi->restoration_type[i] == RESTORE_SGRPROJ) {
-          rsi->sgrproj_info[i].level = 1;
           read_sgrproj_filter(&rsi->sgrproj_info[i], rb);
         } else if (rsi->restoration_type[i] == RESTORE_DOMAINTXFMRF) {
-          rsi->domaintxfmrf_info[i].level = 1;
           read_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], rb);
         }
       }
@@ -2383,10 +2380,8 @@
       for (i = 0; i < ntiles; ++i) {
         if (aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
           rsi->restoration_type[i] = RESTORE_WIENER;
-          rsi->wiener_info[i].level = 1;
           read_wiener_filter(&rsi->wiener_info[i], rb);
         } else {
-          rsi->wiener_info[i].level = 0;
           rsi->restoration_type[i] = RESTORE_NONE;
         }
       }
@@ -2394,10 +2389,8 @@
       for (i = 0; i < ntiles; ++i) {
         if (aom_read(rb, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)) {
           rsi->restoration_type[i] = RESTORE_SGRPROJ;
-          rsi->sgrproj_info[i].level = 1;
           read_sgrproj_filter(&rsi->sgrproj_info[i], rb);
         } else {
-          rsi->sgrproj_info[i].level = 0;
           rsi->restoration_type[i] = RESTORE_NONE;
         }
       }
@@ -2405,10 +2398,8 @@
       for (i = 0; i < ntiles; ++i) {
         if (aom_read(rb, RESTORE_NONE_DOMAINTXFMRF_PROB, ACCT_STR)) {
           rsi->restoration_type[i] = RESTORE_DOMAINTXFMRF;
-          rsi->domaintxfmrf_info[i].level = 1;
           read_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], rb);
         } else {
-          rsi->domaintxfmrf_info[i].level = 0;
           rsi->restoration_type[i] = RESTORE_NONE;
         }
       }
@@ -2417,13 +2408,16 @@
   for (p = 1; p < MAX_MB_PLANE; ++p) {
     rsi = &cm->rst_info[p];
     if (rsi->frame_restoration_type == RESTORE_WIENER) {
-      rsi->restoration_type[0] = RESTORE_WIENER;
-      rsi->wiener_info[0].level = 1;
-      read_wiener_filter(&rsi->wiener_info[0], rb);
-      for (i = 1; i < ntiles_uv; ++i) {
-        rsi->restoration_type[i] = RESTORE_WIENER;
-        memcpy(&rsi->wiener_info[i], &rsi->wiener_info[0],
-               sizeof(rsi->wiener_info[0]));
+      for (i = 0; i < ntiles_uv; ++i) {
+        if (ntiles_uv > 1)
+          rsi->restoration_type[i] =
+              aom_read(rb, RESTORE_NONE_WIENER_PROB, ACCT_STR) ? RESTORE_WIENER
+                                                               : RESTORE_NONE;
+        else
+          rsi->restoration_type[i] = RESTORE_WIENER;
+        if (rsi->restoration_type[i] == RESTORE_WIENER) {
+          read_wiener_filter(&rsi->wiener_info[i], rb);
+        }
       }
     }
   }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index ae2c36e..a047a90 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -3088,6 +3088,9 @@
   int i, p;
   const int ntiles =
       av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
+  const int ntiles_uv = av1_get_rest_ntiles(cm->width >> cm->subsampling_x,
+                                            cm->height >> cm->subsampling_y,
+                                            NULL, NULL, NULL, NULL);
   RestorationInfo *rsi = &cm->rst_info[0];
   if (rsi->frame_restoration_type != RESTORE_NONE) {
     if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
@@ -3106,24 +3109,25 @@
       }
     } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
       for (i = 0; i < ntiles; ++i) {
-        aom_write(wb, rsi->wiener_info[i].level != 0, RESTORE_NONE_WIENER_PROB);
-        if (rsi->wiener_info[i].level) {
+        aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
+                  RESTORE_NONE_WIENER_PROB);
+        if (rsi->restoration_type[i] != RESTORE_NONE) {
           write_wiener_filter(&rsi->wiener_info[i], wb);
         }
       }
     } else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
       for (i = 0; i < ntiles; ++i) {
-        aom_write(wb, rsi->sgrproj_info[i].level != 0,
+        aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
                   RESTORE_NONE_SGRPROJ_PROB);
-        if (rsi->sgrproj_info[i].level) {
+        if (rsi->restoration_type[i] != RESTORE_NONE) {
           write_sgrproj_filter(&rsi->sgrproj_info[i], wb);
         }
       }
     } else if (rsi->frame_restoration_type == RESTORE_DOMAINTXFMRF) {
       for (i = 0; i < ntiles; ++i) {
-        aom_write(wb, rsi->domaintxfmrf_info[i].level != 0,
+        aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
                   RESTORE_NONE_DOMAINTXFMRF_PROB);
-        if (rsi->domaintxfmrf_info[i].level) {
+        if (rsi->restoration_type[i] != RESTORE_NONE) {
           write_domaintxfmrf_filter(&rsi->domaintxfmrf_info[i], wb);
         }
       }
@@ -3132,7 +3136,14 @@
   for (p = 1; p < MAX_MB_PLANE; ++p) {
     rsi = &cm->rst_info[p];
     if (rsi->frame_restoration_type == RESTORE_WIENER) {
-      write_wiener_filter(&rsi->wiener_info[0], wb);
+      for (i = 0; i < ntiles_uv; ++i) {
+        if (ntiles_uv > 1)
+          aom_write(wb, rsi->restoration_type[i] != RESTORE_NONE,
+                    RESTORE_NONE_WIENER_PROB);
+        if (rsi->restoration_type[i] != RESTORE_NONE) {
+          write_wiener_filter(&rsi->wiener_info[i], wb);
+        }
+      }
     } else if (rsi->frame_restoration_type != RESTORE_NONE) {
       assert(0);
     }
diff --git a/av1/encoder/pickrst.c b/av1/encoder/pickrst.c
index f8a374e..8de1bd4 100644
--- a/av1/encoder/pickrst.c
+++ b/av1/encoder/pickrst.c
@@ -33,6 +33,7 @@
 typedef double (*search_restore_type)(const YV12_BUFFER_CONFIG *src,
                                       AV1_COMP *cpi, int filter_level,
                                       int partial_frame, RestorationInfo *info,
+                                      RestorationType *rest_level,
                                       double *best_tile_cost,
                                       YV12_BUFFER_CONFIG *dst_frame);
 
@@ -327,7 +328,8 @@
 
 static double search_sgrproj(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                              int filter_level, int partial_frame,
-                             RestorationInfo *info, double *best_tile_cost,
+                             RestorationInfo *info, RestorationType *type,
+                             double *best_tile_cost,
                              YV12_BUFFER_CONFIG *dst_frame) {
   SgrprojInfo *sgrproj_info = info->sgrproj_info;
   double err, cost_norestore, cost_sgrproj;
@@ -349,8 +351,9 @@
 
   rsi->frame_restoration_type = RESTORE_SGRPROJ;
 
-  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
-    rsi->sgrproj_info[tile_idx].level = 0;
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
+  }
   // Compute best Sgrproj filters for each tile
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
     av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
@@ -373,15 +376,16 @@
 #endif  // CONFIG_AOM_HIGHBITDEPTH
         &rsi->sgrproj_info[tile_idx].ep, rsi->sgrproj_info[tile_idx].xqd,
         cm->rst_internal.tmpbuf);
-    rsi->sgrproj_info[tile_idx].level = 1;
+    rsi->restoration_type[tile_idx] = RESTORE_SGRPROJ;
     err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
                                dst_frame);
     bits = SGRPROJ_BITS << AV1_PROB_COST_SHIFT;
     bits += av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, 1);
     cost_sgrproj = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
     if (cost_sgrproj >= cost_norestore) {
-      sgrproj_info[tile_idx].level = 0;
+      type[tile_idx] = RESTORE_NONE;
     } else {
+      type[tile_idx] = RESTORE_SGRPROJ;
       memcpy(&sgrproj_info[tile_idx], &rsi->sgrproj_info[tile_idx],
              sizeof(sgrproj_info[tile_idx]));
       bits = SGRPROJ_BITS << AV1_PROB_COST_SHIFT;
@@ -389,19 +393,20 @@
           x->rdmult, x->rddiv,
           (bits + cpi->switchable_restore_cost[RESTORE_SGRPROJ]) >> 4, err);
     }
-    rsi->sgrproj_info[tile_idx].level = 0;
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
   }
   // Cost for Sgrproj filtering
   bits = frame_level_restore_bits[rsi->frame_restoration_type]
          << AV1_PROB_COST_SHIFT;
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
     bits +=
-        av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, sgrproj_info[tile_idx].level);
+        av1_cost_bit(RESTORE_NONE_SGRPROJ_PROB, type[tile_idx] != RESTORE_NONE);
     memcpy(&rsi->sgrproj_info[tile_idx], &sgrproj_info[tile_idx],
            sizeof(sgrproj_info[tile_idx]));
-    if (sgrproj_info[tile_idx].level) {
+    if (type[tile_idx] == RESTORE_SGRPROJ) {
       bits += (SGRPROJ_BITS << AV1_PROB_COST_SHIFT);
     }
+    rsi->restoration_type[tile_idx] = type[tile_idx];
   }
   err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
   cost_sgrproj = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -543,7 +548,8 @@
 
 static double search_domaintxfmrf(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                                   int filter_level, int partial_frame,
-                                  RestorationInfo *info, double *best_tile_cost,
+                                  RestorationInfo *info, RestorationType *type,
+                                  double *best_tile_cost,
                                   YV12_BUFFER_CONFIG *dst_frame) {
   DomaintxfmrfInfo *domaintxfmrf_info = info->domaintxfmrf_info;
   double cost_norestore, cost_domaintxfmrf;
@@ -565,8 +571,9 @@
 
   rsi->frame_restoration_type = RESTORE_DOMAINTXFMRF;
 
-  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
-    rsi->domaintxfmrf_info[tile_idx].level = 0;
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
+  }
   // Compute best Domaintxfm filters for each tile
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
     av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
@@ -591,15 +598,16 @@
         &rsi->domaintxfmrf_info[tile_idx].sigma_r, cpi->extra_rstbuf,
         cm->rst_internal.tmpbuf);
 
-    rsi->domaintxfmrf_info[tile_idx].level = 1;
+    rsi->restoration_type[tile_idx] = RESTORE_DOMAINTXFMRF;
     err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
                                dst_frame);
     bits = DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT;
     bits += av1_cost_bit(RESTORE_NONE_DOMAINTXFMRF_PROB, 1);
     cost_domaintxfmrf = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
     if (cost_domaintxfmrf >= cost_norestore) {
-      domaintxfmrf_info[tile_idx].level = 0;
+      type[tile_idx] = RESTORE_NONE;
     } else {
+      type[tile_idx] = RESTORE_DOMAINTXFMRF;
       memcpy(&domaintxfmrf_info[tile_idx], &rsi->domaintxfmrf_info[tile_idx],
              sizeof(domaintxfmrf_info[tile_idx]));
       bits = DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT;
@@ -608,19 +616,20 @@
           (bits + cpi->switchable_restore_cost[RESTORE_DOMAINTXFMRF]) >> 4,
           err);
     }
-    rsi->domaintxfmrf_info[tile_idx].level = 0;
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
   }
   // Cost for Domaintxfmrf filtering
   bits = frame_level_restore_bits[rsi->frame_restoration_type]
          << AV1_PROB_COST_SHIFT;
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
     bits += av1_cost_bit(RESTORE_NONE_DOMAINTXFMRF_PROB,
-                         domaintxfmrf_info[tile_idx].level);
+                         type[tile_idx] != RESTORE_NONE);
     memcpy(&rsi->domaintxfmrf_info[tile_idx], &domaintxfmrf_info[tile_idx],
            sizeof(domaintxfmrf_info[tile_idx]));
-    if (domaintxfmrf_info[tile_idx].level) {
+    if (type[tile_idx] == RESTORE_DOMAINTXFMRF) {
       bits += (DOMAINTXFMRF_PARAMS_BITS << AV1_PROB_COST_SHIFT);
     }
+    rsi->restoration_type[tile_idx] = type[tile_idx];
   }
   err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
   cost_domaintxfmrf = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -942,14 +951,14 @@
 
 static double search_wiener_uv(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                                int filter_level, int partial_frame, int plane,
-                               RestorationInfo *info,
+                               RestorationInfo *info, RestorationType *type,
                                YV12_BUFFER_CONFIG *dst_frame) {
   WienerInfo *wiener_info = info->wiener_info;
   AV1_COMMON *const cm = &cpi->common;
   RestorationInfo *rsi = cpi->rst_search;
   int64_t err;
   int bits;
-  double cost_wiener = 0, cost_norestore = 0;
+  double cost_wiener, cost_norestore, cost_wiener_frame, cost_norestore_frame;
   MACROBLOCK *x = &cpi->td.mb;
   double M[WIENER_WIN2];
   double H[WIENER_WIN2 * WIENER_WIN2];
@@ -961,9 +970,9 @@
   const int dgd_stride = dgd->uv_stride;
   double score;
   int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
+  int h_start, h_end, v_start, v_end;
   const int ntiles = av1_get_rest_ntiles(width, height, &tile_width,
                                          &tile_height, &nhtiles, &nvtiles);
-
   assert(width == dgd->uv_crop_width);
   assert(height == dgd->uv_crop_height);
 
@@ -978,100 +987,123 @@
   aom_yv12_copy_v(cm->frame_to_show, &cpi->last_frame_db);
 
   rsi[plane].frame_restoration_type = RESTORE_NONE;
-
   err = sse_restoration_frame(src, cm->frame_to_show, (1 << plane));
   bits = 0;
-  cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+  cost_norestore_frame = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
 
   rsi[plane].frame_restoration_type = RESTORE_WIENER;
 
-#if CONFIG_AOM_HIGHBITDEPTH
-  if (cm->use_highbitdepth) {
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
+  }
+
+  // Compute best Wiener filters for each tile
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
+                             tile_height, width, height, 0, 0, &h_start, &h_end,
+                             &v_start, &v_end);
+    err = sse_restoration_tile(src, cm->frame_to_show, cm, h_start,
+                               h_end - h_start, v_start, v_end - v_start,
+                               1 << plane);
+    // #bits when a tile is not restored
+    bits = av1_cost_bit(RESTORE_NONE_WIENER_PROB, 0);
+    cost_norestore = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+    // best_tile_cost[tile_idx] = DBL_MAX;
+
+    av1_get_rest_tile_limits(tile_idx, 0, 0, nhtiles, nvtiles, tile_width,
+                             tile_height, width, height, WIENER_HALFWIN,
+                             WIENER_HALFWIN, &h_start, &h_end, &v_start,
+                             &v_end);
     if (plane == AOM_PLANE_U) {
-      extend_frame_highbd(CONVERT_TO_SHORTPTR(dgd->u_buffer), width, height,
-                          dgd_stride);
-      compute_stats_highbd(dgd->u_buffer, src->u_buffer, 0, width, 0, height,
-                           dgd_stride, src_stride, M, H);
+#if CONFIG_AOM_HIGHBITDEPTH
+      if (cm->use_highbitdepth)
+        compute_stats_highbd(dgd->u_buffer, src->u_buffer, h_start, h_end,
+                             v_start, v_end, dgd_stride, src_stride, M, H);
+      else
+#endif  // CONFIG_AOM_HIGHBITDEPTH
+        compute_stats(dgd->u_buffer, src->u_buffer, h_start, h_end, v_start,
+                      v_end, dgd_stride, src_stride, M, H);
     } else if (plane == AOM_PLANE_V) {
-      extend_frame_highbd(CONVERT_TO_SHORTPTR(dgd->v_buffer), width, height,
-                          dgd_stride);
-      compute_stats_highbd(dgd->v_buffer, src->v_buffer, 0, width, 0, height,
-                           dgd_stride, src_stride, M, H);
+#if CONFIG_AOM_HIGHBITDEPTH
+      if (cm->use_highbitdepth)
+        compute_stats_highbd(dgd->v_buffer, src->v_buffer, h_start, h_end,
+                             v_start, v_end, dgd_stride, src_stride, M, H);
+      else
+#endif  // CONFIG_AOM_HIGHBITDEPTH
+        compute_stats(dgd->v_buffer, src->v_buffer, h_start, h_end, v_start,
+                      v_end, dgd_stride, src_stride, M, H);
     } else {
       assert(0);
     }
-  } else {
-#endif
-    if (plane == AOM_PLANE_U) {
-      extend_frame(dgd->u_buffer, width, height, dgd_stride);
-      compute_stats(dgd->u_buffer, src->u_buffer, 0, width, 0, height,
-                    dgd_stride, src_stride, M, H);
-    } else if (plane == AOM_PLANE_V) {
-      extend_frame(dgd->v_buffer, width, height, dgd_stride);
-      compute_stats(dgd->v_buffer, src->v_buffer, 0, width, 0, height,
-                    dgd_stride, src_stride, M, H);
-    } else {
-      assert(0);
+
+    type[tile_idx] = RESTORE_WIENER;
+
+    if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
+      type[tile_idx] = RESTORE_NONE;
+      continue;
     }
-#if CONFIG_AOM_HIGHBITDEPTH
-  }
-#endif
+    quantize_sym_filter(vfilterd, rsi[plane].wiener_info[tile_idx].vfilter);
+    quantize_sym_filter(hfilterd, rsi[plane].wiener_info[tile_idx].hfilter);
 
-  if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
-    info->frame_restoration_type = RESTORE_NONE;
-    aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
-    return cost_norestore;
-  }
-  quantize_sym_filter(vfilterd, rsi[plane].wiener_info[0].vfilter);
-  quantize_sym_filter(hfilterd, rsi[plane].wiener_info[0].hfilter);
+    // Filter score computes the value of the function x'*A*x - x'*b for the
+    // learned filter and compares it against identity filer. If there is no
+    // reduction in the function, the filter is reverted back to identity
+    score = compute_score(M, H, rsi[plane].wiener_info[tile_idx].vfilter,
+                          rsi[plane].wiener_info[tile_idx].hfilter);
+    if (score > 0.0) {
+      type[tile_idx] = RESTORE_NONE;
+      continue;
+    }
 
-  // Filter score computes the value of the function x'*A*x - x'*b for the
-  // learned filter and compares it against identity filer. If there is no
-  // reduction in the function, the filter is reverted back to identity
-  score = compute_score(M, H, rsi[plane].wiener_info[0].vfilter,
-                        rsi[plane].wiener_info[0].hfilter);
-  if (score > 0.0) {
-    info->frame_restoration_type = RESTORE_NONE;
-    aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
-    return cost_norestore;
+    rsi[plane].restoration_type[tile_idx] = RESTORE_WIENER;
+    err = try_restoration_tile(src, cpi, rsi, 1 << plane, partial_frame,
+                               tile_idx, 0, 0, dst_frame);
+    bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
+    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, 1);
+    cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+    if (cost_wiener >= cost_norestore) {
+      type[tile_idx] = RESTORE_NONE;
+    } else {
+      type[tile_idx] = RESTORE_WIENER;
+      memcpy(&wiener_info[tile_idx], &rsi[plane].wiener_info[tile_idx],
+             sizeof(wiener_info[tile_idx]));
+    }
+    rsi[plane].restoration_type[tile_idx] = RESTORE_NONE;
   }
-
-  info->frame_restoration_type = RESTORE_WIENER;
-  rsi[plane].restoration_type[0] = info->restoration_type[0] = RESTORE_WIENER;
-  rsi[plane].wiener_info[0].level = 1;
-  memcpy(&wiener_info[0], &rsi[plane].wiener_info[0], sizeof(wiener_info[0]));
-  for (tile_idx = 1; tile_idx < ntiles; ++tile_idx) {
-    info->restoration_type[tile_idx] = RESTORE_WIENER;
-    memcpy(&rsi[plane].wiener_info[tile_idx], &rsi[plane].wiener_info[0],
-           sizeof(rsi[plane].wiener_info[0]));
-    memcpy(&wiener_info[tile_idx], &rsi[plane].wiener_info[0],
-           sizeof(rsi[plane].wiener_info[0]));
+  aom_yv12_copy_frame(&cpi->last_frame_db, cm->frame_to_show);
+  // Cost for Wiener filtering
+  bits = 0;
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    bits +=
+        av1_cost_bit(RESTORE_NONE_WIENER_PROB, type[tile_idx] != RESTORE_NONE);
+    memcpy(&rsi[plane].wiener_info[tile_idx], &wiener_info[tile_idx],
+           sizeof(wiener_info[tile_idx]));
+    if (type[tile_idx] == RESTORE_WIENER) {
+      bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
+    }
+    rsi[plane].restoration_type[tile_idx] = type[tile_idx];
   }
-  err = try_restoration_frame(src, cpi, rsi, (1 << plane), partial_frame,
+  err = try_restoration_frame(src, cpi, rsi, 1 << plane, partial_frame,
                               dst_frame);
-  bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
-  cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
-  if (cost_wiener > cost_norestore) {
+  cost_wiener_frame = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
+
+  if (cost_wiener_frame < cost_norestore_frame) {
+    info->frame_restoration_type = RESTORE_WIENER;
+  } else {
     info->frame_restoration_type = RESTORE_NONE;
-    aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
-    aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
-    return cost_norestore;
   }
 
   aom_yv12_copy_y(&cpi->last_frame_uf, cm->frame_to_show);
   aom_yv12_copy_u(&cpi->last_frame_uf, cm->frame_to_show);
   aom_yv12_copy_v(&cpi->last_frame_uf, cm->frame_to_show);
-  return cost_wiener;
+  return info->frame_restoration_type == RESTORE_WIENER ? cost_wiener_frame
+                                                        : cost_norestore_frame;
 }
 
 static double search_wiener(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                             int filter_level, int partial_frame,
-                            RestorationInfo *info, double *best_tile_cost,
+                            RestorationInfo *info, RestorationType *type,
+                            double *best_tile_cost,
                             YV12_BUFFER_CONFIG *dst_frame) {
   WienerInfo *wiener_info = info->wiener_info;
   AV1_COMMON *const cm = &cpi->common;
@@ -1091,7 +1123,6 @@
   double score;
   int tile_idx, tile_width, tile_height, nhtiles, nvtiles;
   int h_start, h_end, v_start, v_end;
-  int i;
   const int ntiles = av1_get_rest_ntiles(width, height, &tile_width,
                                          &tile_height, &nhtiles, &nvtiles);
   assert(width == dgd->y_crop_width);
@@ -1107,8 +1138,9 @@
 
   rsi->frame_restoration_type = RESTORE_WIENER;
 
-  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx)
-    rsi->wiener_info[tile_idx].level = 0;
+  for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
+  }
 
 // Construct a (WIENER_HALFWIN)-pixel border around the frame
 #if CONFIG_AOM_HIGHBITDEPTH
@@ -1143,9 +1175,10 @@
       compute_stats(dgd->y_buffer, src->y_buffer, h_start, h_end, v_start,
                     v_end, dgd_stride, src_stride, M, H);
 
-    wiener_info[tile_idx].level = 1;
+    type[tile_idx] = RESTORE_WIENER;
+
     if (!wiener_decompose_sep_sym(M, H, vfilterd, hfilterd)) {
-      wiener_info[tile_idx].level = 0;
+      type[tile_idx] = RESTORE_NONE;
       continue;
     }
     quantize_sym_filter(vfilterd, rsi->wiener_info[tile_idx].vfilter);
@@ -1157,48 +1190,41 @@
     score = compute_score(M, H, rsi->wiener_info[tile_idx].vfilter,
                           rsi->wiener_info[tile_idx].hfilter);
     if (score > 0.0) {
-      wiener_info[tile_idx].level = 0;
+      type[tile_idx] = RESTORE_NONE;
       continue;
     }
 
-    rsi->wiener_info[tile_idx].level = 1;
+    rsi->restoration_type[tile_idx] = RESTORE_WIENER;
     err = try_restoration_tile(src, cpi, rsi, 1, partial_frame, tile_idx, 0, 0,
                                dst_frame);
     bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
     bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, 1);
     cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
     if (cost_wiener >= cost_norestore) {
-      wiener_info[tile_idx].level = 0;
+      type[tile_idx] = RESTORE_NONE;
     } else {
-      wiener_info[tile_idx].level = 1;
-      for (i = 0; i < WIENER_WIN; ++i) {
-        wiener_info[tile_idx].vfilter[i] =
-            rsi->wiener_info[tile_idx].vfilter[i];
-        wiener_info[tile_idx].hfilter[i] =
-            rsi->wiener_info[tile_idx].hfilter[i];
-      }
+      type[tile_idx] = RESTORE_WIENER;
+      memcpy(&wiener_info[tile_idx], &rsi->wiener_info[tile_idx],
+             sizeof(wiener_info[tile_idx]));
       bits = WIENER_FILT_BITS << AV1_PROB_COST_SHIFT;
       best_tile_cost[tile_idx] = RDCOST_DBL(
           x->rdmult, x->rddiv,
           (bits + cpi->switchable_restore_cost[RESTORE_WIENER]) >> 4, err);
     }
-    rsi->wiener_info[tile_idx].level = 0;
+    rsi->restoration_type[tile_idx] = RESTORE_NONE;
   }
   // Cost for Wiener filtering
   bits = frame_level_restore_bits[rsi->frame_restoration_type]
          << AV1_PROB_COST_SHIFT;
   for (tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
-    bits += av1_cost_bit(RESTORE_NONE_WIENER_PROB, wiener_info[tile_idx].level);
-    rsi->wiener_info[tile_idx].level = wiener_info[tile_idx].level;
-    if (wiener_info[tile_idx].level) {
+    bits +=
+        av1_cost_bit(RESTORE_NONE_WIENER_PROB, type[tile_idx] != RESTORE_NONE);
+    memcpy(&rsi->wiener_info[tile_idx], &wiener_info[tile_idx],
+           sizeof(wiener_info[tile_idx]));
+    if (type[tile_idx] == RESTORE_WIENER) {
       bits += (WIENER_FILT_BITS << AV1_PROB_COST_SHIFT);
-      for (i = 0; i < WIENER_WIN; ++i) {
-        rsi->wiener_info[tile_idx].vfilter[i] =
-            wiener_info[tile_idx].vfilter[i];
-        rsi->wiener_info[tile_idx].hfilter[i] =
-            wiener_info[tile_idx].hfilter[i];
-      }
     }
+    rsi->restoration_type[tile_idx] = type[tile_idx];
   }
   err = try_restoration_frame(src, cpi, rsi, 1, partial_frame, dst_frame);
   cost_wiener = RDCOST_DBL(x->rdmult, x->rddiv, (bits >> 4), err);
@@ -1209,7 +1235,8 @@
 
 static double search_norestore(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
                                int filter_level, int partial_frame,
-                               RestorationInfo *info, double *best_tile_cost,
+                               RestorationInfo *info, RestorationType *type,
+                               double *best_tile_cost,
                                YV12_BUFFER_CONFIG *dst_frame) {
   double err, cost_norestore;
   int bits;
@@ -1237,6 +1264,7 @@
     best_tile_cost[tile_idx] =
         RDCOST_DBL(x->rdmult, x->rddiv,
                    (cpi->switchable_restore_cost[RESTORE_NONE] >> 4), err);
+    type[tile_idx] = RESTORE_NONE;
   }
   // RD cost associated with no restoration
   err = sse_restoration_tile(src, cm->frame_to_show, cm, 0, cm->width, 0,
@@ -1291,14 +1319,18 @@
   struct loopfilter *const lf = &cm->lf;
   double cost_restore[RESTORE_TYPES];
   double *tile_cost[RESTORE_SWITCHABLE_TYPES];
+  RestorationType *restore_types[RESTORE_SWITCHABLE_TYPES];
   double best_cost_restore;
   RestorationType r, best_restore;
 
   const int ntiles =
       av1_get_rest_ntiles(cm->width, cm->height, NULL, NULL, NULL, NULL);
 
-  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++)
+  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) {
     tile_cost[r] = (double *)aom_malloc(sizeof(*tile_cost[0]) * ntiles);
+    restore_types[r] =
+        (RestorationType *)aom_malloc(sizeof(*restore_types[0]) * ntiles);
+  }
 
   lf->sharpness_level = cm->frame_type == KEY_FRAME ? 0 : cpi->oxcf.sharpness;
 
@@ -1342,7 +1374,8 @@
   for (r = 0; r < RESTORE_SWITCHABLE_TYPES; ++r) {
     cost_restore[r] = search_restore_fun[r](
         src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
-        &cm->rst_info[0], tile_cost[r], &cpi->trial_frame_rst);
+        &cm->rst_info[0], restore_types[r], tile_cost[r],
+        &cpi->trial_frame_rst);
   }
   cost_restore[RESTORE_SWITCHABLE] = search_switchable_restoration(
       cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE, &cm->rst_info[0],
@@ -1357,13 +1390,19 @@
     }
   }
   cm->rst_info[0].frame_restoration_type = best_restore;
+  if (best_restore != RESTORE_SWITCHABLE) {
+    memcpy(cm->rst_info[0].restoration_type, restore_types[best_restore],
+           ntiles * sizeof(restore_types[best_restore][0]));
+  }
 
   // Color components
   search_wiener_uv(src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
                    AOM_PLANE_U, &cm->rst_info[AOM_PLANE_U],
+                   cm->rst_info[AOM_PLANE_U].restoration_type,
                    &cpi->trial_frame_rst);
   search_wiener_uv(src, cpi, lf->filter_level, method == LPF_PICK_FROM_SUBIMAGE,
                    AOM_PLANE_V, &cm->rst_info[AOM_PLANE_V],
+                   cm->rst_info[AOM_PLANE_V].restoration_type,
                    &cpi->trial_frame_rst);
   /*
   printf("Frame %d/%d restore types: %d %d %d\n",
@@ -1380,5 +1419,8 @@
          cost_restore[2], cost_restore[3], cost_restore[4]);
          */
 
-  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) aom_free(tile_cost[r]);
+  for (r = 0; r < RESTORE_SWITCHABLE_TYPES; r++) {
+    aom_free(tile_cost[r]);
+    aom_free(restore_types[r]);
+  }
 }