Expand RST_MERGECOEFFS to use a dynamic list

Each tool has a dynamic list of filters used within the frame,
and the bitstream can now signal any one of them for use in a
RU.
This is the first patch on this theme, and there will be more to
follow with additional features and encoder side changes.
diff --git a/av1/common/blockd.c b/av1/common/blockd.c
index 100405d..cdd23ef 100644
--- a/av1/common/blockd.c
+++ b/av1/common/blockd.c
@@ -128,14 +128,189 @@
 
 void av1_reset_loop_restoration(MACROBLOCKD *xd, const int num_planes) {
   for (int p = 0; p < num_planes; ++p) {
-    set_default_wiener(xd->wiener_info + p);
-    set_default_sgrproj(xd->sgrproj_info + p);
+    av1_reset_wiener_bank(&xd->wiener_info[p]);
+    av1_reset_sgrproj_bank(&xd->sgrproj_info[p]);
 #if CONFIG_WIENER_NONSEP
-    set_default_wiener_nonsep(xd->wiener_nonsep_info + p, xd->base_qindex);
+    av1_reset_wiener_nonsep_bank(&xd->wiener_nonsep_info[p], xd->base_qindex);
 #endif  // CONFIG_WIENER_NONSEP
   }
 }
 
+void av1_reset_wiener_bank(WienerInfoBank *bank) {
+  set_default_wiener(&bank->filter[0]);
+  bank->bank_size = 0;
+  bank->bank_ptr = 0;
+}
+
+void av1_add_to_wiener_bank(WienerInfoBank *bank, const WienerInfo *info) {
+  if (bank->bank_size < LR_BANK_SIZE) {
+    bank->bank_ptr = bank->bank_size;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+    bank->bank_size++;
+  } else {
+    bank->bank_ptr = (bank->bank_ptr + 1) % LR_BANK_SIZE;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+  }
+}
+
+WienerInfo *av1_ref_from_wiener_bank(WienerInfoBank *bank, int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+const WienerInfo *av1_constref_from_wiener_bank(const WienerInfoBank *bank,
+                                                int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+void av1_upd_to_wiener_bank(WienerInfoBank *bank, int ndx,
+                            const WienerInfo *info) {
+  memcpy(av1_ref_from_wiener_bank(bank, ndx), info, sizeof(*info));
+}
+
+void av1_get_from_wiener_bank(WienerInfoBank *bank, int ndx, WienerInfo *info) {
+  if (bank->bank_size == 0) {
+    set_default_wiener(info);
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    memcpy(info, &bank->filter[ptr], sizeof(*info));
+  }
+}
+
+void av1_reset_sgrproj_bank(SgrprojInfoBank *bank) {
+  set_default_sgrproj(&bank->filter[0]);
+  bank->bank_size = 0;
+  bank->bank_ptr = 0;
+}
+
+void av1_add_to_sgrproj_bank(SgrprojInfoBank *bank, const SgrprojInfo *info) {
+  if (bank->bank_size < LR_BANK_SIZE) {
+    bank->bank_ptr = bank->bank_size;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+    bank->bank_size++;
+  } else {
+    bank->bank_ptr = (bank->bank_ptr + 1) % LR_BANK_SIZE;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+  }
+}
+
+SgrprojInfo *av1_ref_from_sgrproj_bank(SgrprojInfoBank *bank, int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+const SgrprojInfo *av1_constref_from_sgrproj_bank(const SgrprojInfoBank *bank,
+                                                  int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+void av1_upd_to_sgrproj_bank(SgrprojInfoBank *bank, int ndx,
+                             const SgrprojInfo *info) {
+  memcpy(av1_ref_from_sgrproj_bank(bank, ndx), info, sizeof(*info));
+}
+
+void av1_get_from_sgrproj_bank(SgrprojInfoBank *bank, int ndx,
+                               SgrprojInfo *info) {
+  if (bank->bank_size == 0) {
+    set_default_sgrproj(info);
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    memcpy(info, &bank->filter[ptr], sizeof(*info));
+  }
+}
+
+#if CONFIG_WIENER_NONSEP
+void av1_reset_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int qindex) {
+  set_default_wiener_nonsep(&bank->filter[0], qindex);
+  bank->bank_size = 0;
+  bank->bank_ptr = 0;
+}
+
+void av1_add_to_wiener_nonsep_bank(WienerNonsepInfoBank *bank,
+                                   const WienerNonsepInfo *info) {
+  if (bank->bank_size < LR_BANK_SIZE) {
+    bank->bank_ptr = bank->bank_size;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+    bank->bank_size++;
+  } else {
+    bank->bank_ptr = (bank->bank_ptr + 1) % LR_BANK_SIZE;
+    memcpy(&bank->filter[bank->bank_ptr], info, sizeof(*info));
+  }
+}
+
+WienerNonsepInfo *av1_ref_from_wiener_nonsep_bank(WienerNonsepInfoBank *bank,
+                                                  int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+const WienerNonsepInfo *av1_constref_from_wiener_nonsep_bank(
+    const WienerNonsepInfoBank *bank, int ndx) {
+  if (bank->bank_size == 0) {
+    return &bank->filter[0];
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    return &bank->filter[ptr];
+  }
+}
+
+void av1_upd_to_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int ndx,
+                                   const WienerNonsepInfo *info) {
+  memcpy(av1_ref_from_wiener_nonsep_bank(bank, ndx), info, sizeof(*info));
+}
+
+void av1_get_from_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int ndx,
+                                     WienerNonsepInfo *info, int qindex) {
+  (void)ndx;
+  if (bank->bank_size == 0) {
+    set_default_wiener_nonsep(info, qindex);
+  } else {
+    assert(ndx < bank->bank_size);
+    const int ptr =
+        bank->bank_ptr - ndx + (bank->bank_ptr < ndx ? LR_BANK_SIZE : 0);
+    memcpy(info, &bank->filter[ptr], sizeof(*info));
+  }
+}
+#endif  // CONFIG_WIENER_NONSEP
+
 void av1_setup_block_planes(MACROBLOCKD *xd, int ss_x, int ss_y,
                             const int num_planes) {
   int i;
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index bb9c166..390a8ff 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -662,6 +662,12 @@
 
 #define BLOCK_OFFSET(i) ((i) << 4)
 
+#if CONFIG_RST_MERGECOEFFS
+#define LR_BANK_SIZE 4
+#else
+#define LR_BANK_SIZE 1
+#endif  // CONFIG_RST_MERGE_COEFFS
+
 /*!\endcond */
 
 /*!\brief Parameters related to Wiener Filter */
@@ -677,6 +683,22 @@
   DECLARE_ALIGNED(16, InterpKernel, hfilter);
 } WienerInfo;
 
+/*!\brief Parameters related to Wiener Filter Bank */
+typedef struct {
+  /*!
+   * Bank of filter infos
+   */
+  WienerInfo filter[LR_BANK_SIZE];
+  /*!
+   * Size of the bank
+   */
+  int bank_size;
+  /*!
+   * Pointer to the most current filter
+   */
+  int bank_ptr;
+} WienerInfoBank;
+
 /*!\brief Parameters related to Sgrproj Filter */
 typedef struct {
   /*!
@@ -690,6 +712,22 @@
   int xqd[2];
 } SgrprojInfo;
 
+/*!\brief Parameters related to Sgrproj Filter Bank */
+typedef struct {
+  /*!
+   * Bank of filter infos
+   */
+  SgrprojInfo filter[LR_BANK_SIZE];
+  /*!
+   * Size of the bank
+   */
+  int bank_size;
+  /*!
+   * Pointer to the most current filter
+   */
+  int bank_ptr;
+} SgrprojInfoBank;
+
 #if CONFIG_CNN_GUIDED_QUADTREE
 
 /*!\cond */
@@ -717,6 +755,23 @@
    */
   DECLARE_ALIGNED(16, int16_t, nsfilter[WIENERNS_YUV_MAX]);
 } WienerNonsepInfo;
+
+/*!\brief Parameters related to Nonseparable Wiener Filter Bank */
+typedef struct {
+  /*!
+   * Bank of filter infos
+   */
+  WienerNonsepInfo filter[LR_BANK_SIZE];
+  /*!
+   * Size of the bank
+   */
+  int bank_size;
+  /*!
+   * Pointer to the most current filter
+   */
+  int bank_ptr;
+} WienerNonsepInfoBank;
+
 #endif  // CONFIG_WIENER_NONSEP
 
 /*!\cond */
@@ -1014,22 +1069,22 @@
   TXFM_CONTEXT left_txfm_context_buffer[MAX_MIB_SIZE];
 
   /**
-   * \name Default values for the two restoration filters for each plane.
-   * Default values for the two restoration filters for each plane.
-   * These values are used as reference values when writing the bitstream. That
-   * is, we transmit the delta between the actual values in
+   * \name Reference values for the restoration filters for each plane.
+   * Reference values for the restoration filters for each plane.
+   * The values here are used as reference values when writing the bitstream.
+   * That is, we transmit the delta between the actual values in
    * cm->rst_info[plane].unit_info[unit_idx] and these reference values.
    */
   /**@{*/
-  WienerInfo wiener_info[MAX_MB_PLANE];   /*!< Defaults for Wiener filter*/
-  SgrprojInfo sgrproj_info[MAX_MB_PLANE]; /*!< Defaults for SGR filter */
+  WienerInfoBank wiener_info[MAX_MB_PLANE];   /*!< Refs for Wiener filter*/
+  SgrprojInfoBank sgrproj_info[MAX_MB_PLANE]; /*!< Refs for SGR filter */
   /**@}*/
 
 #if CONFIG_WIENER_NONSEP
   /*!
    * Nonseparable Wiener filter information for all planes.
    */
-  WienerNonsepInfo wiener_nonsep_info[MAX_MB_PLANE];
+  WienerNonsepInfoBank wiener_nonsep_info[MAX_MB_PLANE];
 #endif  // CONFIG_WIENER_NONSEP
 
   /**
@@ -1783,6 +1838,39 @@
 
 void av1_reset_loop_filter_delta(MACROBLOCKD *xd, int num_planes);
 
+void av1_reset_wiener_bank(WienerInfoBank *bank);
+void av1_add_to_wiener_bank(WienerInfoBank *bank, const WienerInfo *info);
+WienerInfo *av1_ref_from_wiener_bank(WienerInfoBank *bank, int ndx);
+const WienerInfo *av1_constref_from_wiener_bank(const WienerInfoBank *bank,
+                                                int ndx);
+void av1_upd_to_wiener_bank(WienerInfoBank *bank, int ndx,
+                            const WienerInfo *info);
+void av1_get_from_wiener_bank(WienerInfoBank *bank, int ndx, WienerInfo *info);
+
+void av1_reset_sgrproj_bank(SgrprojInfoBank *bank);
+void av1_add_to_sgrproj_bank(SgrprojInfoBank *bank, const SgrprojInfo *info);
+SgrprojInfo *av1_ref_from_sgrproj_bank(SgrprojInfoBank *bank, int ndx);
+const SgrprojInfo *av1_constref_from_sgrproj_bank(const SgrprojInfoBank *bank,
+                                                  int ndx);
+void av1_upd_to_sgrproj_bank(SgrprojInfoBank *bank, int ndx,
+                             const SgrprojInfo *info);
+void av1_get_from_sgrproj_bank(SgrprojInfoBank *bank, int ndx,
+                               SgrprojInfo *info);
+
+#if CONFIG_WIENER_NONSEP
+void av1_reset_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int qindex);
+void av1_add_to_wiener_nonsep_bank(WienerNonsepInfoBank *bank,
+                                   const WienerNonsepInfo *info);
+WienerNonsepInfo *av1_ref_from_wiener_nonsep_bank(WienerNonsepInfoBank *bank,
+                                                  int ndx);
+const WienerNonsepInfo *av1_constref_from_wiener_nonsep_bank(
+    const WienerNonsepInfoBank *bank, int ndx);
+void av1_upd_to_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int ndx,
+                                   const WienerNonsepInfo *info);
+void av1_get_from_wiener_nonsep_bank(WienerNonsepInfoBank *bank, int ndx,
+                                     WienerNonsepInfo *info, int qindex);
+#endif  // CONFIG_WIENER_NONSEP
+
 void av1_reset_loop_restoration(MACROBLOCKD *xd, const int num_planes);
 
 typedef void (*foreach_transformed_block_visitor)(int plane, int block,
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 5969dd7..6c42747 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -1469,10 +1469,10 @@
 #if CONFIG_LR_FLEX_SYNTAX
 static const aom_cdf_prob default_switchable_flex_restore_cdf
     [MULTIQ_LR_LEVELS][MAX_LR_FLEX_SWITCHABLE_BITS][CDF_SIZE(2)] = {
-      { { AOM_CDF2(16384) },
-        { AOM_CDF2(16384) },
-        { AOM_CDF2(16384) },
-        { AOM_CDF2(16384) } },
+      { { AOM_CDF2(20384) },
+        { AOM_CDF2(20384) },
+        { AOM_CDF2(24384) },
+        { AOM_CDF2(20384) } },
 #if CONFIG_MULTIQ_LR_SIGNALING
       { { AOM_CDF2(16384) },
         { AOM_CDF2(16384) },
diff --git a/av1/common/restoration.c b/av1/common/restoration.c
index 2b6ad7b..c5c1bfb 100644
--- a/av1/common/restoration.c
+++ b/av1/common/restoration.c
@@ -1870,6 +1870,7 @@
   return filter;
 }
 
+#if CONFIG_COMBINE_PC_NS_WIENER
 void apply_wiener_nonsep_class_id_highbd(
     const uint8_t *dgd8, int width, int height, int stride, int base_qindex,
     const int16_t *filter, uint8_t *dst8, int dst_stride, int plane,
@@ -1911,6 +1912,7 @@
   }
   return;
 }
+#endif  // CONFIG_COMBINE_PC_NS_WIENER
 
 static void wiener_nsfilter_stripe_highbd(const RestorationUnitInfo *rui,
                                           int stripe_width, int stripe_height,
diff --git a/av1/common/restoration.h b/av1/common/restoration.h
index 3be66df..d55af52 100644
--- a/av1/common/restoration.h
+++ b/av1/common/restoration.h
@@ -460,21 +460,6 @@
   wiener_info->vfilter[6] = wiener_info->hfilter[6] = WIENER_FILT_TAP0_MIDV;
 }
 
-#if CONFIG_RST_MERGECOEFFS
-static INLINE int check_wiener_eq(const WienerInfo *info,
-                                  const WienerInfo *ref) {
-  return !memcmp(info->vfilter, ref->vfilter,
-                 WIENER_HALFWIN * sizeof(info->vfilter[0])) &&
-         !memcmp(info->hfilter, ref->hfilter,
-                 WIENER_HALFWIN * sizeof(info->hfilter[0]));
-}
-static INLINE int check_sgrproj_eq(const SgrprojInfo *info,
-                                   const SgrprojInfo *ref) {
-  if (!memcmp(info, ref, sizeof(*info))) return 1;
-  return 0;
-}
-#endif  // CONFIG_RST_MERGECOEFFS
-
 #if CONFIG_WIENER_NONSEP
 static INLINE void set_default_wiener_nonsep(WienerNonsepInfo *wienerns_info,
                                              int qindex) {
@@ -491,24 +476,6 @@
   }
 }
 
-#if CONFIG_RST_MERGECOEFFS
-static INLINE int check_wienerns_eq(int chroma, const WienerNonsepInfo *info,
-                                    const WienerNonsepInfo *ref,
-                                    const WienernsFilterConfigPairType *wnsf) {
-  if (!chroma) {
-    if (!memcmp(info->nsfilter, ref->nsfilter,
-                wnsf->y->ncoeffs * sizeof(*info->nsfilter)))
-      return 1;
-  } else {
-    if (!memcmp(&info->nsfilter[wnsf->y->ncoeffs],
-                &ref->nsfilter[wnsf->y->ncoeffs],
-                wnsf->uv->ncoeffs * sizeof(*info->nsfilter)))
-      return 1;
-  }
-  return 0;
-}
-#endif  // CONFIG_RST_MERGECOEFFS
-
 #if CONFIG_WIENER_NONSEP_CROSS_FILT
 uint8_t *wienerns_copy_luma(const uint8_t *dgd, int height_y, int width_y,
                             int in_stride, uint8_t **luma, int height_uv,
@@ -525,30 +492,6 @@
   int h_start, h_end, v_start, v_end;
 } RestorationTileLimits;
 
-#if CONFIG_RST_MERGECOEFFS
-typedef struct RstUnitSnapshot {
-  RestorationTileLimits limits;
-  int rest_unit_idx;  // update filter value and sse as needed
-  int64_t current_sse;
-  int64_t current_bits;
-  int64_t merge_sse;
-  int64_t merge_bits;
-  // Wiener filter info
-  int64_t M[WIENER_WIN2];
-  int64_t H[WIENER_WIN2 * WIENER_WIN2];
-  WienerInfo ref_wiener;
-#if CONFIG_WIENER_NONSEP
-  // Nonseparable Wiener filter info
-  double A[WIENERNS_MAX * WIENERNS_MAX];
-  double b[WIENERNS_MAX];
-  WienerNonsepInfo ref_wiener_nonsep;
-#endif  // CONFIG_WIENER_NONSEP
-  // Sgrproj filter info
-  SgrprojInfo unit_sgrproj;
-  SgrprojInfo ref_sgrproj;
-} RstUnitSnapshot;
-#endif  // CONFIG_RST_MERGECOEFFS
-
 typedef void (*rest_unit_visitor_t)(const RestorationTileLimits *limits,
                                     const AV1PixelRect *tile_rect,
                                     int rest_unit_idx, void *priv,
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 50f51f3..3038a34 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -2314,18 +2314,21 @@
 
 static AOM_INLINE void read_wiener_filter(MACROBLOCKD *xd, int wiener_win,
                                           WienerInfo *wiener_info,
-                                          WienerInfo *ref_wiener_info,
+                                          WienerInfoBank *bank,
                                           aom_reader *rb) {
 #if CONFIG_RST_MERGECOEFFS
-  const int equal =
-      aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR);
-  if (equal) {
-    memcpy(wiener_info, ref_wiener_info, sizeof(*wiener_info));
-    return;
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR)) {
+      memcpy(wiener_info, av1_ref_from_wiener_bank(bank, k),
+             sizeof(*wiener_info));
+      if (bank->bank_size == 0) av1_add_to_wiener_bank(bank, wiener_info);
+      return;
+    }
   }
 #else
   (void)xd;
 #endif  // CONFIG_RST_MERGECOEFFS
+  WienerInfo *ref_wiener_info = av1_ref_from_wiener_bank(bank, 0);
   memset(wiener_info->vfilter, 0, sizeof(wiener_info->vfilter));
   memset(wiener_info->hfilter, 0, sizeof(wiener_info->hfilter));
 
@@ -2380,23 +2383,27 @@
   wiener_info->hfilter[WIENER_HALFWIN] =
       -2 * (wiener_info->hfilter[0] + wiener_info->hfilter[1] +
             wiener_info->hfilter[2]);
-  memcpy(ref_wiener_info, wiener_info, sizeof(*wiener_info));
+  // memcpy(ref_wiener_info, wiener_info, sizeof(*wiener_info));
+  av1_add_to_wiener_bank(bank, wiener_info);
 }
 
 static AOM_INLINE void read_sgrproj_filter(MACROBLOCKD *xd,
                                            SgrprojInfo *sgrproj_info,
-                                           SgrprojInfo *ref_sgrproj_info,
+                                           SgrprojInfoBank *bank,
                                            aom_reader *rb) {
 #if CONFIG_RST_MERGECOEFFS
-  const int equal =
-      aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR);
-  if (equal) {
-    memcpy(sgrproj_info, ref_sgrproj_info, sizeof(*sgrproj_info));
-    return;
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR)) {
+      memcpy(sgrproj_info, av1_ref_from_sgrproj_bank(bank, k),
+             sizeof(*sgrproj_info));
+      if (bank->bank_size == 0) av1_add_to_sgrproj_bank(bank, sgrproj_info);
+      return;
+    }
   }
 #else
   (void)xd;
 #endif  // CONFIG_RST_MERGECOEFFS
+  SgrprojInfo *ref_sgrproj_info = av1_ref_from_sgrproj_bank(bank, 0);
   sgrproj_info->ep = aom_read_literal(rb, SGRPROJ_PARAMS_BITS, ACCT_STR);
   const sgr_params_type *params = &av1_sgr_params[sgrproj_info->ep];
 
@@ -2427,21 +2434,23 @@
             ref_sgrproj_info->xqd[1] - SGRPROJ_PRJ_MIN1, ACCT_STR) +
         SGRPROJ_PRJ_MIN1;
   }
-
-  memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
+  // memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
+  av1_add_to_sgrproj_bank(bank, sgrproj_info);
 }
 
 #if CONFIG_WIENER_NONSEP
 static void read_wienerns_filter(MACROBLOCKD *xd, int is_uv, int ql,
                                  WienerNonsepInfo *wienerns_info,
-                                 WienerNonsepInfo *ref_wienerns_info,
-                                 aom_reader *rb) {
+                                 WienerNonsepInfoBank *bank, aom_reader *rb) {
 #if CONFIG_RST_MERGECOEFFS
-  const int equal =
-      aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR);
-  if (equal) {
-    memcpy(wienerns_info, ref_wienerns_info, sizeof(*wienerns_info));
-    return;
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (aom_read_symbol(rb, xd->tile_ctx->merged_param_cdf, 2, ACCT_STR)) {
+      memcpy(wienerns_info, av1_ref_from_wiener_nonsep_bank(bank, k),
+             sizeof(*wienerns_info));
+      if (bank->bank_size == 0)
+        av1_add_to_wiener_nonsep_bank(bank, wienerns_info);
+      return;
+    }
   }
 #else
   (void)xd;
@@ -2453,6 +2462,8 @@
       is_uv ? wnsf->y->ncoeffs + wnsf->uv->ncoeffs : wnsf->y->ncoeffs;
   const int(*wienerns_coeffs)[WIENERNS_COEFCFG_LEN] =
       is_uv ? wnsf->uv->coeffs : wnsf->y->coeffs;
+  WienerNonsepInfo *ref_wienerns_info =
+      av1_ref_from_wiener_nonsep_bank(bank, 0);
 
   // printf("Dec %s ", is_uv ? "UV:" : "Y: ");
   int reduce_step[WIENERNS_REDUCE_STEPS] = { 0 };
@@ -2517,7 +2528,8 @@
     // ref_wienerns_info->nsfilter[i]);
   }
   // printf("\n");
-  memcpy(ref_wienerns_info, wienerns_info, sizeof(*wienerns_info));
+  // memcpy(ref_wienerns_info, wienerns_info, sizeof(*wienerns_info));
+  av1_add_to_wiener_nonsep_bank(bank, wienerns_info);
 }
 #endif  // CONFIG_WIENER_NONSEP
 
@@ -2540,11 +2552,6 @@
 #if CONFIG_WIENER_NONSEP
   const int is_uv = (plane > 0);
 #endif  // CONFIG_WIENER_NONSEP
-  WienerInfo *wiener_info = xd->wiener_info + plane;
-  SgrprojInfo *sgrproj_info = xd->sgrproj_info + plane;
-#if CONFIG_WIENER_NONSEP
-  WienerNonsepInfo *wiener_nonsep_info = xd->wiener_nonsep_info + plane;
-#endif  // CONFIG_WIENER_NONSEP
 
   if (rsi->frame_restoration_type == RESTORE_SWITCHABLE) {
 #if CONFIG_LR_FLEX_SYNTAX
@@ -2565,15 +2572,17 @@
 #endif  // CONFIG_LR_FLEX_SYNTAX
     switch (rui->restoration_type) {
       case RESTORE_WIENER:
-        read_wiener_filter(xd, wiener_win, &rui->wiener_info, wiener_info, r);
+        read_wiener_filter(xd, wiener_win, &rui->wiener_info,
+                           &xd->wiener_info[plane], r);
         break;
       case RESTORE_SGRPROJ:
-        read_sgrproj_filter(xd, &rui->sgrproj_info, sgrproj_info, r);
+        read_sgrproj_filter(xd, &rui->sgrproj_info, &xd->sgrproj_info[plane],
+                            r);
         break;
 #if CONFIG_WIENER_NONSEP
       case RESTORE_WIENER_NONSEP:
         read_wienerns_filter(xd, is_uv, ql, &rui->wiener_nonsep_info,
-                             wiener_nonsep_info, r);
+                             &xd->wiener_nonsep_info[plane], r);
         break;
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
@@ -2586,7 +2595,8 @@
   } else if (rsi->frame_restoration_type == RESTORE_WIENER) {
     if (aom_read_symbol(r, xd->tile_ctx->wiener_restore_cdf[ql], 2, ACCT_STR)) {
       rui->restoration_type = RESTORE_WIENER;
-      read_wiener_filter(xd, wiener_win, &rui->wiener_info, wiener_info, r);
+      read_wiener_filter(xd, wiener_win, &rui->wiener_info,
+                         &xd->wiener_info[plane], r);
     } else {
       rui->restoration_type = RESTORE_NONE;
     }
@@ -2594,7 +2604,7 @@
     if (aom_read_symbol(r, xd->tile_ctx->sgrproj_restore_cdf[ql], 2,
                         ACCT_STR)) {
       rui->restoration_type = RESTORE_SGRPROJ;
-      read_sgrproj_filter(xd, &rui->sgrproj_info, sgrproj_info, r);
+      read_sgrproj_filter(xd, &rui->sgrproj_info, &xd->sgrproj_info[plane], r);
     } else {
       rui->restoration_type = RESTORE_NONE;
     }
@@ -2604,7 +2614,7 @@
                         ACCT_STR)) {
       rui->restoration_type = RESTORE_WIENER_NONSEP;
       read_wienerns_filter(xd, is_uv, ql, &rui->wiener_nonsep_info,
-                           wiener_nonsep_info, r);
+                           &xd->wiener_nonsep_info[plane], r);
     } else {
       rui->restoration_type = RESTORE_NONE;
     }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 3878696..471f097 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -51,6 +51,7 @@
 #include "av1/encoder/encodetxb.h"
 #include "av1/encoder/mcomp.h"
 #include "av1/encoder/palette.h"
+#include "av1/encoder/pickrst.h"
 #include "av1/encoder/segmentation.h"
 #include "av1/encoder/tokenize.h"
 
@@ -2584,17 +2585,24 @@
 
 static AOM_INLINE void write_wiener_filter(MACROBLOCKD *xd, int wiener_win,
                                            const WienerInfo *wiener_info,
-                                           WienerInfo *ref_wiener_info,
+                                           WienerInfoBank *bank,
                                            aom_writer *wb) {
 #if CONFIG_RST_MERGECOEFFS
-  const int equal = check_wiener_eq(wiener_info, ref_wiener_info);
-  aom_write_symbol(wb, equal, xd->tile_ctx->merged_param_cdf, 2);
-  if (equal) {
+  const int equal = check_wiener_bank_eq(bank, wiener_info);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
+    aom_write_symbol(wb, 1, xd->tile_ctx->merged_param_cdf, 2);
+    if (bank->bank_size == 0) av1_add_to_wiener_bank(bank, wiener_info);
     return;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
   }
 #else
   (void)xd;
 #endif  // CONFIG_RST_MERGECOEFFS
+  const WienerInfo *ref_wiener_info = av1_ref_from_wiener_bank(bank, 0);
   if (wiener_win == WIENER_WIN)
     aom_write_primitive_refsubexpfin(
         wb, WIENER_FILT_TAP0_MAXV - WIENER_FILT_TAP0_MINV + 1,
@@ -2633,23 +2641,31 @@
       WIENER_FILT_TAP2_SUBEXP_K,
       ref_wiener_info->hfilter[2] - WIENER_FILT_TAP2_MINV,
       wiener_info->hfilter[2] - WIENER_FILT_TAP2_MINV);
-  memcpy(ref_wiener_info, wiener_info, sizeof(*wiener_info));
+  // memcpy(ref_wiener_info, wiener_info, sizeof(*wiener_info));
+  av1_add_to_wiener_bank(bank, wiener_info);
+  return;
 }
 
 static AOM_INLINE void write_sgrproj_filter(MACROBLOCKD *xd,
                                             const SgrprojInfo *sgrproj_info,
-                                            SgrprojInfo *ref_sgrproj_info,
+                                            SgrprojInfoBank *bank,
                                             aom_writer *wb) {
 #if CONFIG_RST_MERGECOEFFS
-  const int equal = check_sgrproj_eq(sgrproj_info, ref_sgrproj_info);
-  aom_write_symbol(wb, equal, xd->tile_ctx->merged_param_cdf, 2);
-  if (equal) {
-    memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
+  const int equal = check_sgrproj_bank_eq(bank, sgrproj_info);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
+    aom_write_symbol(wb, 1, xd->tile_ctx->merged_param_cdf, 2);
+    if (bank->bank_size == 0) av1_add_to_sgrproj_bank(bank, sgrproj_info);
     return;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
   }
 #else
   (void)xd;
 #endif  // CONFIG_RST_MERGECOEFFS
+  const SgrprojInfo *ref_sgrproj_info = av1_ref_from_sgrproj_bank(bank, 0);
   aom_write_literal(wb, sgrproj_info->ep, SGRPROJ_PARAMS_BITS);
   const sgr_params_type *params = &av1_sgr_params[sgrproj_info->ep];
 
@@ -2674,28 +2690,35 @@
         ref_sgrproj_info->xqd[1] - SGRPROJ_PRJ_MIN1,
         sgrproj_info->xqd[1] - SGRPROJ_PRJ_MIN1);
   }
-
-  memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
+  // memcpy(ref_sgrproj_info, sgrproj_info, sizeof(*sgrproj_info));
+  av1_add_to_sgrproj_bank(bank, sgrproj_info);
+  return;
 }
 
 #if CONFIG_WIENER_NONSEP
-static void write_wienerns_filter(MACROBLOCKD *xd, int is_uv, int ql,
-                                  const WienerNonsepInfo *wienerns_info,
-                                  WienerNonsepInfo *ref_wienerns_info,
-                                  aom_writer *wb) {
+static AOM_INLINE void write_wienerns_filter(
+    MACROBLOCKD *xd, int is_uv, int ql, const WienerNonsepInfo *wienerns_info,
+    WienerNonsepInfoBank *bank, aom_writer *wb) {
   const WienernsFilterConfigPairType *wnsf =
       get_wienerns_filters(xd->base_qindex);
 #if CONFIG_RST_MERGECOEFFS
-  const int equal =
-      check_wienerns_eq(is_uv, wienerns_info, ref_wienerns_info, wnsf);
-  aom_write_symbol(wb, equal, xd->tile_ctx->merged_param_cdf, 2);
-  if (equal) {
-    memcpy(ref_wienerns_info, wienerns_info, sizeof(*wienerns_info));
+  const int equal = check_wienerns_bank_eq(is_uv, bank, wienerns_info, wnsf);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
+    aom_write_symbol(wb, 1, xd->tile_ctx->merged_param_cdf, 2);
+    if (bank->bank_size == 0)
+      av1_add_to_wiener_nonsep_bank(bank, wienerns_info);
     return;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      aom_write_symbol(wb, 0, xd->tile_ctx->merged_param_cdf, 2);
   }
 #else
   (void)xd;
 #endif  // CONFIG_RST_MERGECOEFFS
+  WienerNonsepInfo *ref_wienerns_info =
+      av1_ref_from_wiener_nonsep_bank(bank, 0);
   int beg_feat = is_uv ? wnsf->y->ncoeffs : 0;
   int end_feat =
       is_uv ? wnsf->y->ncoeffs + wnsf->uv->ncoeffs : wnsf->y->ncoeffs;
@@ -2782,7 +2805,9 @@
 #endif  // CONFIG_LR_4PART_CODE
   }
   // printf("\n");
-  memcpy(ref_wienerns_info, wienerns_info, sizeof(*wienerns_info));
+  // memcpy(ref_wienerns_info, wienerns_info, sizeof(*wienerns_info));
+  av1_add_to_wiener_nonsep_bank(bank, wienerns_info);
+  return;
 }
 #endif  // CONFIG_WIENER_NONSEP
 
@@ -2800,11 +2825,6 @@
 #if CONFIG_WIENER_NONSEP
   const int is_uv = (plane > 0);
 #endif  // CONFIG_WIENER_NONSEP
-  WienerInfo *ref_wiener_info = &xd->wiener_info[plane];
-  SgrprojInfo *ref_sgrproj_info = &xd->sgrproj_info[plane];
-#if CONFIG_WIENER_NONSEP
-  WienerNonsepInfo *ref_wiener_nonsep_info = &xd->wiener_nonsep_info[plane];
-#endif  // CONFIG_WIENER_NONSEP
 
   RestorationType unit_rtype = rui->restoration_type;
 #if CONFIG_LR_FLEX_SYNTAX
@@ -2839,16 +2859,17 @@
 
     switch (unit_rtype) {
       case RESTORE_WIENER:
-        write_wiener_filter(xd, wiener_win, &rui->wiener_info, ref_wiener_info,
-                            w);
+        write_wiener_filter(xd, wiener_win, &rui->wiener_info,
+                            &xd->wiener_info[plane], w);
         break;
       case RESTORE_SGRPROJ:
-        write_sgrproj_filter(xd, &rui->sgrproj_info, ref_sgrproj_info, w);
+        write_sgrproj_filter(xd, &rui->sgrproj_info, &xd->sgrproj_info[plane],
+                             w);
         break;
 #if CONFIG_WIENER_NONSEP
       case RESTORE_WIENER_NONSEP:
         write_wienerns_filter(xd, is_uv, ql, &rui->wiener_nonsep_info,
-                              ref_wiener_nonsep_info, w);
+                              &xd->wiener_nonsep_info[plane], w);
         break;
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
@@ -2865,8 +2886,8 @@
     ++counts->wiener_restore[unit_rtype != RESTORE_NONE];
 #endif
     if (unit_rtype != RESTORE_NONE) {
-      write_wiener_filter(xd, wiener_win, &rui->wiener_info, ref_wiener_info,
-                          w);
+      write_wiener_filter(xd, wiener_win, &rui->wiener_info,
+                          &xd->wiener_info[plane], w);
     }
   } else if (frame_rtype == RESTORE_SGRPROJ) {
     aom_write_symbol(w, unit_rtype != RESTORE_NONE,
@@ -2875,7 +2896,7 @@
     ++counts->sgrproj_restore[unit_rtype != RESTORE_NONE];
 #endif
     if (unit_rtype != RESTORE_NONE) {
-      write_sgrproj_filter(xd, &rui->sgrproj_info, ref_sgrproj_info, w);
+      write_sgrproj_filter(xd, &rui->sgrproj_info, &xd->sgrproj_info[plane], w);
     }
 #if CONFIG_WIENER_NONSEP
   } else if (frame_rtype == RESTORE_WIENER_NONSEP) {
@@ -2886,7 +2907,7 @@
 #endif  // CONFIG_ENTROPY_STATS
     if (unit_rtype != RESTORE_NONE) {
       write_wienerns_filter(xd, is_uv, ql, &rui->wiener_nonsep_info,
-                            ref_wiener_nonsep_info, w);
+                            &xd->wiener_nonsep_info[plane], w);
     }
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
diff --git a/av1/encoder/pickrst.c b/av1/encoder/pickrst.c
index 2215461..f9546c6 100644
--- a/av1/encoder/pickrst.c
+++ b/av1/encoder/pickrst.c
@@ -172,10 +172,10 @@
 
   // sgrproj and wiener are initialised by rsc_on_tile when starting the first
   // tile in the frame.
-  SgrprojInfo sgrproj;
-  WienerInfo wiener;
+  WienerInfoBank wiener;
+  SgrprojInfoBank sgrproj;
 #if CONFIG_WIENER_NONSEP
-  WienerNonsepInfo wiener_nonsep;
+  WienerNonsepInfoBank wiener_nonsep;
 #if CONFIG_WIENER_NONSEP_CROSS_FILT
   const uint8_t *luma;
   int luma_stride;
@@ -190,13 +190,37 @@
   AV1PixelRect tile_rect;
 } RestSearchCtxt;
 
+#if CONFIG_RST_MERGECOEFFS
+typedef struct RstUnitSnapshot {
+  RestorationTileLimits limits;
+  int rest_unit_idx;  // update filter value and sse as needed
+  int64_t current_sse;
+  int64_t current_bits;
+  int64_t merge_sse;
+  int64_t merge_bits;
+  // Wiener filter info
+  int64_t M[WIENER_WIN2];
+  int64_t H[WIENER_WIN2 * WIENER_WIN2];
+  WienerInfoBank ref_wiener;
+#if CONFIG_WIENER_NONSEP
+  // Nonseparable Wiener filter info
+  double A[WIENERNS_MAX * WIENERNS_MAX];
+  double b[WIENERNS_MAX];
+  WienerNonsepInfoBank ref_wiener_nonsep;
+#endif  // CONFIG_WIENER_NONSEP
+  // Sgrproj filter info
+  SgrprojInfo unit_sgrproj;
+  SgrprojInfoBank ref_sgrproj;
+} RstUnitSnapshot;
+#endif  // CONFIG_RST_MERGECOEFFS
+
 static AOM_INLINE void rsc_on_tile(void *priv) {
   RestSearchCtxt *rsc = (RestSearchCtxt *)priv;
-  set_default_sgrproj(&rsc->sgrproj);
-  set_default_wiener(&rsc->wiener);
+  av1_reset_wiener_bank(&rsc->wiener);
+  av1_reset_sgrproj_bank(&rsc->sgrproj);
 #if CONFIG_WIENER_NONSEP
-  set_default_wiener_nonsep(&rsc->wiener_nonsep,
-                            rsc->cm->quant_params.base_qindex);
+  av1_reset_wiener_nonsep_bank(&rsc->wiener_nonsep,
+                               rsc->cm->quant_params.base_qindex);
 #endif  // CONFIG_WIENER_NONSEP
   rsc->tile_stripe0 = 0;
 }
@@ -907,8 +931,12 @@
 }
 
 static int64_t count_sgrproj_bits(SgrprojInfo *sgrproj_info,
-                                  SgrprojInfo *ref_sgrproj_info) {
-  int64_t bits = SGRPROJ_PARAMS_BITS;
+                                  const ModeCosts *mode_costs,
+                                  const SgrprojInfoBank *bank) {
+  (void)mode_costs;
+  int64_t bits = 0;
+  const SgrprojInfo *ref_sgrproj_info = av1_constref_from_sgrproj_bank(bank, 0);
+  bits += SGRPROJ_PARAMS_BITS;
   const sgr_params_type *params = &av1_sgr_params[sgrproj_info->ep];
   if (params->r[0] > 0)
     bits += aom_count_primitive_refsubexpfin(
@@ -923,6 +951,25 @@
   return bits << AV1_PROB_COST_SHIFT;
 }
 
+#if CONFIG_RST_MERGECOEFFS
+static int64_t count_sgrproj_bits_all(SgrprojInfo *sgrproj_info,
+                                      const ModeCosts *mode_costs,
+                                      const SgrprojInfoBank *bank) {
+  int64_t bits = 0;
+  const int *merged_param_cost = mode_costs->merged_param_cost;
+  const int equal = check_sgrproj_bank_eq(bank, sgrproj_info);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k) bits += merged_param_cost[0];
+    bits += merged_param_cost[1];
+    return bits;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      bits += merged_param_cost[0];
+  }
+  return bits + count_sgrproj_bits(sgrproj_info, mode_costs, bank);
+}
+#endif  // CONFIG_RST_MERGECOEFFS
+
 static AOM_INLINE void search_sgrproj(const RestorationTileLimits *limits,
                                       const AV1PixelRect *tile,
                                       int rest_unit_idx, void *priv,
@@ -967,9 +1014,10 @@
 
 #if CONFIG_RST_MERGECOEFFS
   Vector *current_unit_stack = rsc->unit_stack;
-  int64_t bits_nomerge = x->mode_costs.sgrproj_restore_cost[1] +
-                         x->mode_costs.merged_param_cost[0] +
-                         count_sgrproj_bits(&rusi->sgrproj, &rsc->sgrproj);
+  int64_t bits_nomerge =
+      x->mode_costs.sgrproj_restore_cost[1] +
+      // x->mode_costs.merged_param_cost[0] +
+      count_sgrproj_bits_all(&rusi->sgrproj, &x->mode_costs, &rsc->sgrproj);
   double cost_nomerge = RDCOST_DBL_WITH_NATIVE_BD_DIST(
       x->rdmult, bits_nomerge >> 4, rusi->sse[RESTORE_SGRPROJ], bit_depth);
   const double dual_sgr_penalty_sf_mult =
@@ -997,7 +1045,9 @@
   unit_snapshot.ref_sgrproj = rsc->sgrproj;
   // If current_unit_stack is empty, we can leave early.
   if (aom_vector_is_empty(current_unit_stack)) {
-    if (rtype == RESTORE_SGRPROJ) rsc->sgrproj = rusi->sgrproj;
+    if (rtype == RESTORE_SGRPROJ)
+      av1_add_to_sgrproj_bank(&rsc->sgrproj, &rusi->sgrproj);
+    // rsc->sgrproj = rusi->sgrproj;
     aom_vector_push_back(current_unit_stack, &unit_snapshot);
     return;
   }
@@ -1005,12 +1055,15 @@
   // filter for the stack - we don't want to perform another merge and
   // get a less optimal filter, but we want to continue building the stack.
   if (rtype == RESTORE_SGRPROJ &&
-      check_sgrproj_eq(&rusi->sgrproj, &rsc->sgrproj)) {
+      check_sgrproj_eq(&rusi->sgrproj,
+                       av1_ref_from_sgrproj_bank(&rsc->sgrproj, 0))) {
+    /*
     rsc->bits -= bits_nomerge;
     rsc->bits += x->mode_costs.sgrproj_restore_cost[1] +
                  x->mode_costs.merged_param_cost[1];
     unit_snapshot.current_bits = x->mode_costs.sgrproj_restore_cost[1] +
                                  x->mode_costs.merged_param_cost[1];
+                                 */
     aom_vector_push_back(current_unit_stack, &unit_snapshot);
     return;
   }
@@ -1047,8 +1100,9 @@
     if (aom_iterator_equals(&(listed_unit), &begin)) {
       old_unit->merge_bits =
           x->mode_costs.sgrproj_restore_cost[1] +
-          x->mode_costs.merged_param_cost[0] +
-          count_sgrproj_bits(&rui_temp.sgrproj_info, &old_unit->ref_sgrproj);
+          // x->mode_costs.merged_param_cost[0] +
+          count_sgrproj_bits_all(&rui_temp.sgrproj_info, &x->mode_costs,
+                                 &old_unit->ref_sgrproj);
     } else {
       old_unit->merge_bits = x->mode_costs.sgrproj_restore_cost[1] +
                              x->mode_costs.merged_param_cost[1];
@@ -1074,7 +1128,8 @@
       old_unit->current_sse = old_unit->merge_sse;
       old_unit->current_bits = old_unit->merge_bits;
     }
-    rsc->sgrproj = rui_temp.sgrproj_info;
+    av1_upd_to_sgrproj_bank(&rsc->sgrproj, 0, &rui_temp.sgrproj_info);
+    // rsc->sgrproj = rui_temp.sgrproj_info;
   } else {
     // Copy current unit from the top of the stack.
     memset(&unit_snapshot, 0, sizeof(unit_snapshot));
@@ -1082,7 +1137,8 @@
     // RESTORE_SGRPROJ units become start of new stack, and
     // RESTORE_NONE units are discarded.
     if (rtype == RESTORE_SGRPROJ) {
-      rsc->sgrproj = rusi->sgrproj;
+      // rsc->sgrproj = rusi->sgrproj;
+      av1_add_to_sgrproj_bank(&rsc->sgrproj, &rusi->sgrproj);
       aom_vector_clear(current_unit_stack);
       aom_vector_push_back(current_unit_stack, &unit_snapshot);
     } else {
@@ -1090,8 +1146,9 @@
     }
   }
 #else   // CONFIG_RST_MERGECOEFFS
-  const int64_t bits_sgr = x->mode_costs.sgrproj_restore_cost[1] +
-                           count_sgrproj_bits(&rusi->sgrproj, &rsc->sgrproj);
+  const int64_t bits_sgr =
+      x->mode_costs.sgrproj_restore_cost[1] +
+      count_sgrproj_bits(&rusi->sgrproj, &x->mode_costs, &rsc->sgrproj);
   double cost_sgr = RDCOST_DBL_WITH_NATIVE_BD_DIST(
       x->rdmult, bits_sgr >> 4, rusi->sse[RESTORE_SGRPROJ], bit_depth);
   if (rusi->sgrproj.ep < 10)
@@ -1104,7 +1161,9 @@
 
   rsc->sse += rusi->sse[rtype];
   rsc->bits += (cost_sgr < cost_none) ? bits_sgr : bits_none;
-  if (cost_sgr < cost_none) rsc->sgrproj = rusi->sgrproj;
+  if (cost_sgr < cost_none)
+    av1_add_to_sgrproj_bank(&rsc->sgrproj, &rusi->sgrproj);
+    // rsc->sgrproj = rusi->sgrproj;
 #endif  // CONFIG_RST_MERGECOEFFS
 }
 
@@ -1520,9 +1579,12 @@
 }
 #endif  // CONFIG_PC_WIENER
 
-static int64_t count_wiener_bits(int wiener_win, WienerInfo *wiener_info,
-                                 const WienerInfo *ref_wiener_info) {
+static int64_t count_wiener_bits(int wiener_win, const ModeCosts *mode_costs,
+                                 WienerInfo *wiener_info,
+                                 const WienerInfoBank *bank) {
+  (void)mode_costs;
   int64_t bits = 0;
+  const WienerInfo *ref_wiener_info = av1_constref_from_wiener_bank(bank, 0);
   if (wiener_win == WIENER_WIN)
     bits += aom_count_primitive_refsubexpfin(
         WIENER_FILT_TAP0_MAXV - WIENER_FILT_TAP0_MINV + 1,
@@ -1558,6 +1620,26 @@
   return bits << AV1_PROB_COST_SHIFT;
 }
 
+#if CONFIG_RST_MERGECOEFFS
+static int64_t count_wiener_bits_all(int wiener_win,
+                                     const ModeCosts *mode_costs,
+                                     WienerInfo *wiener_info,
+                                     const WienerInfoBank *bank) {
+  int64_t bits = 0;
+  const int *merged_param_cost = mode_costs->merged_param_cost;
+  const int equal = check_wiener_bank_eq(bank, wiener_info);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k) bits += merged_param_cost[0];
+    bits += merged_param_cost[1];
+    return bits;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      bits += merged_param_cost[0];
+  }
+  return bits + count_wiener_bits(wiener_win, mode_costs, wiener_info, bank);
+}
+#endif  // CONFIG_RST_MERGECOEFFS
+
 #if CONFIG_WIENER_NONSEP || CONFIG_RST_MERGECOEFFS
 
 // If limits != NULL, calculates error for current restoration unit.
@@ -1585,7 +1667,7 @@
 #endif  // CONFIG_WIENER_NONSEP
 
 #define USE_WIENER_REFINEMENT_SEARCH 1
-static int64_t finer_tile_search_wiener(const RestSearchCtxt *rsc,
+static int64_t finer_tile_search_wiener(RestSearchCtxt *rsc,
                                         const RestorationTileLimits *limits,
                                         const AV1PixelRect *tile,
                                         RestorationUnitInfo *rui,
@@ -1601,7 +1683,8 @@
   WienerInfo *plane_wiener = &rui->wiener_info;
 
   const MACROBLOCK *const x = rsc->x;
-  int64_t bits = count_wiener_bits(wiener_win, plane_wiener, &rsc->wiener);
+  int64_t bits =
+      count_wiener_bits(wiener_win, &x->mode_costs, plane_wiener, &rsc->wiener);
   double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(x->rdmult, bits >> 4, err,
                                                rsc->cm->seq_params.bit_depth);
   int tap_min[] = { WIENER_FILT_TAP0_MINV, WIENER_FILT_TAP1_MINV,
@@ -1624,8 +1707,8 @@
 #else   // CONFIG_RST_MERGECOEFFS
           int64_t err2 = try_restoration_unit(rsc, limits, tile, rui);
 #endif  // CONFIG_RST_MERGECOEFFS
-          int64_t bits2 =
-              count_wiener_bits(wiener_win, plane_wiener, &rsc->wiener);
+          int64_t bits2 = count_wiener_bits(wiener_win, &x->mode_costs,
+                                            plane_wiener, &rsc->wiener);
           double cost2 = RDCOST_DBL_WITH_NATIVE_BD_DIST(
               x->rdmult, bits2 >> 4, err2, rsc->cm->seq_params.bit_depth);
           if (cost2 > cost) {
@@ -1653,8 +1736,8 @@
 #else   // CONFIG_RST_MERGECOEFFS
           int64_t err2 = try_restoration_unit(rsc, limits, tile, rui);
 #endif  // CONFIG_RST_MERGECOEFFS
-          int64_t bits2 =
-              count_wiener_bits(wiener_win, plane_wiener, &rsc->wiener);
+          int64_t bits2 = count_wiener_bits(wiener_win, &x->mode_costs,
+                                            plane_wiener, &rsc->wiener);
           double cost2 = RDCOST_DBL_WITH_NATIVE_BD_DIST(
               x->rdmult, bits2 >> 4, err2, rsc->cm->seq_params.bit_depth);
           if (cost2 > cost) {
@@ -1683,8 +1766,8 @@
 #else   // CONFIG_RST_MERGECOEFFS
           int64_t err2 = try_restoration_unit(rsc, limits, tile, rui);
 #endif  // CONFIG_RST_MERGECOEFFS
-          int64_t bits2 =
-              count_wiener_bits(wiener_win, plane_wiener, &rsc->wiener);
+          int64_t bits2 = count_wiener_bits(wiener_win, &x->mode_costs,
+                                            plane_wiener, &rsc->wiener);
           double cost2 = RDCOST_DBL_WITH_NATIVE_BD_DIST(
               x->rdmult, bits2 >> 4, err2, rsc->cm->seq_params.bit_depth);
           if (cost2 > cost) {
@@ -1712,8 +1795,8 @@
 #else   // CONFIG_RST_MERGECOEFFS
           int64_t err2 = try_restoration_unit(rsc, limits, tile, rui);
 #endif  // CONFIG_RST_MERGECOEFFS
-          int64_t bits2 =
-              count_wiener_bits(wiener_win, plane_wiener, &rsc->wiener);
+          int64_t bits2 = count_wiener_bits(wiener_win, &x->mode_costs,
+                                            plane_wiener, &rsc->wiener);
           double cost2 = RDCOST_DBL_WITH_NATIVE_BD_DIST(
               x->rdmult, bits2 >> 4, err2, rsc->cm->seq_params.bit_depth);
           if (cost2 > cost) {
@@ -1841,10 +1924,10 @@
       rsc->cm->seq_params.bit_depth);
 #if CONFIG_RST_MERGECOEFFS
   Vector *current_unit_stack = rsc->unit_stack;
-  int64_t bits_nomerge =
-      x->mode_costs.wiener_restore_cost[1] +
-      x->mode_costs.merged_param_cost[0] +
-      count_wiener_bits(wiener_win, &rusi->wiener, &rsc->wiener);
+  int64_t bits_nomerge = x->mode_costs.wiener_restore_cost[1] +
+                         // x->mode_costs.merged_param_cost[0] +
+                         count_wiener_bits_all(wiener_win, &x->mode_costs,
+                                               &rusi->wiener, &rsc->wiener);
   double cost_nomerge = RDCOST_DBL_WITH_NATIVE_BD_DIST(
       x->rdmult, bits_nomerge >> 4, rusi->sse[RESTORE_WIENER],
       rsc->cm->seq_params.bit_depth);
@@ -1870,19 +1953,25 @@
   unit_snapshot.ref_wiener = rsc->wiener;
   // If current_unit_stack is empty, we can leave early.
   if (aom_vector_is_empty(current_unit_stack)) {
-    if (rtype == RESTORE_WIENER) rsc->wiener = rusi->wiener;
+    if (rtype == RESTORE_WIENER)
+      av1_add_to_wiener_bank(&rsc->wiener, &rusi->wiener);
+    // rsc->wiener = rusi->wiener;
     aom_vector_push_back(current_unit_stack, &unit_snapshot);
     return;
   }
   // Handles special case where no-merge filter is equal to merged
   // filter for the stack - we don't want to perform another merge and
   // get a less optimal filter, but we want to continue building the stack.
-  if (rtype == RESTORE_WIENER && check_wiener_eq(&rusi->wiener, &rsc->wiener)) {
+  if (rtype == RESTORE_WIENER &&
+      check_wiener_eq(&rusi->wiener,
+                      av1_ref_from_wiener_bank(&rsc->wiener, 0))) {
+    /*
     rsc->bits -= bits_nomerge;
     rsc->bits += x->mode_costs.wiener_restore_cost[1] +
                  x->mode_costs.merged_param_cost[1];
     unit_snapshot.current_bits = x->mode_costs.wiener_restore_cost[1] +
                                  x->mode_costs.merged_param_cost[1];
+                 */
     aom_vector_push_back(current_unit_stack, &unit_snapshot);
     return;
   }
@@ -1942,9 +2031,9 @@
     if (aom_iterator_equals(&(listed_unit), &begin)) {
       old_unit->merge_bits =
           x->mode_costs.wiener_restore_cost[1] +
-          x->mode_costs.merged_param_cost[0] +
-          count_wiener_bits(wiener_win, &rui_temp.wiener_info,
-                            &old_unit->ref_wiener);
+          // x->mode_costs.merged_param_cost[0] +
+          count_wiener_bits_all(wiener_win, &x->mode_costs,
+                                &rui_temp.wiener_info, &old_unit->ref_wiener);
     } else {
       old_unit->merge_bits = x->mode_costs.wiener_restore_cost[1] +
                              x->mode_costs.merged_param_cost[1];
@@ -1968,7 +2057,8 @@
       old_unit->current_sse = old_unit->merge_sse;
       old_unit->current_bits = old_unit->merge_bits;
     }
-    rsc->wiener = rui_temp.wiener_info;
+    // rsc->wiener = rui_temp.wiener_info;
+    av1_upd_to_wiener_bank(&rsc->wiener, 0, &rui_temp.wiener_info);
   } else {
     // Copy current unit from the top of the stack.
     memset(&unit_snapshot, 0, sizeof(unit_snapshot));
@@ -1976,7 +2066,8 @@
     // RESTORE_WIENER units become start of new stack, and
     // RESTORE_NONE units are discarded.
     if (rtype == RESTORE_WIENER) {
-      rsc->wiener = rusi->wiener;
+      // rsc->wiener = rusi->wiener;
+      av1_add_to_wiener_bank(&rsc->wiener, &rusi->wiener);
       aom_vector_clear(current_unit_stack);
       aom_vector_push_back(current_unit_stack, &unit_snapshot);
     } else {
@@ -1985,9 +2076,9 @@
   }
 
 #else   // CONFIG_RST_MERGECOEFFS
-  const int64_t bits_wiener =
-      x->mode_costs.wiener_restore_cost[1] +
-      count_wiener_bits(wiener_win, &rusi->wiener, &rsc->wiener);
+  const int64_t bits_wiener = x->mode_costs.wiener_restore_cost[1] +
+                              count_wiener_bits(wiener_win, &x->mode_costs,
+                                                &rusi->wiener, &rsc->wiener);
 
   double cost_wiener = RDCOST_DBL_WITH_NATIVE_BD_DIST(
       x->rdmult, bits_wiener >> 4, rusi->sse[RESTORE_WIENER],
@@ -2007,7 +2098,9 @@
 
   rsc->sse += rusi->sse[rtype];
   rsc->bits += (cost_wiener < cost_none) ? bits_wiener : bits_none;
-  if (cost_wiener < cost_none) rsc->wiener = rusi->wiener;
+  if (cost_wiener < cost_none)
+    // rsc->wiener = rusi->wiener;
+    av1_add_to_wiener_bank(&rsc->wiener, &rusi->wiener);
 #endif  // CONFIG_RST_MERGECOEFFS
 }
 
@@ -2030,22 +2123,25 @@
 }
 
 #if CONFIG_WIENER_NONSEP
-static int64_t count_wienerns_bits(int plane, const int (*reduce_cost)[2],
-#if CONFIG_LR_4PART_CODE
-                                   const int (*cost_4part)[4],
-#endif  // CONFIG_LR_4PART_CODE
+static int64_t count_wienerns_bits(int plane, const ModeCosts *mode_costs,
                                    WienerNonsepInfo *wienerns_info,
-                                   const WienerNonsepInfo *ref_wienerns_info,
+                                   const WienerNonsepInfoBank *bank,
                                    const WienernsFilterConfigPairType *wnsf) {
+  (void)mode_costs;
   int is_uv = (plane != AOM_PLANE_Y);
+  int64_t bits = 0;
+  const WienerNonsepInfo *ref_wienerns_info =
+      av1_constref_from_wiener_nonsep_bank(bank, 0);
+  const int(*reduce_cost)[2] = mode_costs->wiener_nonsep_reduce_cost;
+#if CONFIG_LR_4PART_CODE
+  const int(*cost_4part)[4] = mode_costs->wiener_nonsep_4part_cost;
+#endif  // CONFIG_LR_4PART_CODE
   int beg_feat = is_uv ? wnsf->y->ncoeffs : 0;
   int end_feat =
       is_uv ? wnsf->y->ncoeffs + wnsf->uv->ncoeffs : wnsf->y->ncoeffs;
   const int(*wienerns_coeffs)[WIENERNS_COEFCFG_LEN] =
       is_uv ? wnsf->uv->coeffs : wnsf->y->coeffs;
 
-  int64_t bits = 0;
-
   int reduce_step[WIENERNS_REDUCE_STEPS] = { 0 };
   if (end_feat - beg_feat > 1 && wienerns_info->nsfilter[end_feat - 1] == 0) {
     reduce_step[WIENERNS_REDUCE_STEPS - 1] = 1;
@@ -2109,6 +2205,28 @@
   return bits;
 }
 
+#if CONFIG_RST_MERGECOEFFS
+static int64_t count_wienerns_bits_all(
+    int plane, const ModeCosts *mode_costs, WienerNonsepInfo *wienerns_info,
+    const WienerNonsepInfoBank *bank,
+    const WienernsFilterConfigPairType *wnsf) {
+  int is_uv = (plane != AOM_PLANE_Y);
+  int64_t bits = 0;
+  const int *merged_param_cost = mode_costs->merged_param_cost;
+  const int equal = check_wienerns_bank_eq(is_uv, bank, wienerns_info, wnsf);
+  if (equal != -1) {
+    for (int k = 0; k < equal; ++k) bits += merged_param_cost[0];
+    bits += merged_param_cost[1];
+    return bits;
+  } else {
+    for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k)
+      bits += merged_param_cost[0];
+  }
+  return bits +
+         count_wienerns_bits(plane, mode_costs, wienerns_info, bank, wnsf);
+}
+#endif  // CONFIG_RST_MERGECOEFFS
+
 static int16_t quantize(double x, int16_t minv, int16_t n, int prec_bits) {
   int scale_x = (int)round(x * (1 << prec_bits));
   scale_x = AOMMAX(scale_x, minv);
@@ -2120,7 +2238,7 @@
 #define MIN(a, b) ((a) > (b) ? (b) : (a))
 
 static int64_t finer_tile_search_wienerns(
-    const RestSearchCtxt *rsc, const RestorationTileLimits *limits,
+    RestSearchCtxt *rsc, const RestorationTileLimits *limits,
     const AV1PixelRect *tile_rect, RestorationUnitInfo *rui,
     const WienernsFilterConfigPairType *wnsf, int ext_search) {
   assert(rsc->plane == rui->plane);
@@ -2129,12 +2247,8 @@
   WienerNonsepInfo best = curr;
   int64_t best_err = calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
 
-  int64_t best_bits =
-      count_wienerns_bits(rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-                          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-                          &curr, &rsc->wiener_nonsep, wnsf);
+  int64_t best_bits = count_wienerns_bits(rsc->plane, &x->mode_costs, &curr,
+                                          &rsc->wiener_nonsep, wnsf);
   double best_cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
       x->rdmult, best_bits >> 4, best_err, rsc->cm->seq_params.bit_depth);
   // printf("Err  pre = %"PRId64", cost = %f\n", best_err, best_cost);
@@ -2166,12 +2280,9 @@
         rui->wiener_nonsep_info.nsfilter[i] = ci;
         const int64_t err =
             calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-        const int64_t bits = count_wienerns_bits(
-            rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-            x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-            &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+        const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                                 &rui->wiener_nonsep_info,
+                                                 &rsc->wiener_nonsep, wnsf);
         const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
             x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
         if (cost < best_cost) {
@@ -2203,12 +2314,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 1] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2229,12 +2337,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 3] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2259,12 +2364,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 5] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2293,12 +2395,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 7] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2318,12 +2417,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 2] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2346,12 +2442,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 4] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2378,12 +2471,9 @@
       rui->wiener_nonsep_info.nsfilter[end_feat - 6] = 0;
       const int64_t err =
           calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-      const int64_t bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+      const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                               &rui->wiener_nonsep_info,
+                                               &rsc->wiener_nonsep, wnsf);
       const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
           x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
       if (cost < best_cost) {
@@ -2430,12 +2520,9 @@
         }
         const int64_t err =
             calc_finer_tile_search_error(rsc, limits, tile_rect, rui);
-        const int64_t bits = count_wienerns_bits(
-            rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-            x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-            &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+        const int64_t bits = count_wienerns_bits(rsc->plane, &x->mode_costs,
+                                                 &rui->wiener_nonsep_info,
+                                                 &rsc->wiener_nonsep, wnsf);
         const double cost = RDCOST_DBL_WITH_NATIVE_BD_DIST(
             x->rdmult, bits >> 4, err, rsc->cm->seq_params.bit_depth);
         if (cost < best_cost) {
@@ -2592,12 +2679,9 @@
         //     finer_tile_search_wienerns(rsc, limits, tile_rect, rui, wnsf, 0);
         // for better results at the expense of higger encoder complexity.
         if (real_errq > real_sse) break;
-        int64_t bits = count_wienerns_bits(
-            rui->plane, rsc->x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-            rsc->x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-            &rui->wiener_nonsep_info, &rsc->wiener_nonsep, wnsf);
+        int64_t bits = count_wienerns_bits(rui->plane, &rsc->x->mode_costs,
+                                           &rui->wiener_nonsep_info,
+                                           &rsc->wiener_nonsep, wnsf);
         double cost =
             RDCOST_DBL_WITH_NATIVE_BD_DIST(rsc->x->rdmult, bits >> 4, real_errq,
                                            rsc->cm->seq_params.bit_depth);
@@ -2686,14 +2770,11 @@
 #if CONFIG_RST_MERGECOEFFS
     int is_uv = (rsc->plane != AOM_PLANE_Y);
     Vector *current_unit_stack = rsc->unit_stack;
-    int64_t bits_nomerge =
-        x->mode_costs.wiener_nonsep_restore_cost[1] +
-        x->mode_costs.merged_param_cost[0] +
-        count_wienerns_bits(rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-                            x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-                            &rusi->wiener_nonsep, &rsc->wiener_nonsep, wnsf);
+    int64_t bits_nomerge = x->mode_costs.wiener_nonsep_restore_cost[1] +
+                           // x->mode_costs.merged_param_cost[0] +
+                           count_wienerns_bits_all(rsc->plane, &x->mode_costs,
+                                                   &rusi->wiener_nonsep,
+                                                   &rsc->wiener_nonsep, wnsf);
     double cost_nomerge = RDCOST_DBL_WITH_NATIVE_BD_DIST(
         x->rdmult, bits_nomerge >> 4, rusi->sse[RESTORE_WIENER_NONSEP],
         bit_depth);
@@ -2720,7 +2801,9 @@
     // If current_unit_stack is empty, we can leave early.
     if (aom_vector_is_empty(current_unit_stack)) {
       if (rtype == RESTORE_WIENER_NONSEP)
-        rsc->wiener_nonsep = rusi->wiener_nonsep;
+        // rsc->wiener_nonsep = rusi->wiener_nonsep;
+        av1_add_to_wiener_nonsep_bank(&rsc->wiener_nonsep,
+                                      &rusi->wiener_nonsep);
       aom_vector_push_back(current_unit_stack, &unit_snapshot);
       return;
     }
@@ -2728,13 +2811,16 @@
     // filter for the stack - we don't want to perform another merge and
     // get a less optimal filter, but we want to continue building the stack.
     if (rtype == RESTORE_WIENER_NONSEP &&
-        check_wienerns_eq(is_uv, &rusi->wiener_nonsep, &rsc->wiener_nonsep,
-                          wnsf)) {
+        check_wienerns_eq(
+            is_uv, &rusi->wiener_nonsep,
+            av1_ref_from_wiener_nonsep_bank(&rsc->wiener_nonsep, 0), wnsf)) {
+      /*
       rsc->bits -= bits_nomerge;
       rsc->bits += x->mode_costs.wiener_nonsep_restore_cost[1] +
                    x->mode_costs.merged_param_cost[1];
       unit_snapshot.current_bits = x->mode_costs.wiener_nonsep_restore_cost[1] +
                                    x->mode_costs.merged_param_cost[1];
+                                   */
       aom_vector_push_back(current_unit_stack, &unit_snapshot);
       return;
     }
@@ -2822,14 +2908,10 @@
       if (aom_iterator_equals(&(listed_unit), &begin)) {
         old_unit->merge_bits =
             x->mode_costs.wiener_nonsep_restore_cost[1] +
-            x->mode_costs.merged_param_cost[0] +
-            count_wienerns_bits(rsc->plane,
-                                x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-                                x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-                                &rui_temp.wiener_nonsep_info,
-                                &old_unit->ref_wiener_nonsep, wnsf);
+            // x->mode_costs.merged_param_cost[0] +
+            count_wienerns_bits_all(rsc->plane, &x->mode_costs,
+                                    &rui_temp.wiener_nonsep_info,
+                                    &old_unit->ref_wiener_nonsep, wnsf);
       } else {
         old_unit->merge_bits = x->mode_costs.wiener_nonsep_restore_cost[1] +
                                x->mode_costs.merged_param_cost[1];
@@ -2852,7 +2934,9 @@
         old_unit->current_sse = old_unit->merge_sse;
         old_unit->current_bits = old_unit->merge_bits;
       }
-      rsc->wiener_nonsep = rui_temp.wiener_nonsep_info;
+      // rsc->wiener_nonsep = rui_temp.wiener_nonsep_info;
+      av1_upd_to_wiener_nonsep_bank(&rsc->wiener_nonsep, 0,
+                                    &rui_temp.wiener_nonsep_info);
     } else {
       // Copy current unit from the top of the stack.
       memset(&unit_snapshot, 0, sizeof(unit_snapshot));
@@ -2860,21 +2944,20 @@
       // RESTORE_WIENER_NONSEP units become start of new stack, and
       // RESTORE_NONE units are discarded.
       if (rtype == RESTORE_WIENER_NONSEP) {
-        rsc->wiener_nonsep = rusi->wiener_nonsep;
+        // rsc->wiener_nonsep = rusi->wiener_nonsep;
+        av1_add_to_wiener_nonsep_bank(&rsc->wiener_nonsep,
+                                      &rusi->wiener_nonsep);
         aom_vector_clear(current_unit_stack);
         aom_vector_push_back(current_unit_stack, &unit_snapshot);
       } else {
         aom_vector_pop_back(current_unit_stack);
       }
     }
-#else  // CONFIG_RST_MERGECOEFFS
+#else   // CONFIG_RST_MERGECOEFFS
     const int64_t bits_wienerns =
         x->mode_costs.wiener_nonsep_restore_cost[1] +
-        count_wienerns_bits(rui.plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-                            x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-                            &rusi->wiener_nonsep, &rsc->wiener_nonsep, wnsf);
+        count_wienerns_bits(rui.plane, &x->mode_costs, &rusi->wiener_nonsep,
+                            &rsc->wiener_nonsep, wnsf);
     double cost_wienerns = RDCOST_DBL_WITH_NATIVE_BD_DIST(
         x->rdmult, bits_wienerns >> 4, rusi->sse[RESTORE_WIENER_NONSEP],
         bit_depth);
@@ -2883,7 +2966,9 @@
     rusi->best_rtype[RESTORE_WIENER_NONSEP - 1] = rtype;
     rsc->sse += rusi->sse[rtype];
     rsc->bits += (cost_wienerns < cost_none) ? bits_wienerns : bits_none;
-    if (cost_wienerns < cost_none) rsc->wiener_nonsep = rusi->wiener_nonsep;
+    if (cost_wienerns < cost_none)
+      // rsc->wiener_nonsep = rusi->wiener_nonsep;
+      av1_add_to_wiener_nonsep_bank(&rsc->wiener_nonsep, &rusi->wiener_nonsep);
       /*
       printf("[%d] none: %"PRId64"/%"PRId64"/%f; wns: %"PRId64"/%"PRId64"/%f\n",
              x->rdmult, rusi->sse[RESTORE_NONE], bits_none, cost_none,
@@ -2934,19 +3019,18 @@
   switch (rest_type) {
     case RESTORE_NONE: coeff_bits = 0; break;
     case RESTORE_WIENER:
-      coeff_bits = count_wiener_bits(wiener_win, &rusi->wiener, &rsc->wiener);
+      coeff_bits = count_wiener_bits(wiener_win, &x->mode_costs, &rusi->wiener,
+                                     &rsc->wiener);
       break;
     case RESTORE_SGRPROJ:
-      coeff_bits = count_sgrproj_bits(&rusi->sgrproj, &rsc->sgrproj);
+      coeff_bits =
+          count_sgrproj_bits(&rusi->sgrproj, &x->mode_costs, &rsc->sgrproj);
       break;
 #if CONFIG_WIENER_NONSEP
     case RESTORE_WIENER_NONSEP:
-      coeff_bits = count_wienerns_bits(
-          rsc->plane, x->mode_costs.wiener_nonsep_reduce_cost,
-#if CONFIG_LR_4PART_CODE
-          x->mode_costs.wiener_nonsep_4part_cost,
-#endif  // CONFIG_LR_4PART_CODE
-          &rusi->wiener_nonsep, &rsc->wiener_nonsep, wnsf);
+      coeff_bits =
+          count_wienerns_bits(rsc->plane, &x->mode_costs, &rusi->wiener_nonsep,
+                              &rsc->wiener_nonsep, wnsf);
       break;
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
@@ -2964,16 +3048,21 @@
   int merged = 0;
   switch (rest_type) {
     case RESTORE_WIENER:
-      if (check_wiener_eq(&rusi->wiener, &rsc->wiener)) merged = 1;
+      if (check_wiener_eq(&rusi->wiener,
+                          av1_ref_from_wiener_bank(&rsc->wiener, 0)))
+        merged = 1;
       break;
     case RESTORE_SGRPROJ:
-      if (check_sgrproj_eq(&rusi->sgrproj, &rsc->sgrproj)) merged = 1;
+      if (check_sgrproj_eq(&rusi->sgrproj,
+                           av1_ref_from_sgrproj_bank(&rsc->sgrproj, 0)))
+        merged = 1;
       break;
 #if CONFIG_WIENER_NONSEP
     case RESTORE_WIENER_NONSEP: {
       int is_uv = (rsc->plane != AOM_PLANE_Y);
-      if (check_wienerns_eq(is_uv, &rusi->wiener_nonsep, &rsc->wiener_nonsep,
-                            wnsf))
+      if (check_wienerns_eq(
+              is_uv, &rusi->wiener_nonsep,
+              av1_ref_from_wiener_nonsep_bank(&rsc->wiener_nonsep, 0), wnsf))
         merged = 1;
     } break;
 #endif  // CONFIG_WIENER_NONSEP
@@ -3012,6 +3101,9 @@
   // Duplicate rsc to avoid overwriting
   RestSearchCtxt rsc_dup = *rsc;
 
+  const WienernsFilterConfigPairType *wnsf =
+      get_wienerns_filters(rsc->cm->quant_params.base_qindex);
+
   int is_uv = (rsc->plane != AOM_PLANE_Y);
   int nunits = rest_tiles_in_plane(rsc->cm, is_uv);
   int max_out = RESTORE_SWITCHABLE_TYPES;
@@ -3036,11 +3128,27 @@
     }
     switch (visited_rtype) {
       case RESTORE_NONE: break;
-      case RESTORE_WIENER: rsc_dup.wiener = visited_rusi->wiener; break;
-      case RESTORE_SGRPROJ: rsc_dup.sgrproj = visited_rusi->sgrproj; break;
+      case RESTORE_WIENER:
+        if (!check_wiener_eq(&visited_rusi->wiener,
+                             av1_ref_from_wiener_bank(&rsc_dup.wiener, 0)))
+          av1_add_to_wiener_bank(&rsc_dup.wiener, &visited_rusi->wiener);
+        // rsc_dup.wiener = visited_rusi->wiener;
+        break;
+      case RESTORE_SGRPROJ:
+        if (!check_sgrproj_eq(&visited_rusi->sgrproj,
+                              av1_ref_from_sgrproj_bank(&rsc_dup.sgrproj, 0)))
+          av1_add_to_sgrproj_bank(&rsc_dup.sgrproj, &visited_rusi->sgrproj);
+        // rsc_dup.sgrproj = visited_rusi->sgrproj;
+        break;
 #if CONFIG_WIENER_NONSEP
       case RESTORE_WIENER_NONSEP:
-        rsc_dup.wiener_nonsep = visited_rusi->wiener_nonsep;
+        if (!check_wienerns_eq(
+                is_uv, &visited_rusi->wiener_nonsep,
+                av1_ref_from_wiener_nonsep_bank(&rsc_dup.wiener_nonsep, 0),
+                wnsf))
+          av1_add_to_wiener_nonsep_bank(&rsc_dup.wiener_nonsep,
+                                        &visited_rusi->wiener_nonsep);
+        // rsc_dup.wiener_nonsep = visited_rusi->wiener_nonsep;
         break;
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
@@ -3256,11 +3364,16 @@
 
     rsc->sse += rusi->sse[best_rtype];
     rsc->bits += best_bits;
-    if (best_rtype == RESTORE_WIENER) rsc->wiener = rusi->wiener;
-    if (best_rtype == RESTORE_SGRPROJ) rsc->sgrproj = rusi->sgrproj;
+    if (best_rtype == RESTORE_WIENER)
+      av1_add_to_wiener_bank(&rsc->wiener, &rusi->wiener);
+    // rsc->wiener = rusi->wiener;
+    if (best_rtype == RESTORE_SGRPROJ)
+      av1_add_to_sgrproj_bank(&rsc->sgrproj, &rusi->sgrproj);
+      // rsc->sgrproj = rusi->sgrproj;
 #if CONFIG_WIENER_NONSEP
     if (best_rtype == RESTORE_WIENER_NONSEP)
-      rsc->wiener_nonsep = rusi->wiener_nonsep;
+      av1_add_to_wiener_nonsep_bank(&rsc->wiener_nonsep, &rusi->wiener_nonsep);
+      // rsc->wiener_nonsep = rusi->wiener_nonsep;
 #endif  // CONFIG_WIENER_NONSEP
 #if CONFIG_PC_WIENER
     if (best_rtype == RESTORE_PC_WIENER) {
diff --git a/av1/encoder/pickrst.h b/av1/encoder/pickrst.h
index 33b1aba..ac5b190 100644
--- a/av1/encoder/pickrst.h
+++ b/av1/encoder/pickrst.h
@@ -56,6 +56,67 @@
   return (uint16_t)avg;
 }
 
+#if CONFIG_RST_MERGECOEFFS
+static INLINE int check_wiener_eq(const WienerInfo *info,
+                                  const WienerInfo *ref) {
+  return !memcmp(info->vfilter, ref->vfilter,
+                 WIENER_HALFWIN * sizeof(info->vfilter[0])) &&
+         !memcmp(info->hfilter, ref->hfilter,
+                 WIENER_HALFWIN * sizeof(info->hfilter[0]));
+}
+static INLINE int check_sgrproj_eq(const SgrprojInfo *info,
+                                   const SgrprojInfo *ref) {
+  if (!memcmp(info, ref, sizeof(*info))) return 1;
+  return 0;
+}
+
+static INLINE int check_wiener_bank_eq(const WienerInfoBank *bank,
+                                       const WienerInfo *info) {
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (check_wiener_eq(info, av1_constref_from_wiener_bank(bank, k))) return k;
+  }
+  return -1;
+}
+
+static INLINE int check_sgrproj_bank_eq(const SgrprojInfoBank *bank,
+                                        const SgrprojInfo *info) {
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (check_sgrproj_eq(info, av1_constref_from_sgrproj_bank(bank, k)))
+      return k;
+  }
+  return -1;
+}
+
+#if CONFIG_WIENER_NONSEP
+static INLINE int check_wienerns_eq(int chroma, const WienerNonsepInfo *info,
+                                    const WienerNonsepInfo *ref,
+                                    const WienernsFilterConfigPairType *wnsf) {
+  if (!chroma) {
+    if (!memcmp(info->nsfilter, ref->nsfilter,
+                wnsf->y->ncoeffs * sizeof(*info->nsfilter)))
+      return 1;
+  } else {
+    if (!memcmp(&info->nsfilter[wnsf->y->ncoeffs],
+                &ref->nsfilter[wnsf->y->ncoeffs],
+                wnsf->uv->ncoeffs * sizeof(*info->nsfilter)))
+      return 1;
+  }
+  return 0;
+}
+
+static INLINE int check_wienerns_bank_eq(
+    int chroma, const WienerNonsepInfoBank *bank, const WienerNonsepInfo *info,
+    const WienernsFilterConfigPairType *wnsf) {
+  for (int k = 0; k < AOMMAX(1, bank->bank_size); ++k) {
+    if (check_wienerns_eq(chroma, info,
+                          av1_constref_from_wiener_nonsep_bank(bank, k), wnsf))
+      return k;
+  }
+  return -1;
+}
+#endif  // CONFIG_WIENER_NONSEP
+#endif  // CONFIG_RST_MERGECOEFFS
+
 /*!\brief Algorithm for AV1 loop restoration search and estimation.
  *
  * \ingroup in_loop_restoration