Expose av1_loop_restoration_filter_unit in restoration.h

This patch also does a certain amount of rejigging for loop
restoration coefficients, grouping the information for a given
restoration unit into a structure called RestorationUnitInfo. The end
result is to completely dispense with the RestorationInternal
structure.

The copy_tile functions in restoration.c, together with those
functions that operate on a single stripe, have been changed so that
they take pointers to the top-left corner of the area on which they
should work, together with a width and height.

The same isn't true of av1_loop_restoration_filter_unit, which still
takes pointers to the top-left of the tile. This is because you
actually need the absolute position in the tile in order to do striped
loop restoration properly.

Change-Id: I768c182cd15c9b2d6cfabb5ffca697cd2a3ff9e1
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c
index a7a2c5c..0bd26a7 100644
--- a/av1/common/alloccommon.c
+++ b/av1/common/alloccommon.c
@@ -162,8 +162,9 @@
     int buf_size = num_stripes * 2 * stride;
     uint8_t *above_buf, *below_buf;
 
-    aom_free(cm->rst_info[p].stripe_boundary_above);
-    aom_free(cm->rst_info[p].stripe_boundary_below);
+    RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries;
+    aom_free(boundaries->stripe_boundary_above);
+    aom_free(boundaries->stripe_boundary_below);
 
 #if CONFIG_HIGHBITDEPTH
     if (cm->use_highbitdepth) buf_size = buf_size * 2;
@@ -172,9 +173,9 @@
                     (uint8_t *)aom_memalign(1 << align_bits, buf_size));
     CHECK_MEM_ERROR(cm, below_buf,
                     (uint8_t *)aom_memalign(1 << align_bits, buf_size));
-    cm->rst_info[p].stripe_boundary_above = above_buf;
-    cm->rst_info[p].stripe_boundary_below = below_buf;
-    cm->rst_info[p].stripe_boundary_stride = stride;
+    boundaries->stripe_boundary_above = above_buf;
+    boundaries->stripe_boundary_below = below_buf;
+    boundaries->stripe_boundary_stride = stride;
   }
 #endif  // CONFIG_STRIPED_LOOP_RESTORATION
 }
diff --git a/av1/common/av1_rtcd_defs.pl b/av1/common/av1_rtcd_defs.pl
index 3f68091..59b9514 100755
--- a/av1/common/av1_rtcd_defs.pl
+++ b/av1/common/av1_rtcd_defs.pl
@@ -576,7 +576,7 @@
 # LOOP_RESTORATION functions
 
 if (aom_config("CONFIG_LOOP_RESTORATION") eq "yes") {
-  add_proto qw/void apply_selfguided_restoration/, "const uint8_t *dat, int width, int height, int stride, int eps, int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf";
+  add_proto qw/void apply_selfguided_restoration/, "const uint8_t *dat, int width, int height, int stride, int eps, const int *xqd, uint8_t *dst, int dst_stride, int32_t *tmpbuf";
   specialize qw/apply_selfguided_restoration sse4_1/;
 
   add_proto qw/void av1_selfguided_restoration/, "const uint8_t *dgd, int width, int height, int stride, int32_t *dst, int dst_stride, int r, int eps";
@@ -586,7 +586,7 @@
   specialize qw/av1_highpass_filter sse4_1/;
 
   if (aom_config("CONFIG_HIGHBITDEPTH") eq "yes") {
-    add_proto qw/void apply_selfguided_restoration_highbd/, "const uint16_t *dat, int width, int height, int stride, int bit_depth, int eps, int *xqd, uint16_t *dst, int dst_stride, int32_t *tmpbuf";
+    add_proto qw/void apply_selfguided_restoration_highbd/, "const uint16_t *dat, int width, int height, int stride, int bit_depth, int eps, const int *xqd, uint16_t *dst, int dst_stride, int32_t *tmpbuf";
     specialize qw/apply_selfguided_restoration_highbd sse4_1/;
 
     add_proto qw/void av1_selfguided_restoration_highbd/, "const uint16_t *dgd, int width, int height, int stride, int32_t *dst, int dst_stride, int bit_depth, int r, int eps";
diff --git a/av1/common/restoration.c b/av1/common/restoration.c
index 01a427f..d8b2e1d 100644
--- a/av1/common/restoration.c
+++ b/av1/common/restoration.c
@@ -45,53 +45,20 @@
 #endif
 };
 
-typedef struct {
-  RestorationInfo *rsi;
-  int keyframe;
-  int ntiles, nhtiles, nvtiles;
-#if CONFIG_HIGHBITDEPTH
-  int bit_depth;
-#endif
-  int subsampling_y;
-  int32_t *tmpbuf;
-#if CONFIG_STRIPED_LOOP_RESTORATION
-  // Temporary buffers to save/restore 2 lines above/below the restoration
-  // stripe
-  // Allow for filter margin to left and right
-  uint16_t
-      tmp_save_above[2][RESTORATION_TILESIZE_MAX + 2 * RESTORATION_EXTRA_HORZ];
-  uint16_t
-      tmp_save_below[2][RESTORATION_TILESIZE_MAX + 2 * RESTORATION_EXTRA_HORZ];
-#endif
-} RestorationInternal;
-
 int av1_alloc_restoration_struct(AV1_COMMON *cm, RestorationInfo *rst_info,
                                  int width, int height) {
   const int ntiles = av1_get_rest_ntiles(
       width, height, rst_info->restoration_tilesize, NULL, NULL);
-  aom_free(rst_info->restoration_type);
-  CHECK_MEM_ERROR(cm, rst_info->restoration_type,
-                  (RestorationType *)aom_malloc(
-                      sizeof(*rst_info->restoration_type) * ntiles));
-  aom_free(rst_info->wiener_info);
+  aom_free(rst_info->unit_info);
   CHECK_MEM_ERROR(
-      cm, rst_info->wiener_info,
-      (WienerInfo *)aom_memalign(16, sizeof(*rst_info->wiener_info) * ntiles));
-  memset(rst_info->wiener_info, 0, sizeof(*rst_info->wiener_info) * ntiles);
-  aom_free(rst_info->sgrproj_info);
-  CHECK_MEM_ERROR(
-      cm, rst_info->sgrproj_info,
-      (SgrprojInfo *)aom_malloc(sizeof(*rst_info->sgrproj_info) * ntiles));
+      cm, rst_info->unit_info,
+      (RestorationUnitInfo *)aom_malloc(sizeof(*rst_info->unit_info) * ntiles));
   return ntiles;
 }
 
 void av1_free_restoration_struct(RestorationInfo *rst_info) {
-  aom_free(rst_info->restoration_type);
-  rst_info->restoration_type = NULL;
-  aom_free(rst_info->wiener_info);
-  rst_info->wiener_info = NULL;
-  aom_free(rst_info->sgrproj_info);
-  rst_info->sgrproj_info = NULL;
+  aom_free(rst_info->unit_info);
+  rst_info->unit_info = NULL;
 }
 
 // TODO(debargha): This table can be substantially reduced since only a few
@@ -165,39 +132,32 @@
   extend_frame_lowbd(data, width, height, stride, border_horz, border_vert);
 }
 
-static void copy_tile_lowbd(const RestorationTileLimits *limits,
-                            const uint8_t *src, int src_stride, uint8_t *dst,
-                            int dst_stride) {
-  for (int i = limits->v_start; i < limits->v_end; ++i)
-    memcpy(dst + i * dst_stride + limits->h_start,
-           src + i * src_stride + limits->h_start,
-           limits->h_end - limits->h_start);
+static void copy_tile_lowbd(int width, int height, const uint8_t *src,
+                            int src_stride, uint8_t *dst, int dst_stride) {
+  for (int i = 0; i < height; ++i)
+    memcpy(dst + i * dst_stride, src + i * src_stride, width);
 }
 
 #if CONFIG_HIGHBITDEPTH
-static void copy_tile_highbd(const RestorationTileLimits *limits,
-                             const uint16_t *src, int src_stride, uint16_t *dst,
-                             int dst_stride) {
-  for (int i = limits->v_start; i < limits->v_end; ++i)
-    memcpy(dst + i * dst_stride + limits->h_start,
-           src + i * src_stride + limits->h_start,
-           (limits->h_end - limits->h_start) * sizeof(*dst));
+static void copy_tile_highbd(int width, int height, const uint16_t *src,
+                             int src_stride, uint16_t *dst, int dst_stride) {
+  for (int i = 0; i < height; ++i)
+    memcpy(dst + i * dst_stride, src + i * src_stride, width * sizeof(*dst));
 }
 #endif
 
-static void copy_tile(const RestorationTileLimits *limits, const uint8_t *src,
-                      int src_stride, uint8_t *dst, int dst_stride,
-                      int highbd) {
+static void copy_tile(int width, int height, const uint8_t *src, int src_stride,
+                      uint8_t *dst, int dst_stride, int highbd) {
 #if !CONFIG_HIGHBITDEPTH
   assert(highbd == 0);
   (void)highbd;
 #else
   if (highbd)
-    copy_tile_highbd(limits, CONVERT_TO_SHORTPTR(src), src_stride,
+    copy_tile_highbd(width, height, CONVERT_TO_SHORTPTR(src), src_stride,
                      CONVERT_TO_SHORTPTR(dst), dst_stride);
   else
 #endif
-  copy_tile_lowbd(limits, src, src_stride, dst, dst_stride);
+  copy_tile_lowbd(width, height, src, src_stride, dst, dst_stride);
 }
 
 #if CONFIG_STRIPED_LOOP_RESTORATION
@@ -214,23 +174,26 @@
 // restore_processing_stripe_boundary.
 //
 // limits gives the rectangular limits of the remaining stripes for the current
-// restoration unit.
-static int setup_processing_stripe_boundary(const RestorationTileLimits *limits,
-                                            uint8_t *data8, int stride,
-                                            RestorationInternal *rst,
-                                            int use_highbd) {
+// restoration unit. rsb is the stored stripe boundaries (the saved output from
+// the deblocker). stripe_height is the height of each stripe. ss_y is true if
+// we're on a chroma plane with vertical subsampling. use_highbd is true if the
+// data has 2 bytes per pixel. rlbs contain scratch buffers to hold the CDEF
+// data (written back to the frame by restore_processing_stripe_boundary)
+static int setup_processing_stripe_boundary(
+    const RestorationTileLimits *limits, const RestorationStripeBoundaries *rsb,
+    int stripe_height, int ss_y, int use_highbd, uint8_t *data8, int stride,
+    RestorationLineBuffers *rlbs) {
   // Which stripe is this? limits->v_start is the top of the stripe in pixel
   // units, but we add tile_offset to get the number of pixels from the top of
   // the first stripe, which lies off the image.
-  const int tile_offset = RESTORATION_TILE_OFFSET >> rst->subsampling_y;
-  const int stripe_height = rst->rsi->procunit_height;
+  const int tile_offset = RESTORATION_TILE_OFFSET >> ss_y;
   const int stripe_index = (limits->v_start + tile_offset) / stripe_height;
 
   // Horizontal offsets within the line buffers. The buffer logically starts at
   // column -RESTORATION_EXTRA_HORZ. We'll start our copy from the column
   // limits->h_start - RESTORATION_EXTRA_HORZ and copy up to the column
   // limits->h_end + RESTORATION_EXTRA_HORZ.
-  const int buf_stride = rst->rsi->stripe_boundary_stride;
+  const int buf_stride = rsb->stripe_boundary_stride;
   const int buf_x0_off = limits->h_start;
   const int line_width =
       (limits->h_end - limits->h_start) + 2 * RESTORATION_EXTRA_HORZ;
@@ -247,11 +210,10 @@
 
     for (int i = 0; i < 2; ++i) {
       const int buf_off = buf_x0_off + (above_buf_y + i) * buf_stride;
-      const uint8_t *src =
-          rst->rsi->stripe_boundary_above + (buf_off << use_highbd);
+      const uint8_t *src = rsb->stripe_boundary_above + (buf_off << use_highbd);
       uint8_t *dst8 = data8_tl + i * stride;
       // Save old pixels, then replace with data from boundary_above_buf
-      memcpy(rst->tmp_save_above[i], REAL_PTR(use_highbd, dst8), line_size);
+      memcpy(rlbs->tmp_save_above[i], REAL_PTR(use_highbd, dst8), line_size);
       memcpy(REAL_PTR(use_highbd, dst8), src, line_size);
     }
   }
@@ -268,11 +230,10 @@
 
   for (int i = 0; i < rows_needed_below; ++i) {
     const int buf_off = buf_x0_off + (below_buf_y + i) * buf_stride;
-    const uint8_t *src =
-        rst->rsi->stripe_boundary_below + (buf_off << use_highbd);
+    const uint8_t *src = rsb->stripe_boundary_below + (buf_off << use_highbd);
     uint8_t *dst8 = data8_bl + i * stride;
     // Save old pixels, then replace with data from boundary_below_buf
-    memcpy(rst->tmp_save_below[i], REAL_PTR(use_highbd, dst8), line_size);
+    memcpy(rlbs->tmp_save_below[i], REAL_PTR(use_highbd, dst8), line_size);
     memcpy(REAL_PTR(use_highbd, dst8), src, line_size);
   }
 
@@ -283,10 +244,9 @@
 // This function restores the boundary lines modified by
 // setup_processing_stripe_boundary.
 static void restore_processing_stripe_boundary(
-    const RestorationTileLimits *limits, const RestorationInternal *rst,
-    uint8_t *data8, int stride, int use_highbd) {
-  const int tile_offset = RESTORATION_TILE_OFFSET >> rst->subsampling_y;
-  const int stripe_height = rst->rsi->procunit_height;
+    const RestorationTileLimits *limits, const RestorationLineBuffers *rlbs,
+    int stripe_height, int ss_y, int use_highbd, uint8_t *data8, int stride) {
+  const int tile_offset = RESTORATION_TILE_OFFSET >> ss_y;
   const int stripe_index = (limits->v_start + tile_offset) / stripe_height;
 
   const int line_width =
@@ -301,7 +261,7 @@
     for (int i = 0; i < 2; ++i) {
       uint8_t *dst8 = data8_tl + i * stride;
       // Save old pixels, then replace with data from boundary_above_buf
-      memcpy(REAL_PTR(use_highbd, dst8), rst->tmp_save_above[i], line_size);
+      memcpy(REAL_PTR(use_highbd, dst8), rlbs->tmp_save_above[i], line_size);
     }
   }
 
@@ -313,7 +273,7 @@
   for (int i = 0; i < rows_needed_below; ++i) {
     uint8_t *dst8 = data8_bl + i * stride;
     // Save old pixels, then replace with data from boundary_below_buf
-    memcpy(REAL_PTR(use_highbd, dst8), rst->tmp_save_below[i], line_size);
+    memcpy(REAL_PTR(use_highbd, dst8), rlbs->tmp_save_below[i], line_size);
   }
 }
 #undef REAL_PTR
@@ -357,44 +317,46 @@
 #define wiener_convolve8_add_src aom_convolve8_add_src
 #endif
 
-static void wiener_filter_stripe(const RestorationTileLimits *limits,
-                                 const RestorationInternal *rst, int tile_idx,
-                                 int procunit_width, int stripe_height,
-                                 const uint8_t *src, int src_stride,
-                                 uint8_t *dst, int dst_stride) {
-  const RestorationInfo *rsi = rst->rsi;
+static void wiener_filter_stripe(const RestorationUnitInfo *rui,
+                                 int stripe_width, int stripe_height,
+                                 int procunit_width, const uint8_t *src,
+                                 int src_stride, uint8_t *dst, int dst_stride,
+                                 int32_t *tmpbuf, int bit_depth) {
+  (void)tmpbuf;
+  (void)bit_depth;
+  assert(bit_depth == 8);
+
   const int mid_height =
       stripe_height - (WIENER_HALFWIN - WIENER_BORDER_VERT) * 2;
   assert(mid_height > 0);
-  for (int j = limits->h_start; j < limits->h_end; j += procunit_width) {
-    int w = AOMMIN(procunit_width, (limits->h_end - j + 15) & ~15);
+  for (int j = 0; j < stripe_width; j += procunit_width) {
+    int w = AOMMIN(procunit_width, (stripe_width - j + 15) & ~15);
     const uint8_t *src_p = src + j;
     uint8_t *dst_p = dst + j;
     for (int b = 0; b < WIENER_HALFWIN - WIENER_BORDER_VERT; ++b) {
       InterpKernel vertical_top;
-      stepdown_wiener_kernel(rsi->wiener_info[tile_idx].vfilter, vertical_top,
+      stepdown_wiener_kernel(rui->wiener_info.vfilter, vertical_top,
                              WIENER_BORDER_VERT + b, 1);
       wiener_convolve8_add_src(src_p, src_stride, dst_p, dst_stride,
-                               rsi->wiener_info[tile_idx].hfilter, 16,
-                               vertical_top, 16, w, 1);
+                               rui->wiener_info.hfilter, 16, vertical_top, 16,
+                               w, 1);
       src_p += src_stride;
       dst_p += dst_stride;
     }
 
     wiener_convolve8_add_src(src_p, src_stride, dst_p, dst_stride,
-                             rsi->wiener_info[tile_idx].hfilter, 16,
-                             rsi->wiener_info[tile_idx].vfilter, 16, w,
-                             mid_height);
+                             rui->wiener_info.hfilter, 16,
+                             rui->wiener_info.vfilter, 16, w, mid_height);
     src_p += src_stride * mid_height;
     dst_p += dst_stride * mid_height;
 
     for (int b = WIENER_HALFWIN - WIENER_BORDER_VERT - 1; b >= 0; --b) {
       InterpKernel vertical_bot;
-      stepdown_wiener_kernel(rsi->wiener_info[tile_idx].vfilter, vertical_bot,
+      stepdown_wiener_kernel(rui->wiener_info.vfilter, vertical_bot,
                              WIENER_BORDER_VERT + b, 0);
       wiener_convolve8_add_src(src_p, src_stride, dst_p, dst_stride,
-                               rsi->wiener_info[tile_idx].hfilter, 16,
-                               vertical_bot, 16, w, 1);
+                               rui->wiener_info.hfilter, 16, vertical_bot, 16,
+                               w, 1);
       src_p += src_stride;
       dst_p += dst_stride;
     }
@@ -749,7 +711,7 @@
   }
 }
 
-void decode_xq(int *xqd, int *xq) {
+void decode_xq(const int *xqd, int *xq) {
   xq[0] = xqd[0];
   xq[1] = (1 << SGRPROJ_PRJ_BITS) - xq[0] - xqd[1];
 }
@@ -1091,8 +1053,9 @@
 }
 
 void apply_selfguided_restoration_c(const uint8_t *dat, int width, int height,
-                                    int stride, int eps, int *xqd, uint8_t *dst,
-                                    int dst_stride, int32_t *tmpbuf) {
+                                    int stride, int eps, const int *xqd,
+                                    uint8_t *dst, int dst_stride,
+                                    int32_t *tmpbuf) {
   int xq[2];
   int32_t *flt1 = tmpbuf;
   int32_t *flt2 = flt1 + RESTORATION_TILEPELS_MAX;
@@ -1124,19 +1087,19 @@
   }
 }
 
-static void sgrproj_filter_stripe(const RestorationTileLimits *limits,
-                                  const RestorationInternal *rst, int tile_idx,
-                                  int procunit_width, int stripe_height,
-                                  const uint8_t *src, int src_stride,
-                                  uint8_t *dst, int dst_stride) {
-  for (int j = limits->h_start; j < limits->h_end; j += procunit_width) {
-    int w = AOMMIN(procunit_width, limits->h_end - j);
-    const uint8_t *src_p = src + j;
-    uint8_t *dst_p = dst + j;
-    apply_selfguided_restoration(src_p, w, stripe_height, src_stride,
-                                 rst->rsi->sgrproj_info[tile_idx].ep,
-                                 rst->rsi->sgrproj_info[tile_idx].xqd, dst_p,
-                                 dst_stride, rst->tmpbuf);
+static void sgrproj_filter_stripe(const RestorationUnitInfo *rui,
+                                  int stripe_width, int stripe_height,
+                                  int procunit_width, const uint8_t *src,
+                                  int src_stride, uint8_t *dst, int dst_stride,
+                                  int32_t *tmpbuf, int bit_depth) {
+  (void)bit_depth;
+  assert(bit_depth == 8);
+
+  for (int j = 0; j < stripe_width; j += procunit_width) {
+    int w = AOMMIN(procunit_width, stripe_width - j);
+    apply_selfguided_restoration(src + j, w, stripe_height, src_stride,
+                                 rui->sgrproj_info.ep, rui->sgrproj_info.xqd,
+                                 dst + j, dst_stride, tmpbuf);
   }
 }
 
@@ -1147,46 +1110,46 @@
 #define wiener_highbd_convolve8_add_src aom_highbd_convolve8_add_src
 #endif
 
-static void wiener_filter_stripe_highbd(const RestorationTileLimits *limits,
-                                        const RestorationInternal *rst,
-                                        int tile_idx, int procunit_width,
-                                        int stripe_height, const uint8_t *src8,
+static void wiener_filter_stripe_highbd(const RestorationUnitInfo *rui,
+                                        int stripe_width, int stripe_height,
+                                        int procunit_width, const uint8_t *src8,
                                         int src_stride, uint8_t *dst8,
-                                        int dst_stride) {
-  const RestorationInfo *rsi = rst->rsi;
+                                        int dst_stride, int32_t *tmpbuf,
+                                        int bit_depth) {
+  (void)tmpbuf;
+
   const int mid_height =
       stripe_height - (WIENER_HALFWIN - WIENER_BORDER_VERT) * 2;
   assert(mid_height > 0);
 
-  for (int j = limits->h_start; j < limits->h_end; j += procunit_width) {
-    int w = AOMMIN(procunit_width, (limits->h_end - j + 15) & ~15);
+  for (int j = 0; j < stripe_width; j += procunit_width) {
+    int w = AOMMIN(procunit_width, (stripe_width - j + 15) & ~15);
     const uint8_t *src8_p = src8 + j;
     uint8_t *dst8_p = dst8 + j;
 
     for (int b = 0; b < WIENER_HALFWIN - WIENER_BORDER_VERT; ++b) {
       InterpKernel vertical_top;
-      stepdown_wiener_kernel(rsi->wiener_info[tile_idx].vfilter, vertical_top,
+      stepdown_wiener_kernel(rui->wiener_info.vfilter, vertical_top,
                              WIENER_BORDER_VERT + b, 1);
       wiener_highbd_convolve8_add_src(src8_p, src_stride, dst8_p, dst_stride,
-                                      rsi->wiener_info[tile_idx].hfilter, 16,
-                                      vertical_top, 16, w, 1, rst->bit_depth);
+                                      rui->wiener_info.hfilter, 16,
+                                      vertical_top, 16, w, 1, bit_depth);
       src8_p += src_stride;
       dst8_p += dst_stride;
     }
     assert(stripe_height > (WIENER_HALFWIN - WIENER_BORDER_VERT) * 2);
-    wiener_highbd_convolve8_add_src(src8_p, src_stride, dst8_p, dst_stride,
-                                    rsi->wiener_info[tile_idx].hfilter, 16,
-                                    rsi->wiener_info[tile_idx].vfilter, 16, w,
-                                    mid_height, rst->bit_depth);
+    wiener_highbd_convolve8_add_src(
+        src8_p, src_stride, dst8_p, dst_stride, rui->wiener_info.hfilter, 16,
+        rui->wiener_info.vfilter, 16, w, mid_height, bit_depth);
     src8_p += src_stride * (mid_height);
     dst8_p += dst_stride * (mid_height);
     for (int b = WIENER_HALFWIN - WIENER_BORDER_VERT - 1; b >= 0; --b) {
       InterpKernel vertical_bot;
-      stepdown_wiener_kernel(rsi->wiener_info[tile_idx].vfilter, vertical_bot,
+      stepdown_wiener_kernel(rui->wiener_info.vfilter, vertical_bot,
                              WIENER_BORDER_VERT + b, 0);
       wiener_highbd_convolve8_add_src(src8_p, src_stride, dst8_p, dst_stride,
-                                      rsi->wiener_info[tile_idx].hfilter, 16,
-                                      vertical_bot, 16, w, 1, rst->bit_depth);
+                                      rui->wiener_info.hfilter, 16,
+                                      vertical_bot, 16, w, 1, bit_depth);
       src8_p += src_stride;
       dst8_p += dst_stride;
     }
@@ -1304,9 +1267,9 @@
 
 void apply_selfguided_restoration_highbd_c(const uint16_t *dat, int width,
                                            int height, int stride,
-                                           int bit_depth, int eps, int *xqd,
-                                           uint16_t *dst, int dst_stride,
-                                           int32_t *tmpbuf) {
+                                           int bit_depth, int eps,
+                                           const int *xqd, uint16_t *dst,
+                                           int dst_stride, int32_t *tmpbuf) {
   int xq[2];
   int32_t *flt1 = tmpbuf;
   int32_t *flt2 = flt1 + RESTORATION_TILEPELS_MAX;
@@ -1340,29 +1303,28 @@
   }
 }
 
-static void sgrproj_filter_stripe_highbd(const RestorationTileLimits *limits,
-                                         const RestorationInternal *rst,
-                                         int tile_idx, int procunit_width,
-                                         int stripe_height, const uint8_t *src8,
-                                         int src_stride, uint8_t *dst8,
-                                         int dst_stride) {
-  for (int j = limits->h_start; j < limits->h_end; j += procunit_width) {
-    int w = AOMMIN(procunit_width, limits->h_end - j);
+static void sgrproj_filter_stripe_highbd(const RestorationUnitInfo *rui,
+                                         int stripe_width, int stripe_height,
+                                         int procunit_width,
+                                         const uint8_t *src8, int src_stride,
+                                         uint8_t *dst8, int dst_stride,
+                                         int32_t *tmpbuf, int bit_depth) {
+  for (int j = 0; j < stripe_width; j += procunit_width) {
+    int w = AOMMIN(procunit_width, stripe_width - j);
     const uint16_t *data_p = CONVERT_TO_SHORTPTR(src8) + j;
     uint16_t *dst_p = CONVERT_TO_SHORTPTR(dst8) + j;
     apply_selfguided_restoration_highbd(
-        data_p, w, stripe_height, src_stride, rst->bit_depth,
-        rst->rsi->sgrproj_info[tile_idx].ep,
-        rst->rsi->sgrproj_info[tile_idx].xqd, dst_p, dst_stride, rst->tmpbuf);
+        data_p, w, stripe_height, src_stride, bit_depth, rui->sgrproj_info.ep,
+        rui->sgrproj_info.xqd, dst_p, dst_stride, tmpbuf);
   }
 }
 #endif  // CONFIG_HIGHBITDEPTH
 
-typedef void (*stripe_filter_fun)(const RestorationTileLimits *limits,
-                                  const RestorationInternal *rst, int tile_idx,
-                                  int procunit_width, int stripe_height,
-                                  const uint8_t *src, int src_stride,
-                                  uint8_t *dst, int dst_stride);
+typedef void (*stripe_filter_fun)(const RestorationUnitInfo *rui,
+                                  int stripe_width, int stripe_height,
+                                  int procunit_width, const uint8_t *src,
+                                  int src_stride, uint8_t *dst, int dst_stride,
+                                  int32_t *tmpbuf, int bit_depth);
 
 #if CONFIG_HIGHBITDEPTH
 #define NUM_STRIPE_FILTERS 4
@@ -1377,17 +1339,29 @@
 #endif  // CONFIG_HIGHBITDEPTH
 };
 
-static void filter_rest_unit(const RestorationTileLimits *limits,
-                             RestorationInternal *rst, int tile_idx, int highbd,
-                             uint8_t *data8, int stride, uint8_t *dst8,
-                             int dst_stride) {
-  RestorationType tile_rtype = rst->rsi->restoration_type[tile_idx];
-  if (tile_rtype == RESTORE_NONE) {
-    copy_tile(limits, data8, stride, dst8, dst_stride, highbd);
+void av1_loop_restoration_filter_unit(const RestorationTileLimits *limits,
+                                      const RestorationUnitInfo *rui,
+#if CONFIG_STRIPED_LOOP_RESTORATION
+                                      const RestorationStripeBoundaries *rsb,
+                                      RestorationLineBuffers *rlbs, int ss_y,
+#endif
+                                      int procunit_width, int procunit_height,
+                                      int highbd, int bit_depth, uint8_t *data8,
+                                      int stride, uint8_t *dst8, int dst_stride,
+                                      int32_t *tmpbuf) {
+  RestorationType unit_rtype = rui->restoration_type;
+
+  int unit_h = limits->v_end - limits->v_start;
+  int unit_w = limits->h_end - limits->h_start;
+  uint8_t *data8_tl = data8 + limits->v_start * stride + limits->h_start;
+  uint8_t *dst8_tl = dst8 + limits->v_start * dst_stride + limits->h_start;
+
+  if (unit_rtype == RESTORE_NONE) {
+    copy_tile(unit_w, unit_h, data8_tl, stride, dst8_tl, dst_stride, highbd);
     return;
   }
 
-  const int filter_idx = 2 * highbd + (tile_rtype == RESTORE_SGRPROJ);
+  const int filter_idx = 2 * highbd + (unit_rtype == RESTORE_SGRPROJ);
   assert(filter_idx < NUM_STRIPE_FILTERS);
   const stripe_filter_fun stripe_filter = stripe_filters[filter_idx];
 
@@ -1395,25 +1369,24 @@
 #if CONFIG_STRIPED_LOOP_RESTORATION
   RestorationTileLimits remaining_stripes = *limits;
 #endif
-  int i = limits->v_start;
-  while (i < limits->v_end) {
+  int i = 0;
+  while (i < unit_h) {
 #if CONFIG_STRIPED_LOOP_RESTORATION
-    remaining_stripes.v_start = i;
-    int h = setup_processing_stripe_boundary(&remaining_stripes, data8, stride,
-                                             rst, highbd);
-    if (tile_rtype == RESTORE_WIENER) h = ALIGN_POWER_OF_TWO(h, 1);
+    remaining_stripes.v_start = limits->v_start + i;
+    int h = setup_processing_stripe_boundary(&remaining_stripes, rsb,
+                                             procunit_height, ss_y, highbd,
+                                             data8, stride, rlbs);
+    if (unit_rtype == RESTORE_WIENER) h = ALIGN_POWER_OF_TWO(h, 1);
 #else
-    const int h =
-        AOMMIN(rst->rsi->procunit_height, (limits->v_end - i + 15) & ~15);
+    const int h = AOMMIN(procunit_height, (unit_h - i + 15) & ~15);
 #endif
 
-    stripe_filter(limits, rst, tile_idx, rst->rsi->procunit_width, h,
-                  data8 + i * stride, stride, dst8 + i * dst_stride,
-                  dst_stride);
+    stripe_filter(rui, unit_w, h, procunit_width, data8_tl + i * stride, stride,
+                  dst8_tl + i * dst_stride, dst_stride, tmpbuf, bit_depth);
 
 #if CONFIG_STRIPED_LOOP_RESTORATION
-    restore_processing_stripe_boundary(&remaining_stripes, rst, data8, stride,
-                                       highbd);
+    restore_processing_stripe_boundary(
+        &remaining_stripes, rlbs, procunit_height, ss_y, highbd, data8, stride);
 #endif
 
     i += h;
@@ -1431,27 +1404,10 @@
   { RESTORATION_BORDER_HORZ, RESTORATION_BORDER_VERT }
 };
 
-static void filter_frame(int width, int height, RestorationType frame_rtype,
-                         int highbd, uint8_t *data8, int stride, uint8_t *dst8,
-                         int dst_stride, RestorationInternal *rst) {
-  const struct restore_borders *borders = &restore_borders[frame_rtype];
-
-  extend_frame(data8, width, height, stride, borders->hborder, borders->vborder,
-               highbd);
-
-  for (int tile_idx = 0; tile_idx < rst->ntiles; ++tile_idx) {
-    RestorationTileLimits limits = av1_get_rest_tile_limits(
-        tile_idx, rst->nhtiles, rst->nvtiles, rst->rsi->restoration_tilesize,
-        width, height, rst->subsampling_y);
-
-    filter_rest_unit(&limits, rst, tile_idx, highbd, data8, stride, dst8,
-                     dst_stride);
-  }
-}
-
-void av1_loop_restoration_frame(YV12_BUFFER_CONFIG *frame, AV1_COMMON *cm,
-                                RestorationInfo *rsi, int components_pattern,
-                                YV12_BUFFER_CONFIG *dst) {
+void av1_loop_restoration_filter_frame(YV12_BUFFER_CONFIG *frame,
+                                       AV1_COMMON *cm, RestorationInfo *rsi,
+                                       int components_pattern,
+                                       YV12_BUFFER_CONFIG *dst) {
   YV12_BUFFER_CONFIG dst_;
 
   typedef void (*copy_fun)(const YV12_BUFFER_CONFIG *src,
@@ -1491,11 +1447,21 @@
                          "Failed to allocate restoration dst buffer");
   }
 
-  RestorationInternal rst;
+#if CONFIG_STRIPED_LOOP_RESTORATION
+  RestorationLineBuffers rlbs;
+#endif
+#if CONFIG_HIGHBITDEPTH
+  const int bit_depth = cm->bit_depth;
+  const int highbd = cm->use_highbitdepth;
+#else
+  const int bit_depth = 8;
+  const int highbd = 0;
+#endif
+
   for (int plane = 0; plane < 3; ++plane) {
     if (!((components_pattern >> plane) & 1)) continue;
-
-    RestorationType rtype = rsi[plane].frame_restoration_type;
+    const RestorationInfo *prsi = &rsi[plane];
+    RestorationType rtype = prsi->frame_restoration_type;
     if (rtype == RESTORE_NONE) {
       copy_funs[plane](frame, dst);
       continue;
@@ -1507,23 +1473,31 @@
     const int plane_width = frame->crop_widths[is_uv];
     const int plane_height = frame->crop_heights[is_uv];
 
-    rst.rsi = &rsi[plane];
-    rst.keyframe = cm->frame_type == KEY_FRAME;
-    rst.ntiles = av1_get_rest_ntiles(plane_width, plane_height,
-                                     rst.rsi->restoration_tilesize,
-                                     &rst.nhtiles, &rst.nvtiles);
-    rst.subsampling_y = ss_y;
-    rst.tmpbuf = cm->rst_tmpbuf;
-#if CONFIG_HIGHBITDEPTH
-    rst.bit_depth = cm->bit_depth;
-    const int highbd = cm->use_highbitdepth;
-#else
-    const int highbd = 0;
-#endif
+    int nhtiles, nvtiles;
+    const int ntiles =
+        av1_get_rest_ntiles(plane_width, plane_height,
+                            prsi->restoration_tilesize, &nhtiles, &nvtiles);
 
-    filter_frame(plane_width, plane_height, rtype, highbd,
-                 frame->buffers[plane], frame->strides[is_uv],
-                 dst->buffers[plane], dst->strides[is_uv], &rst);
+    const struct restore_borders *borders =
+        &restore_borders[prsi->frame_restoration_type];
+    extend_frame(frame->buffers[plane], plane_width, plane_height,
+                 frame->strides[is_uv], borders->hborder, borders->vborder,
+                 highbd);
+
+    for (int tile_idx = 0; tile_idx < ntiles; ++tile_idx) {
+      RestorationTileLimits limits = av1_get_rest_tile_limits(
+          tile_idx, nhtiles, nvtiles, prsi->restoration_tilesize, plane_width,
+          plane_height, ss_y);
+
+      av1_loop_restoration_filter_unit(
+          &limits, &prsi->unit_info[tile_idx],
+#if CONFIG_STRIPED_LOOP_RESTORATION
+          &prsi->boundaries, &rlbs, ss_y,
+#endif
+          prsi->procunit_width, prsi->procunit_height, highbd, bit_depth,
+          frame->buffers[plane], frame->strides[is_uv], dst->buffers[plane],
+          dst->strides[is_uv], cm->rst_tmpbuf);
+    }
   }
 
   if (dst == &dst_) {
@@ -1627,7 +1601,7 @@
 // For each 64 pixel high stripe, save 4 scan lines to be used as boundary in
 // the loop restoration process. The lines are saved in
 // rst_internal.stripe_boundary_lines
-void av1_loop_restoration_save_boundary_lines(YV12_BUFFER_CONFIG *frame,
+void av1_loop_restoration_save_boundary_lines(const YV12_BUFFER_CONFIG *frame,
                                               AV1_COMMON *cm) {
   for (int p = 0; p < MAX_MB_PLANE; ++p) {
     const int is_uv = p > 0;
@@ -1638,9 +1612,10 @@
     const int stripe_height = 64 >> (is_uv && cm->subsampling_y);
     const int stripe_offset = (56 >> (is_uv && cm->subsampling_y)) - 2;
 
-    uint8_t *boundary_above_buf = cm->rst_info[p].stripe_boundary_above;
-    uint8_t *boundary_below_buf = cm->rst_info[p].stripe_boundary_below;
-    const int boundary_stride = cm->rst_info[p].stripe_boundary_stride;
+    RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries;
+    uint8_t *boundary_above_buf = boundaries->stripe_boundary_above;
+    uint8_t *boundary_below_buf = boundaries->stripe_boundary_below;
+    const int boundary_stride = boundaries->stripe_boundary_stride;
 #if CONFIG_HIGHBITDEPTH
     const int use_highbitdepth = cm->use_highbitdepth;
     if (use_highbitdepth) {
diff --git a/av1/common/restoration.h b/av1/common/restoration.h
index 161654d..eddb7ff 100644
--- a/av1/common/restoration.h
+++ b/av1/common/restoration.h
@@ -207,18 +207,38 @@
 } sgr_params_type;
 
 typedef struct {
-  int restoration_tilesize;
-  int procunit_width, procunit_height;
-  RestorationType frame_restoration_type;
-  RestorationType *restoration_type;
-  // Wiener filter
-  WienerInfo *wiener_info;
-  // Selfguided proj filter
-  SgrprojInfo *sgrproj_info;
+  RestorationType restoration_type;
+  WienerInfo wiener_info;
+  SgrprojInfo sgrproj_info;
+} RestorationUnitInfo;
+
 #if CONFIG_STRIPED_LOOP_RESTORATION
+// A restoration line buffer needs space for two lines plus a horizontal filter
+// margin of RESTORATION_EXTRA_HORZ on each side.
+#define RESTORATION_LINEBUFFER_WIDTH \
+  (RESTORATION_TILESIZE_MAX + 2 * RESTORATION_EXTRA_HORZ)
+
+typedef struct {
+  // Temporary buffers to save/restore 2 lines above/below the restoration
+  // stripe.
+  uint16_t tmp_save_above[2][RESTORATION_LINEBUFFER_WIDTH];
+  uint16_t tmp_save_below[2][RESTORATION_LINEBUFFER_WIDTH];
+} RestorationLineBuffers;
+
+typedef struct {
   uint8_t *stripe_boundary_above;
   uint8_t *stripe_boundary_below;
   int stripe_boundary_stride;
+} RestorationStripeBoundaries;
+#endif
+
+typedef struct {
+  RestorationType frame_restoration_type;
+  int restoration_tilesize;
+  int procunit_width, procunit_height;
+  RestorationUnitInfo *unit_info;
+#if CONFIG_STRIPED_LOOP_RESTORATION
+  RestorationStripeBoundaries boundaries;
 #endif
 } RestorationInfo;
 
@@ -290,10 +310,43 @@
 
 void extend_frame(uint8_t *data, int width, int height, int stride,
                   int border_horz, int border_vert, int highbd);
-void decode_xq(int *xqd, int *xq);
-void av1_loop_restoration_frame(YV12_BUFFER_CONFIG *frame, struct AV1Common *cm,
-                                RestorationInfo *rsi, int components_pattern,
-                                YV12_BUFFER_CONFIG *dst);
+void decode_xq(const int *xqd, int *xq);
+
+// Filter a single loop restoration unit.
+//
+// limits is the limits of the unit. rui gives the mode to use for this unit
+// and its coefficients. If striped loop restoration is enabled, rsb contains
+// deblocked pixels to use for stripe boundaries; rlbs is just some space to
+// use as a scratch buffer. ss_y is a flag which should be 1 if this is a plane
+// with vertical subsampling.
+//
+// procunit_width and procunit_height are the width and height in which to
+// process the data. highbd is a flag which should be 1 in high bit depth mode,
+// in which case bit_depth is the bit depth.
+//
+// data8 is the frame data (pointing at the top-left corner of the frame, not
+// the restoration unit) and stride is its stride. dst8 is the buffer where the
+// results will be written and has stride dst_stride. Like data8, dst8 should
+// point at the top-left corner of the frame.
+//
+// Finally tmpbuf is a scratch buffer used by the sgrproj filter which should
+// be at least SGRPROJ_TMPBUF_SIZE big.
+void av1_loop_restoration_filter_unit(const RestorationTileLimits *limits,
+                                      const RestorationUnitInfo *rui,
+#if CONFIG_STRIPED_LOOP_RESTORATION
+                                      const RestorationStripeBoundaries *rsb,
+                                      RestorationLineBuffers *rlbs, int ss_y,
+#endif
+                                      int procunit_height, int procunit_width,
+                                      int highbd, int bit_depth, uint8_t *data8,
+                                      int stride, uint8_t *dst8, int dst_stride,
+                                      int32_t *tmpbuf);
+
+void av1_loop_restoration_filter_frame(YV12_BUFFER_CONFIG *frame,
+                                       struct AV1Common *cm,
+                                       RestorationInfo *rsi,
+                                       int components_pattern,
+                                       YV12_BUFFER_CONFIG *dst);
 void av1_loop_restoration_precal();
 
 // Return 1 iff the block at mi_row, mi_col with size bsize is a
@@ -310,7 +363,7 @@
                                        int *rcol0, int *rcol1, int *rrow0,
                                        int *rrow1, int *nhtiles);
 
-void av1_loop_restoration_save_boundary_lines(YV12_BUFFER_CONFIG *frame,
+void av1_loop_restoration_save_boundary_lines(const YV12_BUFFER_CONFIG *frame,
                                               struct AV1Common *cm);
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/av1/common/x86/selfguided_sse4.c b/av1/common/x86/selfguided_sse4.c
index 8626c01..3e66eb0 100644
--- a/av1/common/x86/selfguided_sse4.c
+++ b/av1/common/x86/selfguided_sse4.c
@@ -1058,8 +1058,8 @@
 
 void apply_selfguided_restoration_sse4_1(const uint8_t *dat, int width,
                                          int height, int stride, int eps,
-                                         int *xqd, uint8_t *dst, int dst_stride,
-                                         int32_t *tmpbuf) {
+                                         const int *xqd, uint8_t *dst,
+                                         int dst_stride, int32_t *tmpbuf) {
   int xq[2];
   int32_t *flt1 = tmpbuf;
   int32_t *flt2 = flt1 + RESTORATION_TILEPELS_MAX;
@@ -1740,7 +1740,7 @@
 
 void apply_selfguided_restoration_highbd_sse4_1(
     const uint16_t *dat, int width, int height, int stride, int bit_depth,
-    int eps, int *xqd, uint16_t *dst, int dst_stride, int32_t *tmpbuf) {
+    int eps, const int *xqd, uint16_t *dst, int dst_stride, int32_t *tmpbuf) {
   int xq[2];
   int32_t *flt1 = tmpbuf;
   int32_t *flt2 = flt1 + RESTORATION_TILEPELS_MAX;
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index ccf15b6..4c8b9f6 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -1452,6 +1452,9 @@
 
 static void read_wiener_filter(int wiener_win, WienerInfo *wiener_info,
                                WienerInfo *ref_wiener_info, aom_reader *rb) {
+  memset(wiener_info->vfilter, 0, sizeof(wiener_info->vfilter));
+  memset(wiener_info->hfilter, 0, sizeof(wiener_info->hfilter));
+
   if (wiener_win == WIENER_WIN)
     wiener_info->vfilter[0] = wiener_info->vfilter[WIENER_WIN - 1] =
         aom_read_primitive_refsubexpfin(
@@ -1526,7 +1529,8 @@
                                             MACROBLOCKD *xd,
                                             aom_reader *const r, int plane,
                                             int rtile_idx) {
-  const RestorationInfo *rsi = cm->rst_info + plane;
+  const RestorationInfo *rsi = &cm->rst_info[plane];
+  RestorationUnitInfo *rui = &rsi->unit_info[rtile_idx];
   if (rsi->frame_restoration_type == RESTORE_NONE) return;
 
   const int wiener_win = (plane > 0) ? WIENER_WIN_CHROMA : WIENER_WIN;
@@ -1534,14 +1538,17 @@
   SgrprojInfo *sgrproj_info = xd->sgrproj_info + plane;
 
   if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
-    rsi->restoration_type[rtile_idx] =
+    rui->restoration_type =
         aom_read_symbol(r, xd->tile_ctx->switchable_restore_cdf,
                         RESTORE_SWITCHABLE_TYPES, ACCT_STR);
-    if (rsi->restoration_type[rtile_idx] == RESTORE_WIENER) {
-      read_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx], wiener_info,
-                         r);
-    } else if (rsi->restoration_type[rtile_idx] == RESTORE_SGRPROJ) {
-      read_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], sgrproj_info, r);
+    switch (rui->restoration_type) {
+      case RESTORE_WIENER:
+        read_wiener_filter(wiener_win, &rui->wiener_info, wiener_info, r);
+        break;
+      case RESTORE_SGRPROJ:
+        read_sgrproj_filter(&rui->sgrproj_info, sgrproj_info, r);
+        break;
+      default: assert(rui->restoration_type == RESTORE_NONE); break;
     }
   } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
 #if CONFIG_NEW_MULTISYMBOL
@@ -1549,11 +1556,10 @@
 #else
     if (aom_read(r, RESTORE_NONE_WIENER_PROB, ACCT_STR)) {
 #endif  // CONFIG_NEW_MULTISYMBOL
-      rsi->restoration_type[rtile_idx] = RESTORE_WIENER;
-      read_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx], wiener_info,
-                         r);
+      rui->restoration_type = RESTORE_WIENER;
+      read_wiener_filter(wiener_win, &rui->wiener_info, wiener_info, r);
     } else {
-      rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+      rui->restoration_type = RESTORE_NONE;
     }
   } else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
 #if CONFIG_NEW_MULTISYMBOL
@@ -1561,10 +1567,10 @@
 #else
     if (aom_read(r, RESTORE_NONE_SGRPROJ_PROB, ACCT_STR)) {
 #endif  // CONFIG_NEW_MULTISYMBOL
-      rsi->restoration_type[rtile_idx] = RESTORE_SGRPROJ;
-      read_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], sgrproj_info, r);
+      rui->restoration_type = RESTORE_SGRPROJ;
+      read_sgrproj_filter(&rui->sgrproj_info, sgrproj_info, r);
     } else {
-      rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+      rui->restoration_type = RESTORE_NONE;
     }
   }
 }
@@ -3970,8 +3976,8 @@
       cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
       cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
     aom_extend_frame_borders((YV12_BUFFER_CONFIG *)xd->cur_buf);
-    av1_loop_restoration_frame((YV12_BUFFER_CONFIG *)xd->cur_buf, cm,
-                               cm->rst_info, 7, NULL);
+    av1_loop_restoration_filter_frame((YV12_BUFFER_CONFIG *)xd->cur_buf, cm,
+                                      cm->rst_info, 7, NULL);
   }
 #endif  // CONFIG_LOOP_RESTORATION
 
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index de1aa97..db109e9 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -82,8 +82,8 @@
 #if CONFIG_LOOP_RESTORATION
 static void loop_restoration_write_sb_coeffs(const AV1_COMMON *const cm,
                                              MACROBLOCKD *xd,
-                                             aom_writer *const w, int plane,
-                                             int rtile_idx);
+                                             const RestorationUnitInfo *rui,
+                                             aom_writer *const w, int plane);
 #endif  // CONFIG_LOOP_RESTORATION
 #if CONFIG_OBU
 static void write_uncompressed_header_obu(AV1_COMP *cpi,
@@ -2748,7 +2748,9 @@
       for (int rrow = rrow0; rrow < rrow1; ++rrow) {
         for (int rcol = rcol0; rcol < rcol1; ++rcol) {
           int rtile_idx = rcol + rrow * nhtiles;
-          loop_restoration_write_sb_coeffs(cm, xd, w, plane, rtile_idx);
+          const RestorationUnitInfo *rui =
+              &cm->rst_info[plane].unit_info[rtile_idx];
+          loop_restoration_write_sb_coeffs(cm, xd, rui, w, plane);
         }
       }
     }
@@ -2857,7 +2859,7 @@
   }
 }
 
-static void write_wiener_filter(int wiener_win, WienerInfo *wiener_info,
+static void write_wiener_filter(int wiener_win, const WienerInfo *wiener_info,
                                 WienerInfo *ref_wiener_info, aom_writer *wb) {
   if (wiener_win == WIENER_WIN)
     aom_write_primitive_refsubexpfin(
@@ -2900,7 +2902,7 @@
   memcpy(ref_wiener_info, wiener_info, sizeof(*wiener_info));
 }
 
-static void write_sgrproj_filter(SgrprojInfo *sgrproj_info,
+static void write_sgrproj_filter(const SgrprojInfo *sgrproj_info,
                                  SgrprojInfo *ref_sgrproj_info,
                                  aom_writer *wb) {
   aom_write_literal(wb, sgrproj_info->ep, SGRPROJ_PARAMS_BITS);
@@ -2917,47 +2919,48 @@
 
 static void loop_restoration_write_sb_coeffs(const AV1_COMMON *const cm,
                                              MACROBLOCKD *xd,
-                                             aom_writer *const w, int plane,
-                                             int rtile_idx) {
+                                             const RestorationUnitInfo *rui,
+                                             aom_writer *const w, int plane) {
   const RestorationInfo *rsi = cm->rst_info + plane;
-  if (rsi->frame_restoration_type == RESTORE_NONE) return;
+  RestorationType frame_rtype = rsi->frame_restoration_type;
+  if (frame_rtype == RESTORE_NONE) return;
 
   const int wiener_win = (plane > 0) ? WIENER_WIN_CHROMA : WIENER_WIN;
   WienerInfo *wiener_info = xd->wiener_info + plane;
   SgrprojInfo *sgrproj_info = xd->sgrproj_info + plane;
+  RestorationType unit_rtype = rui->restoration_type;
 
-  if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
-    aom_write_symbol(w, rsi->restoration_type[rtile_idx],
-                     xd->tile_ctx->switchable_restore_cdf,
+  if (frame_rtype == RESTORE_SWITCHABLE) {
+    aom_write_symbol(w, unit_rtype, xd->tile_ctx->switchable_restore_cdf,
                      RESTORE_SWITCHABLE_TYPES);
-    if (rsi->restoration_type[rtile_idx] == RESTORE_WIENER) {
-      write_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx], wiener_info,
-                          w);
-    } else if (rsi->restoration_type[rtile_idx] == RESTORE_SGRPROJ) {
-      write_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], sgrproj_info, w);
+    switch (unit_rtype) {
+      case RESTORE_WIENER:
+        write_wiener_filter(wiener_win, &rui->wiener_info, wiener_info, w);
+        break;
+      case RESTORE_SGRPROJ:
+        write_sgrproj_filter(&rui->sgrproj_info, sgrproj_info, w);
+        break;
+      default: assert(unit_rtype == RESTORE_NONE); break;
     }
-  } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
+  } else if (frame_rtype == RESTORE_WIENER) {
 #if CONFIG_NEW_MULTISYMBOL
-    aom_write_symbol(w, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
+    aom_write_symbol(w, unit_rtype != RESTORE_NONE,
                      xd->tile_ctx->wiener_restore_cdf, 2);
 #else
-    aom_write(w, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
-              RESTORE_NONE_WIENER_PROB);
+    aom_write(w, unit_rtype != RESTORE_NONE, RESTORE_NONE_WIENER_PROB);
 #endif  // CONFIG_NEW_MULTISYMBOL
-    if (rsi->restoration_type[rtile_idx] != RESTORE_NONE) {
-      write_wiener_filter(wiener_win, &rsi->wiener_info[rtile_idx], wiener_info,
-                          w);
+    if (unit_rtype != RESTORE_NONE) {
+      write_wiener_filter(wiener_win, &rui->wiener_info, wiener_info, w);
     }
-  } else if (rsi->frame_restoration_type == RESTORE_SGRPROJ) {
+  } else if (frame_rtype == RESTORE_SGRPROJ) {
 #if CONFIG_NEW_MULTISYMBOL
-    aom_write_symbol(w, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
+    aom_write_symbol(w, unit_rtype != RESTORE_NONE,
                      xd->tile_ctx->sgrproj_restore_cdf, 2);
 #else
-    aom_write(w, rsi->restoration_type[rtile_idx] != RESTORE_NONE,
-              RESTORE_NONE_SGRPROJ_PROB);
+    aom_write(w, unit_rtype != RESTORE_NONE, RESTORE_NONE_SGRPROJ_PROB);
 #endif  // CONFIG_NEW_MULTISYMBOL
-    if (rsi->restoration_type[rtile_idx] != RESTORE_NONE) {
-      write_sgrproj_filter(&rsi->sgrproj_info[rtile_idx], sgrproj_info, w);
+    if (unit_rtype != RESTORE_NONE) {
+      write_sgrproj_filter(&rui->sgrproj_info, sgrproj_info, w);
     }
   }
 }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index de0d05a..95bae67 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4301,9 +4301,7 @@
     av1_alloc_restoration_struct(cm, search, frame_width, frame_height);
 #if CONFIG_STRIPED_LOOP_RESTORATION
     // We can share boundary buffers between the search info and the main one
-    search->stripe_boundary_above = rsi->stripe_boundary_above;
-    search->stripe_boundary_below = rsi->stripe_boundary_below;
-    search->stripe_boundary_stride = rsi->stripe_boundary_stride;
+    search->boundaries = rsi->boundaries;
 #endif
   }
 #endif                            // CONFIG_LOOP_RESTORATION
@@ -4671,7 +4669,8 @@
   if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
       cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
       cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
-    av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, NULL);
+    av1_loop_restoration_filter_frame(cm->frame_to_show, cm, cm->rst_info, 7,
+                                      NULL);
   }
 #endif  // CONFIG_LOOP_RESTORATION
   // TODO(debargha): Fix mv search range on encoder side
diff --git a/av1/encoder/pickrst.c b/av1/encoder/pickrst.c
index f90f3f1..4cf657e 100644
--- a/av1/encoder/pickrst.c
+++ b/av1/encoder/pickrst.c
@@ -141,8 +141,8 @@
   int nhtiles, nvtiles;
   av1_get_rest_ntiles(width, height, rtile_size, &nhtiles, &nvtiles);
 
-  av1_loop_restoration_frame(cm->frame_to_show, cm, rsi, components_pattern,
-                             dst_frame);
+  av1_loop_restoration_filter_frame(cm->frame_to_show, cm, rsi,
+                                    components_pattern, dst_frame);
   RestorationTileLimits limits = av1_get_rest_tile_limits(
       tile_idx, nhtiles, nvtiles, rtile_size, width, height, ss_y);
   int64_t filt_err = sse_restoration_tile(
@@ -158,8 +158,8 @@
                                      YV12_BUFFER_CONFIG *dst_frame) {
   AV1_COMMON *const cm = &cpi->common;
   int64_t filt_err;
-  av1_loop_restoration_frame(cm->frame_to_show, cm, rsi, components_pattern,
-                             dst_frame);
+  av1_loop_restoration_filter_frame(cm->frame_to_show, cm, rsi,
+                                    components_pattern, dst_frame);
   filt_err = sse_restoration_frame(cm, src, dst_frame, components_pattern);
   return filt_err;
 }
@@ -557,8 +557,6 @@
   const MACROBLOCK *const x = &ctxt->cpi->td.mb;
   const AV1_COMMON *const cm = &ctxt->cpi->common;
   RestorationInfo *rsi = ctxt->cpi->rst_search;
-  SgrprojInfo *sgrproj_info = ctxt->info->sgrproj_info;
-
   SgrprojInfo *ref_sgrproj_info = (SgrprojInfo *)arg;
 
   int64_t err =
@@ -570,8 +568,8 @@
   double cost_norestore = RDCOST_DBL(x->rdmult, (bits >> 4), err);
   ctxt->best_tile_cost[rtile_idx] = INT64_MAX;
 
-  RestorationInfo *plane_rsi = &rsi[ctxt->plane];
-  SgrprojInfo *rtile_sgrproj_info = &plane_rsi->sgrproj_info[rtile_idx];
+  RestorationUnitInfo *plane_rui = &rsi[ctxt->plane].unit_info[rtile_idx];
+  SgrprojInfo *rtile_sgrproj_info = &plane_rui->sgrproj_info;
   uint8_t *dgd_start =
       ctxt->dgd_buffer + limits->v_start * ctxt->dgd_stride + limits->h_start;
   const uint8_t *src_start =
@@ -588,23 +586,22 @@
 #endif  // CONFIG_HIGHBITDEPTH
       rsi[ctxt->plane].procunit_width, rsi[ctxt->plane].procunit_height,
       &rtile_sgrproj_info->ep, rtile_sgrproj_info->xqd, cm->rst_tmpbuf);
-  plane_rsi->restoration_type[rtile_idx] = RESTORE_SGRPROJ;
+  plane_rui->restoration_type = RESTORE_SGRPROJ;
   err = try_restoration_tile(ctxt->src, ctxt->cpi, rsi, (1 << ctxt->plane),
                              rtile_idx, ctxt->dst_frame);
-  bits =
-      count_sgrproj_bits(&plane_rsi->sgrproj_info[rtile_idx], ref_sgrproj_info)
-      << AV1_PROB_COST_SHIFT;
+  bits = count_sgrproj_bits(rtile_sgrproj_info, ref_sgrproj_info)
+         << AV1_PROB_COST_SHIFT;
   bits += x->sgrproj_restore_cost[1];
   double cost_sgrproj = RDCOST_DBL(x->rdmult, (bits >> 4), err);
   if (cost_sgrproj >= cost_norestore) {
     ctxt->type[rtile_idx] = RESTORE_NONE;
   } else {
     ctxt->type[rtile_idx] = RESTORE_SGRPROJ;
-    *ref_sgrproj_info = sgrproj_info[rtile_idx] =
-        plane_rsi->sgrproj_info[rtile_idx];
+    SgrprojInfo *sgrproj_info = &ctxt->info->unit_info[rtile_idx].sgrproj_info;
+    *ref_sgrproj_info = *sgrproj_info = plane_rui->sgrproj_info;
     ctxt->best_tile_cost[rtile_idx] = err;
   }
-  plane_rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+  plane_rui->restoration_type = RESTORE_NONE;
 }
 
 static double search_sgrproj(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
@@ -619,7 +616,7 @@
   RestorationInfo *plane_rsi = &cpi->rst_search[plane];
   plane_rsi->frame_restoration_type = RESTORE_SGRPROJ;
   for (int rtile_idx = 0; rtile_idx < nrtiles; ++rtile_idx) {
-    plane_rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+    plane_rsi->unit_info[rtile_idx].restoration_type = RESTORE_NONE;
   }
 
   // Compute best Sgrproj filters for each rtile, one (encoder/decoder)
@@ -646,20 +643,21 @@
   // Cost for Sgrproj filtering
   SgrprojInfo ref_sgrproj_info;
   set_default_sgrproj(&ref_sgrproj_info);
-  SgrprojInfo *sgrproj_info = info->sgrproj_info;
 
   int bits = frame_level_restore_bits[plane_rsi->frame_restoration_type]
              << AV1_PROB_COST_SHIFT;
   for (int rtile_idx = 0; rtile_idx < nrtiles; ++rtile_idx) {
+    RestorationUnitInfo *plane_rui = &plane_rsi->unit_info[rtile_idx];
+    RestorationUnitInfo *search_rui = &info->unit_info[rtile_idx];
+
     bits += x->sgrproj_restore_cost[type[rtile_idx] != RESTORE_NONE];
-    plane_rsi->sgrproj_info[rtile_idx] = sgrproj_info[rtile_idx];
+    plane_rui->sgrproj_info = search_rui->sgrproj_info;
     if (type[rtile_idx] == RESTORE_SGRPROJ) {
-      bits += count_sgrproj_bits(&plane_rsi->sgrproj_info[rtile_idx],
-                                 &ref_sgrproj_info)
+      bits += count_sgrproj_bits(&plane_rui->sgrproj_info, &ref_sgrproj_info)
               << AV1_PROB_COST_SHIFT;
-      ref_sgrproj_info = plane_rsi->sgrproj_info[rtile_idx];
+      ref_sgrproj_info = plane_rui->sgrproj_info;
     }
-    plane_rsi->restoration_type[rtile_idx] = type[rtile_idx];
+    plane_rui->restoration_type = type[rtile_idx];
   }
   int64_t err =
       try_restoration_frame(src, cpi, cpi->rst_search, (1 << plane), dst_frame);
@@ -1038,21 +1036,25 @@
                     WIENER_FILT_TAP2_MINV };
   int tap_max[] = { WIENER_FILT_TAP0_MAXV, WIENER_FILT_TAP1_MAXV,
                     WIENER_FILT_TAP2_MAXV };
+
+  RestorationUnitInfo *plane_rui = &rsi[plane].unit_info[tile_idx];
+  WienerInfo *plane_wiener = &plane_rui->wiener_info;
+
   // printf("err  pre = %"PRId64"\n", err);
   for (int s = start_step; s >= 1; s >>= 1) {
     for (int p = plane_off; p < WIENER_HALFWIN; ++p) {
       int skip = 0;
       do {
-        if (rsi[plane].wiener_info[tile_idx].hfilter[p] - s >= tap_min[p]) {
-          rsi[plane].wiener_info[tile_idx].hfilter[p] -= s;
-          rsi[plane].wiener_info[tile_idx].hfilter[WIENER_WIN - p - 1] -= s;
-          rsi[plane].wiener_info[tile_idx].hfilter[WIENER_HALFWIN] += 2 * s;
+        if (plane_wiener->hfilter[p] - s >= tap_min[p]) {
+          plane_wiener->hfilter[p] -= s;
+          plane_wiener->hfilter[WIENER_WIN - p - 1] -= s;
+          plane_wiener->hfilter[WIENER_HALFWIN] += 2 * s;
           err2 = try_restoration_tile(src, cpi, rsi, 1 << plane, tile_idx,
                                       dst_frame);
           if (err2 > err) {
-            rsi[plane].wiener_info[tile_idx].hfilter[p] += s;
-            rsi[plane].wiener_info[tile_idx].hfilter[WIENER_WIN - p - 1] += s;
-            rsi[plane].wiener_info[tile_idx].hfilter[WIENER_HALFWIN] -= 2 * s;
+            plane_wiener->hfilter[p] += s;
+            plane_wiener->hfilter[WIENER_WIN - p - 1] += s;
+            plane_wiener->hfilter[WIENER_HALFWIN] -= 2 * s;
           } else {
             err = err2;
             skip = 1;
@@ -1064,16 +1066,16 @@
       } while (1);
       if (skip) break;
       do {
-        if (rsi[plane].wiener_info[tile_idx].hfilter[p] + s <= tap_max[p]) {
-          rsi[plane].wiener_info[tile_idx].hfilter[p] += s;
-          rsi[plane].wiener_info[tile_idx].hfilter[WIENER_WIN - p - 1] += s;
-          rsi[plane].wiener_info[tile_idx].hfilter[WIENER_HALFWIN] -= 2 * s;
+        if (plane_wiener->hfilter[p] + s <= tap_max[p]) {
+          plane_wiener->hfilter[p] += s;
+          plane_wiener->hfilter[WIENER_WIN - p - 1] += s;
+          plane_wiener->hfilter[WIENER_HALFWIN] -= 2 * s;
           err2 = try_restoration_tile(src, cpi, rsi, 1 << plane, tile_idx,
                                       dst_frame);
           if (err2 > err) {
-            rsi[plane].wiener_info[tile_idx].hfilter[p] -= s;
-            rsi[plane].wiener_info[tile_idx].hfilter[WIENER_WIN - p - 1] -= s;
-            rsi[plane].wiener_info[tile_idx].hfilter[WIENER_HALFWIN] += 2 * s;
+            plane_wiener->hfilter[p] -= s;
+            plane_wiener->hfilter[WIENER_WIN - p - 1] -= s;
+            plane_wiener->hfilter[WIENER_HALFWIN] += 2 * s;
           } else {
             err = err2;
             // At the highest step size continue moving in the same direction
@@ -1086,16 +1088,16 @@
     for (int p = plane_off; p < WIENER_HALFWIN; ++p) {
       int skip = 0;
       do {
-        if (rsi[plane].wiener_info[tile_idx].vfilter[p] - s >= tap_min[p]) {
-          rsi[plane].wiener_info[tile_idx].vfilter[p] -= s;
-          rsi[plane].wiener_info[tile_idx].vfilter[WIENER_WIN - p - 1] -= s;
-          rsi[plane].wiener_info[tile_idx].vfilter[WIENER_HALFWIN] += 2 * s;
+        if (plane_wiener->vfilter[p] - s >= tap_min[p]) {
+          plane_wiener->vfilter[p] -= s;
+          plane_wiener->vfilter[WIENER_WIN - p - 1] -= s;
+          plane_wiener->vfilter[WIENER_HALFWIN] += 2 * s;
           err2 = try_restoration_tile(src, cpi, rsi, 1 << plane, tile_idx,
                                       dst_frame);
           if (err2 > err) {
-            rsi[plane].wiener_info[tile_idx].vfilter[p] += s;
-            rsi[plane].wiener_info[tile_idx].vfilter[WIENER_WIN - p - 1] += s;
-            rsi[plane].wiener_info[tile_idx].vfilter[WIENER_HALFWIN] -= 2 * s;
+            plane_wiener->vfilter[p] += s;
+            plane_wiener->vfilter[WIENER_WIN - p - 1] += s;
+            plane_wiener->vfilter[WIENER_HALFWIN] -= 2 * s;
           } else {
             err = err2;
             skip = 1;
@@ -1107,16 +1109,16 @@
       } while (1);
       if (skip) break;
       do {
-        if (rsi[plane].wiener_info[tile_idx].vfilter[p] + s <= tap_max[p]) {
-          rsi[plane].wiener_info[tile_idx].vfilter[p] += s;
-          rsi[plane].wiener_info[tile_idx].vfilter[WIENER_WIN - p - 1] += s;
-          rsi[plane].wiener_info[tile_idx].vfilter[WIENER_HALFWIN] -= 2 * s;
+        if (plane_wiener->vfilter[p] + s <= tap_max[p]) {
+          plane_wiener->vfilter[p] += s;
+          plane_wiener->vfilter[WIENER_WIN - p - 1] += s;
+          plane_wiener->vfilter[WIENER_HALFWIN] -= 2 * s;
           err2 = try_restoration_tile(src, cpi, rsi, 1 << plane, tile_idx,
                                       dst_frame);
           if (err2 > err) {
-            rsi[plane].wiener_info[tile_idx].vfilter[p] -= s;
-            rsi[plane].wiener_info[tile_idx].vfilter[WIENER_WIN - p - 1] -= s;
-            rsi[plane].wiener_info[tile_idx].vfilter[WIENER_HALFWIN] += 2 * s;
+            plane_wiener->vfilter[p] -= s;
+            plane_wiener->vfilter[WIENER_WIN - p - 1] -= s;
+            plane_wiener->vfilter[WIENER_HALFWIN] += 2 * s;
           } else {
             err = err2;
             // At the highest step size continue moving in the same direction
@@ -1177,8 +1179,8 @@
     return;
   }
 
-  RestorationInfo *plane_rsi = &rsi[ctxt->plane];
-  WienerInfo *rtile_wiener_info = &plane_rsi->wiener_info[rtile_idx];
+  RestorationUnitInfo *plane_rui = &rsi[ctxt->plane].unit_info[rtile_idx];
+  WienerInfo *rtile_wiener_info = &plane_rui->wiener_info;
   quantize_sym_filter(wiener_win, vfilterd, rtile_wiener_info->vfilter);
   quantize_sym_filter(wiener_win, hfilterd, rtile_wiener_info->hfilter);
 
@@ -1193,7 +1195,7 @@
   }
   aom_clear_system_state();
 
-  plane_rsi->restoration_type[rtile_idx] = RESTORE_WIENER;
+  plane_rui->restoration_type = RESTORE_WIENER;
   err = finer_tile_search_wiener(ctxt->src, ctxt->cpi, rsi, 4, ctxt->plane,
                                  wiener_win, rtile_idx, ctxt->dst_frame);
   if (wiener_win != WIENER_WIN) {
@@ -1210,10 +1212,11 @@
     ctxt->type[rtile_idx] = RESTORE_NONE;
   } else {
     ctxt->type[rtile_idx] = RESTORE_WIENER;
-    *ref_wiener_info = ctxt->info->wiener_info[rtile_idx] = *rtile_wiener_info;
+    *ref_wiener_info = ctxt->info->unit_info[rtile_idx].wiener_info =
+        *rtile_wiener_info;
     ctxt->best_tile_cost[rtile_idx] = err;
   }
-  plane_rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+  plane_rui->restoration_type = RESTORE_NONE;
 }
 
 static double search_wiener(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi,
@@ -1228,7 +1231,7 @@
   RestorationInfo *plane_rsi = &cpi->rst_search[plane];
   plane_rsi->frame_restoration_type = RESTORE_WIENER;
   for (int tile_idx = 0; tile_idx < nrtiles; ++tile_idx) {
-    plane_rsi->restoration_type[tile_idx] = RESTORE_NONE;
+    plane_rsi->unit_info[tile_idx].restoration_type = RESTORE_NONE;
   }
 
   AV1_COMMON *const cm = &cpi->common;
@@ -1260,21 +1263,21 @@
   set_default_wiener(&ref_wiener_info);
   int bits = frame_level_restore_bits[plane_rsi->frame_restoration_type]
              << AV1_PROB_COST_SHIFT;
-  WienerInfo *wiener_info = info->wiener_info;
   const int wiener_win =
       (plane == AOM_PLANE_Y) ? WIENER_WIN : WIENER_WIN_CHROMA;
 
   for (int tile_idx = 0; tile_idx < nrtiles; ++tile_idx) {
     bits += x->wiener_restore_cost[type[tile_idx] != RESTORE_NONE];
-    plane_rsi->wiener_info[tile_idx] = wiener_info[tile_idx];
+    RestorationUnitInfo *plane_rui = &plane_rsi->unit_info[tile_idx];
+    plane_rui->wiener_info = info->unit_info[tile_idx].wiener_info;
 
     if (type[tile_idx] == RESTORE_WIENER) {
-      bits += count_wiener_bits(wiener_win, &plane_rsi->wiener_info[tile_idx],
+      bits += count_wiener_bits(wiener_win, &plane_rui->wiener_info,
                                 &ref_wiener_info)
               << AV1_PROB_COST_SHIFT;
-      ref_wiener_info = plane_rsi->wiener_info[tile_idx];
+      ref_wiener_info = plane_rui->wiener_info;
     }
-    plane_rsi->restoration_type[tile_idx] = type[tile_idx];
+    plane_rui->restoration_type = type[tile_idx];
   }
   int64_t err =
       try_restoration_frame(src, cpi, cpi->rst_search, 1 << plane, dst_frame);
@@ -1336,7 +1339,8 @@
                                         const RestorationTileLimits *limits,
                                         void *arg) {
   const MACROBLOCK *x = &ctxt->cpi->td.mb;
-  RestorationInfo *rsi = &ctxt->cpi->common.rst_info[ctxt->plane];
+  RestorationUnitInfo *rui =
+      &ctxt->cpi->common.rst_info[ctxt->plane].unit_info[rtile_idx];
   struct switchable_rest_search_ctxt *swctxt =
       (struct switchable_rest_search_ctxt *)arg;
 
@@ -1345,7 +1349,8 @@
   double best_cost =
       RDCOST_DBL(x->rdmult, (x->switchable_restore_cost[RESTORE_NONE] >> 4),
                  swctxt->tile_cost[RESTORE_NONE][rtile_idx]);
-  rsi->restoration_type[rtile_idx] = RESTORE_NONE;
+
+  rui->restoration_type = RESTORE_NONE;
   for (RestorationType r = 1; r < RESTORE_SWITCHABLE_TYPES; r++) {
     if (force_restore_type != RESTORE_TYPES)
       if (r != force_restore_type) continue;
@@ -1354,27 +1359,26 @@
     if (r == RESTORE_WIENER)
       tilebits += count_wiener_bits(
           (ctxt->plane == AOM_PLANE_Y ? WIENER_WIN : WIENER_WIN - 2),
-          &rsi->wiener_info[rtile_idx], &swctxt->wiener_info);
+          &rui->wiener_info, &swctxt->wiener_info);
     else if (r == RESTORE_SGRPROJ)
-      tilebits += count_sgrproj_bits(&rsi->sgrproj_info[rtile_idx],
-                                     &swctxt->sgrproj_info);
+      tilebits += count_sgrproj_bits(&rui->sgrproj_info, &swctxt->sgrproj_info);
     tilebits <<= AV1_PROB_COST_SHIFT;
     tilebits += x->switchable_restore_cost[r];
     double cost =
         RDCOST_DBL(x->rdmult, tilebits >> 4, swctxt->tile_cost[r][rtile_idx]);
 
     if (cost < best_cost) {
-      rsi->restoration_type[rtile_idx] = r;
+      rui->restoration_type = r;
       best_cost = cost;
     }
   }
-  if (rsi->restoration_type[rtile_idx] == RESTORE_WIENER)
-    swctxt->wiener_info = rsi->wiener_info[rtile_idx];
-  else if (rsi->restoration_type[rtile_idx] == RESTORE_SGRPROJ)
-    swctxt->sgrproj_info = rsi->sgrproj_info[rtile_idx];
+  if (rui->restoration_type == RESTORE_WIENER)
+    swctxt->wiener_info = rui->wiener_info;
+  else if (rui->restoration_type == RESTORE_SGRPROJ)
+    swctxt->sgrproj_info = rui->sgrproj_info;
   if (force_restore_type != RESTORE_TYPES)
-    assert(rsi->restoration_type[rtile_idx] == force_restore_type ||
-           rsi->restoration_type[rtile_idx] == RESTORE_NONE);
+    assert(rui->restoration_type == force_restore_type ||
+           rui->restoration_type == RESTORE_NONE);
   swctxt->cost_switchable += best_cost;
 }
 
@@ -1464,8 +1468,10 @@
       assert(best_restore == force_restore_type ||
              best_restore == RESTORE_NONE);
     if (best_restore != RESTORE_SWITCHABLE) {
-      memcpy(cm->rst_info[plane].restoration_type, restore_types[best_restore],
-             ntiles * sizeof(restore_types[best_restore][0]));
+      for (int u = 0; u < ntiles; ++u) {
+        cm->rst_info[plane].unit_info[u].restoration_type =
+            restore_types[best_restore][u];
+      }
     }
   }
   /*