shithub: dav1d

Download patch

ref: 3d7920e6ff7c8e8f032a8e685595bcd38e4a3028
parent: 1c9c2534569fc9c4c9d68cbf23e86273619ecc59
author: Luc Trudeau <ltrudeau@twoorioles.com>
date: Fri Sep 28 15:56:17 EDT 2018

Remove VLAs from Loop Restoration

--- a/src/looprestoration.c
+++ b/src/looprestoration.c
@@ -34,11 +34,12 @@
 #include "src/looprestoration.h"
 #include "src/tables.h"
 
+// 256 * 1.5 + 3 + 3 = 390
+#define REST_UNIT_STRIDE (390)
 
 // TODO Reuse p when no padding is needed (add and remove lpf pixels in p)
 // TODO Chroma only requires 2 rows of padding.
-static void padding(pixel *dst, const ptrdiff_t dst_stride,
-                    const pixel *p, const ptrdiff_t p_stride,
+static void padding(pixel *dst, const pixel *p, const ptrdiff_t p_stride,
                     const pixel *lpf, const ptrdiff_t lpf_stride,
                     int unit_w, const int stripe_h, const enum LrEdgeFlags edges)
 {
@@ -56,35 +57,35 @@
         const pixel *const above_1 = lpf;
         const pixel *const above_2 = above_1 + PXSTRIDE(lpf_stride);
         pixel_copy(dst_l, above_1, unit_w);
-        pixel_copy(dst_l + PXSTRIDE(dst_stride), above_1, unit_w);
-        pixel_copy(dst_l + 2 * PXSTRIDE(dst_stride), above_2, unit_w);
+        pixel_copy(dst_l + REST_UNIT_STRIDE, above_1, unit_w);
+        pixel_copy(dst_l + 2 * REST_UNIT_STRIDE, above_2, unit_w);
     } else {
         // Pad with first row
         pixel_copy(dst_l, p, unit_w);
-        pixel_copy(dst_l + PXSTRIDE(dst_stride), p, unit_w);
-        pixel_copy(dst_l + 2 * PXSTRIDE(dst_stride), p, unit_w);
+        pixel_copy(dst_l + REST_UNIT_STRIDE, p, unit_w);
+        pixel_copy(dst_l + 2 * REST_UNIT_STRIDE, p, unit_w);
     }
 
-    pixel *dst_tl = dst_l + 3 * PXSTRIDE(dst_stride);
+    pixel *dst_tl = dst_l + 3 * REST_UNIT_STRIDE;
     if (edges & LR_HAVE_BOTTOM) {
         // Copy next loop filtered rows
         const pixel *const below_1 = lpf + 6 * PXSTRIDE(lpf_stride);
         const pixel *const below_2 = below_1 + PXSTRIDE(lpf_stride);
-        pixel_copy(dst_tl + stripe_h * PXSTRIDE(dst_stride), below_1, unit_w);
-        pixel_copy(dst_tl + (stripe_h + 1) * PXSTRIDE(dst_stride), below_2, unit_w);
-        pixel_copy(dst_tl + (stripe_h + 2) * PXSTRIDE(dst_stride), below_2, unit_w);
+        pixel_copy(dst_tl + stripe_h * REST_UNIT_STRIDE, below_1, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 1) * REST_UNIT_STRIDE, below_2, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 2) * REST_UNIT_STRIDE, below_2, unit_w);
     } else {
         // Pad with last row
         const pixel *const src = p + (stripe_h - 1) * PXSTRIDE(p_stride);
-        pixel_copy(dst_tl + stripe_h * PXSTRIDE(dst_stride), src, unit_w);
-        pixel_copy(dst_tl + (stripe_h + 1) * PXSTRIDE(dst_stride), src, unit_w);
-        pixel_copy(dst_tl + (stripe_h + 2) * PXSTRIDE(dst_stride), src, unit_w);
+        pixel_copy(dst_tl + stripe_h * REST_UNIT_STRIDE, src, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 1) * REST_UNIT_STRIDE, src, unit_w);
+        pixel_copy(dst_tl + (stripe_h + 2) * REST_UNIT_STRIDE, src, unit_w);
     }
 
     // Inner UNIT_WxSTRIPE_H
     for (int j = 0; j < stripe_h; j++) {
         pixel_copy(dst_tl, p, unit_w);
-        dst_tl += PXSTRIDE(dst_stride);
+        dst_tl += REST_UNIT_STRIDE;
         p += PXSTRIDE(p_stride);
     }
 
@@ -94,8 +95,8 @@
         // Pad 3x(STRIPE_H+6) with last column
         for (int j = 0; j < stripe_h + 6; j++) {
             pixel_set(pad, *row_last, 3);
-            pad += PXSTRIDE(dst_stride);
-            row_last += PXSTRIDE(dst_stride);
+            pad += REST_UNIT_STRIDE;
+            row_last += REST_UNIT_STRIDE;
         }
     }
 
@@ -103,8 +104,8 @@
         // Pad 3x(STRIPE_H+6) with first column
         for (int j = 0; j < stripe_h + 6; j++) {
             pixel_set(dst, *dst_l, 3);
-            dst += PXSTRIDE(dst_stride);
-            dst_l += PXSTRIDE(dst_stride);
+            dst += REST_UNIT_STRIDE;
+            dst_l += REST_UNIT_STRIDE;
         }
     }
 }
@@ -119,16 +120,16 @@
                      const int16_t filterh[7], const int16_t filterv[7],
                      const enum LrEdgeFlags edges)
 {
-    // padding is 3 pixels above and 3 pixels below
-    const ptrdiff_t tmp_stride = sizeof(pixel) * (w + 6);
-    pixel tmp[(h + 6) * PXSTRIDE(tmp_stride)];
+    // Wiener filtering is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    pixel tmp[70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE];
     pixel *tmp_ptr = tmp;
 
-    padding(tmp, tmp_stride, p, p_stride, lpf, lpf_stride, w, h, edges);
+    padding(tmp, p, p_stride, lpf, lpf_stride, w, h, edges);
 
     // Values stored between horizontal and vertical filtering don't
     // fit in a uint8_t.
-    uint16_t hor[(h + 6 /*padding*/) * w];
+    uint16_t hor[70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE];
     uint16_t *hor_ptr = hor;
 
     const int round_bits_h = 3 + (BITDEPTH == 12) * 2;
@@ -145,8 +146,8 @@
             hor_ptr[i] =
                 iclip((sum + rounding_off_h) >> round_bits_h, 0, clip_limit);
         }
-        tmp_ptr += PXSTRIDE(tmp_stride);
-        hor_ptr += w;
+        tmp_ptr += REST_UNIT_STRIDE;
+        hor_ptr += REST_UNIT_STRIDE;
     }
 
     const int round_bits_v = 11 - (BITDEPTH == 12) * 2;
@@ -154,10 +155,10 @@
     const int round_offset = 1 << (BITDEPTH + (round_bits_v - 1));
     for (int i = 0; i < w; i++) {
         for (int j = 0; j < h; j++) {
-            int sum = (hor[w * (j + 3) + i] << 7) - round_offset;
+            int sum = (hor[(j + 3) * REST_UNIT_STRIDE + i] << 7) - round_offset;
 
             for (int k = 0; k < 7; k++) {
-                sum += hor[(j + k) * w + i] * filterv[k];
+                sum += hor[(j + k) * REST_UNIT_STRIDE + i] * filterv[k];
             }
 
             p[j * PXSTRIDE(p_stride) + i] =
@@ -188,27 +189,23 @@
 // i: Pixel summed and stored (between loops)
 // c: Pixel summed not stored
 // x: Pixel not summed not stored
-static void boxsum3(coef *dst, const ptrdiff_t dst_stride,
-                    const pixel *src, ptrdiff_t src_stride,
-                    const int w, const int h)
-{
-    src_stride = PXSTRIDE(src_stride);
+static void boxsum3(coef *dst, const pixel *src, const int w, const int h) {
     // We skip the first row, as it is never used
-    src += src_stride;
-    dst += dst_stride;
+    src += REST_UNIT_STRIDE;
+    dst += REST_UNIT_STRIDE;
 
     // We skip the first and last columns, as they are never used
     for (int x = 1; x < w - 1; x++) {
         coef *ds = dst + x;
         const pixel *s = src + x;
-        int a = s[0], b = s[src_stride];
+        int a = s[0], b = s[REST_UNIT_STRIDE];
 
         // We skip the first 2 rows, as they are skipped in the next loop and
         // we don't need the last 2 row as it is skipped in the next loop
         for (int y = 2; y < h - 2; y++) {
-            s += src_stride;
-            const int c = s[src_stride];
-            ds += dst_stride;
+            s += REST_UNIT_STRIDE;
+            const int c = s[REST_UNIT_STRIDE];
+            ds += REST_UNIT_STRIDE;
             *ds = a + b + c;
             a = b;
             b = c;
@@ -216,7 +213,7 @@
      }
 
     // We skip the first 2 rows as they are never read
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
     // We skip the last 2 rows as it is never read
     for (int y = 2; y < h - 2; y++) {
         int a = dst[1], b = dst[2];
@@ -229,7 +226,7 @@
             a = b;
             b = c;
         }
-        dst += dst_stride;
+        dst += REST_UNIT_STRIDE;
     }
 }
 
@@ -255,29 +252,24 @@
 // i: Pixel summed and stored (between loops)
 // c: Pixel summed not stored
 // x: Pixel not summed not stored
-static void boxsum5(coef *dst, const ptrdiff_t dst_stride,
-                    const pixel *const src, ptrdiff_t src_stride,
-                    const int w, const int h)
-{
-    src_stride = PXSTRIDE(src_stride);
-
+static void boxsum5(coef *dst, const pixel *const src, const int w, const int h) {
     // We skip the first row, as it is never used
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
 
     for (int x = 0; x < w; x++) {
         coef *ds = dst + x;
-        const pixel *s = src + 3 * src_stride + x;
-        int a = s[-3 * src_stride];
-        int b = s[-2 * src_stride];
-        int c = s[-1 * src_stride];
+        const pixel *s = src + 3 * REST_UNIT_STRIDE + x;
+        int a = s[-3 * REST_UNIT_STRIDE];
+        int b = s[-2 * REST_UNIT_STRIDE];
+        int c = s[-1 * REST_UNIT_STRIDE];
         int d = s[0];
 
         // We skip the first 2 rows, as they are skipped in the next loop and
         // we don't need the last 2 row as it is skipped in the next loop
         for (int y = 2; y < h - 2; y++) {
-            s += src_stride;
+            s += REST_UNIT_STRIDE;
             const int e = *s;
-            ds += dst_stride;
+            ds += REST_UNIT_STRIDE;
             *ds = a + b + c + d + e;
             a = b;
             b = c;
@@ -287,7 +279,7 @@
     }
 
     // We skip the first 2 rows as they are never read
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
     for (int y = 2; y < h - 2; y++) {
         int a = dst[0];
         int b = dst[1];
@@ -302,20 +294,15 @@
             c = d;
             d = e;
         }
-        dst += dst_stride;
+        dst += REST_UNIT_STRIDE;
     }
 }
 
 // See boxsum3 function comments for details on row and column skipping
-static void boxsum3sqr(int32_t *dst, const ptrdiff_t dst_stride,
-                       const pixel *src, ptrdiff_t src_stride,
-                       const int w, const int h)
-{
-    src_stride = PXSTRIDE(src_stride);
-
+static void boxsum3sqr(int32_t *dst, const pixel *src, const int w, const int h) {
     // We skip the first row, as it is never used
-    src += src_stride;
-    dst += dst_stride;
+    src += REST_UNIT_STRIDE;
+    dst += REST_UNIT_STRIDE;
 
     // We skip the first and last columns, as they are never used
     for (int x = 1; x < w - 1; x++) {
@@ -322,14 +309,14 @@
         int *ds = dst + x;
         const pixel *s = src + x;
         int a = s[0] * s[0];
-        int b = s[src_stride] * s[src_stride];
+        int b = s[REST_UNIT_STRIDE] * s[REST_UNIT_STRIDE];
 
         // We skip the first row, as it is skipped in the next loop and
         // we don't need the last row as it is skipped in the next loop
         for (int y = 2; y < h - 2; y++) {
-            s += src_stride;
-            const int c = s[src_stride] * s[src_stride];
-            ds += dst_stride;
+            s += REST_UNIT_STRIDE;
+            const int c = s[REST_UNIT_STRIDE] * s[REST_UNIT_STRIDE];
+            ds += REST_UNIT_STRIDE;
             *ds = a + b + c;
             a = b;
             b = c;
@@ -337,7 +324,7 @@
      }
 
     // We skip the first row as it is never read
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
     // We skip the last row as it is never read
     for (int y = 2; y < h - 2; y++) {
         int a = dst[1], b = dst[2];
@@ -350,34 +337,31 @@
             a = b;
             b = c;
         }
-        dst += dst_stride;
+        dst += REST_UNIT_STRIDE;
     }
 }
 
 // See boxsum5 function comments for details on row and column skipping
-static void boxsum5sqr(int32_t *dst, const ptrdiff_t dst_stride,
-                       const pixel *const src, ptrdiff_t src_stride,
-                       const int w, const int h)
+static void boxsum5sqr(int32_t *dst, const pixel *const src, const int w,
+                       const int h)
 {
-    src_stride = PXSTRIDE(src_stride);
-
     // We skip the first row, as it is never used
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
 
     for (int x = 0; x < w; x++) {
         int *ds = dst + x;
-        const pixel *s = src + 3 * src_stride + x;
-        int a = s[-3 * src_stride] * s[-3 * src_stride];
-        int b = s[-2 * src_stride] * s[-2 * src_stride];
-        int c = s[-1 * src_stride] * s[-1 * src_stride];
+        const pixel *s = src + 3 * REST_UNIT_STRIDE + x;
+        int a = s[-3 * REST_UNIT_STRIDE] * s[-3 * REST_UNIT_STRIDE];
+        int b = s[-2 * REST_UNIT_STRIDE] * s[-2 * REST_UNIT_STRIDE];
+        int c = s[-1 * REST_UNIT_STRIDE] * s[-1 * REST_UNIT_STRIDE];
         int d = s[0] * s[0];
 
         // We skip the first 2 rows, as they are skipped in the next loop and
         // we don't need the last 2 row as it is skipped in the next loop
         for (int y = 2; y < h - 2; y++) {
-            s += src_stride;
+            s += REST_UNIT_STRIDE;
             const int e = s[0] * s[0];
-            ds += dst_stride;
+            ds += REST_UNIT_STRIDE;
             *ds = a + b + c + d + e;
             a = b;
             b = c;
@@ -387,7 +371,7 @@
     }
 
     // We skip the first 2 rows as they are never read
-    dst += dst_stride;
+    dst += REST_UNIT_STRIDE;
     for (int y = 2; y < h - 2; y++) {
         int a = dst[0];
         int b = dst[1];
@@ -402,34 +386,34 @@
             c = d;
             d = e;
         }
-        dst += dst_stride;
+        dst += REST_UNIT_STRIDE;
     }
 }
 
-static void selfguided_filter(int32_t *dst, const ptrdiff_t dst_stride,
-                              const pixel *src, const ptrdiff_t src_stride,
-                              const int w, const int h, const int n, const int s)
+static void selfguided_filter(int32_t *dst, const pixel *src,
+                              const ptrdiff_t src_stride, const int w,
+                              const int h, const int n, const int s)
 {
-    const int tmp_stride = w + 6;
-    // FIXME Replace array with scratch memory
-    int32_t A_[(h + 6) * tmp_stride];
-    int32_t *A = A_ + 3 * tmp_stride + 3;
+    // Selfguided filter is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    int32_t A_[70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE];
+    int32_t *A = A_ + 3 * REST_UNIT_STRIDE + 3;
     // By inverting A and B after the boxsums, B can be of size coef instead
     // of int32_t
-    coef B_[(h + 6) * tmp_stride];
-    coef *B = B_ + 3 * tmp_stride + 3;
+    coef B_[70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE];
+    coef *B = B_ + 3 * REST_UNIT_STRIDE + 3;
 
     const int step = (n == 25) + 1;
     if (n == 25) {
-        boxsum5(B_, tmp_stride, src, src_stride, w + 6, h + 6);
-        boxsum5sqr(A_, tmp_stride, src, src_stride, w + 6, h + 6);
+        boxsum5(B_, src, w + 6, h + 6);
+        boxsum5sqr(A_, src, w + 6, h + 6);
     } else {
-        boxsum3(B_, tmp_stride, src, src_stride, w + 6, h + 6);
-        boxsum3sqr(A_, tmp_stride, src, src_stride, w + 6, h + 6);
+        boxsum3(B_, src, w + 6, h + 6);
+        boxsum3sqr(A_, src, w + 6, h + 6);
     }
 
-    int32_t *AA = A - tmp_stride;
-    coef *BB = B - tmp_stride;
+    int32_t *AA = A - REST_UNIT_STRIDE;
+    coef *BB = B - REST_UNIT_STRIDE;
     for (int j = -1; j < h + 1; j+= step) {
         for (int i = -1; i < w + 1; i++) {
             const int a =
@@ -445,60 +429,60 @@
             AA[i] = (((1 << 8) - x) * BB[i] * sgr_one_by_x[n - 1] + (1 << 11)) >> 12;
             BB[i] = x;
         }
-        AA += step * tmp_stride;
-        BB += step * tmp_stride;
+        AA += step * REST_UNIT_STRIDE;
+        BB += step * REST_UNIT_STRIDE;
     }
 
-    src += 3 * PXSTRIDE(src_stride) + 3;
+    src += 3 * REST_UNIT_STRIDE + 3;
     if (n == 25) {
         int j = 0;
-#define SIX_NEIGHBORS(P, i, stride)\
-    ((P[i - stride]     + P[i + stride]) * 6 +   \
-     (P[i - 1 - stride] + P[i - 1 + stride] +    \
-      P[i + 1 - stride] + P[i + 1 + stride]) * 5)
+#define SIX_NEIGHBORS(P, i)\
+    ((P[i - REST_UNIT_STRIDE]     + P[i + REST_UNIT_STRIDE]) * 6 +   \
+     (P[i - 1 - REST_UNIT_STRIDE] + P[i - 1 + REST_UNIT_STRIDE] +    \
+      P[i + 1 - REST_UNIT_STRIDE] + P[i + 1 + REST_UNIT_STRIDE]) * 5)
         for (; j < h - 1; j+=2) {
             for (int i = 0; i < w; i++) {
-                const int32_t a = SIX_NEIGHBORS(B, i, tmp_stride);
-                const int32_t b = SIX_NEIGHBORS(A, i, tmp_stride);
+                const int32_t a = SIX_NEIGHBORS(B, i);
+                const int32_t b = SIX_NEIGHBORS(A, i);
                 dst[i] = (a * src[i] + b + (1 << 8)) >> 9;
             }
-            dst += dst_stride;
-            src += PXSTRIDE(src_stride);
-            B += tmp_stride;
-            A += tmp_stride;
+            dst += 384 /* Maximum restoration width is 384 (256 * 1.5) */;
+            src += REST_UNIT_STRIDE;
+            B += REST_UNIT_STRIDE;
+            A += REST_UNIT_STRIDE;
             for (int i = 0; i < w; i++) {
                 const int32_t a = B[i] * 6 + (B[i - 1] + B[i + 1]) * 5;
                 const int32_t b = A[i] * 6 + (A[i - 1] + A[i + 1]) * 5;
                 dst[i] = (a * src[i] + b + (1 << 7)) >> 8;
             }
-            dst += dst_stride;
-            src += PXSTRIDE(src_stride);
-            B += tmp_stride;
-            A += tmp_stride;
+            dst += 384 /* Maximum restoration width is 384 (256 * 1.5) */;
+            src += REST_UNIT_STRIDE;
+            B += REST_UNIT_STRIDE;
+            A += REST_UNIT_STRIDE;
         }
         if (j + 1 == h) { // Last row, when number of rows is odd
             for (int i = 0; i < w; i++) {
-                const int32_t a = SIX_NEIGHBORS(B, i, tmp_stride);
-                const int32_t b = SIX_NEIGHBORS(A, i, tmp_stride);
+                const int32_t a = SIX_NEIGHBORS(B, i);
+                const int32_t b = SIX_NEIGHBORS(A, i);
                 dst[i] = (a * src[i] + b + (1 << 8)) >> 9;
             }
         }
 #undef SIX_NEIGHBORS
     } else {
-#define EIGHT_NEIGHBORS(P, i, stride)\
-    ((P[i] + P[i - 1] + P[i + 1] + P[i - tmp_stride] + P[i + tmp_stride]) * 4 + \
-     (P[i - 1 - tmp_stride] + P[i - 1 + tmp_stride] +                           \
-      P[i + 1 - tmp_stride] + P[i + 1 + tmp_stride]) * 3)
+#define EIGHT_NEIGHBORS(P, i)\
+    ((P[i] + P[i - 1] + P[i + 1] + P[i - REST_UNIT_STRIDE] + P[i + REST_UNIT_STRIDE]) * 4 + \
+     (P[i - 1 - REST_UNIT_STRIDE] + P[i - 1 + REST_UNIT_STRIDE] +                           \
+      P[i + 1 - REST_UNIT_STRIDE] + P[i + 1 + REST_UNIT_STRIDE]) * 3)
         for (int j = 0; j < h; j++) {
             for (int i = 0; i < w; i++) {
-                const int32_t a = EIGHT_NEIGHBORS(B, i, stride);
-                const int32_t b = EIGHT_NEIGHBORS(A, i, stride);
+                const int32_t a = EIGHT_NEIGHBORS(B, i);
+                const int32_t b = EIGHT_NEIGHBORS(A, i);
                 dst[i] = (a * src[i] + b + (1 << 8)) >> 9;
             }
-            dst += dst_stride;
-            src += PXSTRIDE(src_stride);
-            B += tmp_stride;
-            A += tmp_stride;
+            dst += 384;
+            src += REST_UNIT_STRIDE;
+            B += REST_UNIT_STRIDE;
+            A += REST_UNIT_STRIDE;
         }
     }
 #undef NINE_NEIGHBORS
@@ -509,53 +493,54 @@
                          const int w, const int h, const int sgr_idx,
                          const int16_t sgr_w[2], const enum LrEdgeFlags edges)
 {
-    // padding is 3 pixels above and 3 pixels below
-    const int tmp_stride = sizeof(pixel) * (w + 6);
-    pixel tmp[(h + 6) * PXSTRIDE(tmp_stride)];
+    // Selfguided filter is applied to a maximum stripe height of 64 + 3 pixels
+    // of padding above and below
+    pixel tmp[70 /*(64 + 3 + 3)*/ * REST_UNIT_STRIDE];
 
-    padding(tmp, tmp_stride, p, p_stride, lpf, lpf_stride, w, h, edges);
+    padding(tmp, p, p_stride, lpf, lpf_stride, w, h, edges);
 
+    // Selfguided filter outputs to a maximum stripe height of 64 and a
+    // maximum restoration width of 384 (256 * 1.5)
+    int32_t dst[64 * 384];
+
     // both r1 and r0 can't be zero
     if (!sgr_params[sgr_idx][0]) {
-        int32_t dst[h * w];
         const int s1 = sgr_params[sgr_idx][3];
-        selfguided_filter(dst, w, tmp, tmp_stride, w, h, 9, s1);
+        selfguided_filter(dst, tmp, REST_UNIT_STRIDE, w, h, 9, s1);
         const int w1 = (1 << 7) - sgr_w[1];
         for (int j = 0; j < h; j++) {
             for (int i = 0; i < w; i++) {
                 const int32_t u = (p[i] << 4);
-                const int32_t v = (u << 7) + w1 * (dst[j * w + i] - u);
+                const int32_t v = (u << 7) + w1 * (dst[j * 384 + i] - u);
                 p[i] = iclip_pixel((v + (1 << 10)) >> 11);
             }
             p += PXSTRIDE(p_stride);
         }
     } else if (!sgr_params[sgr_idx][1]) {
-        int32_t dst[h * w];
         const int s0 = sgr_params[sgr_idx][2];
-        selfguided_filter(dst, w, tmp, tmp_stride, w, h, 25, s0);
+        selfguided_filter(dst, tmp, REST_UNIT_STRIDE, w, h, 25, s0);
         const int w0 = sgr_w[0];
         for (int j = 0; j < h; j++) {
             for (int i = 0; i < w; i++) {
                 const int32_t u = (p[i] << 4);
-                const int32_t v = (u << 7) + w0 * (dst[j * w + i] - u);
+                const int32_t v = (u << 7) + w0 * (dst[j * 384 + i] - u);
                 p[i] = iclip_pixel((v + (1 << 10)) >> 11);
             }
             p += PXSTRIDE(p_stride);
         }
     } else {
-        int32_t dst0[h * w];
-        int32_t dst1[h * w];
+        int32_t dst1[64 * 384];
         const int s0 = sgr_params[sgr_idx][2];
         const int s1 = sgr_params[sgr_idx][3];
         const int w0 = sgr_w[0];
         const int w1 = (1 << 7) - w0 - sgr_w[1];
-        selfguided_filter(dst0, w, tmp, tmp_stride, w, h, 25, s0);
-        selfguided_filter(dst1, w, tmp, tmp_stride, w, h, 9, s1);
+        selfguided_filter(dst, tmp, REST_UNIT_STRIDE, w, h, 25, s0);
+        selfguided_filter(dst1, tmp, REST_UNIT_STRIDE, w, h, 9, s1);
         for (int j = 0; j < h; j++) {
             for (int i = 0; i < w; i++) {
                 const int32_t u = (p[i] << 4);
-                const int32_t v = (u << 7) + w0 * (dst0[j * w + i] - u) +
-                                  w1 * (dst1[j * w + i] - u);
+                const int32_t v = (u << 7) + w0 * (dst[j * 384 + i] - u) +
+                                  w1 * (dst1[j * 384 + i] - u);
                 p[i] = iclip_pixel((v + (1 << 10)) >> 11);
             }
             p += PXSTRIDE(p_stride);
--- a/src/lr_apply.c
+++ b/src/lr_apply.c
@@ -227,8 +227,8 @@
     const int filter_h =
         imin(((1 << (6 + f->seq_hdr.sb128)) - 8 * !y) >> ss_ver, h - y);
 
-    pixel pre_lr_border[filter_h * 3];
-    pixel post_lr_border[filter_h * 3];
+    pixel pre_lr_border[128 /* maximum sbrow height is 128 */ * 3];
+    pixel post_lr_border[128 /* maximum sbrow height is 128 */ * 3];
 
     int unit_w = unit_size;