Various loop-restoration optimizations * Optimize the self-guided and domaintxfmrf filters * Save 576KiB of buffers in the encoder and decoder * Disable self-guided filter for videos whose width or height is < 5, in order to help simplify the filter. This results in an overall 30-40% improvement in decoder speed with loop-restoration enabled (depending on source and bitate), with no effect on video quality, *except* for videos with width or height < 5 pixels. Change-Id: Ide9181118ec3a63a0335338f316505b08df2d831
diff --git a/av1/common/restoration.c b/av1/common/restoration.c index d725302..f8884c8 100644 --- a/av1/common/restoration.c +++ b/av1/common/restoration.c
@@ -193,77 +193,197 @@ } } -static void boxsum(int32_t *src, int width, int height, int src_stride, int r, - int sqr, int32_t *dst, int dst_stride, int32_t *tmp, - int tmp_stride) { - int i, j; +/* Calculate windowed sums (if sqr=0) or sums of squares (if sqr=1) + over the input. The window is of size (2r + 1)x(2r + 1), and we + only ever have r = 1 or r = 2. So we specialise to these two sizes. - if (sqr) { - for (j = 0; j < width; ++j) tmp[j] = src[j] * src[j]; - for (j = 0; j < width; ++j) - for (i = 1; i < height; ++i) - tmp[i * tmp_stride + j] = - tmp[(i - 1) * tmp_stride + j] + - src[i * src_stride + j] * src[i * src_stride + j]; + Each loop follows the same format: We keep a window's worth of input + in individual variables and select data out of that as appropriate. +*/ +static void boxsum1(int32_t *src, int width, int height, int src_stride, + int sqr, int32_t *dst, int dst_stride) { + int i, j, a, b, c; + + // Vertical sum over 3-pixel regions, from src into dst. + if (!sqr) { + for (j = 0; j < width; ++j) { + a = src[j]; + b = src[src_stride + j]; + c = src[2 * src_stride + j]; + + dst[j] = a + b; + for (i = 1; i < height - 2; ++i) { + // Loop invariant: At the start of each iteration, + // a = src[(i - 1) * src_stride + j] + // b = src[(i ) * src_stride + j] + // c = src[(i + 1) * src_stride + j] + dst[i * dst_stride + j] = a + b + c; + a = b; + b = c; + c = src[(i + 2) * src_stride + j]; + } + dst[i * dst_stride + j] = a + b + c; + dst[(i + 1) * dst_stride + j] = b + c; + } } else { - memcpy(tmp, src, sizeof(*tmp) * width); - for (j = 0; j < width; ++j) - for (i = 1; i < height; ++i) - tmp[i * tmp_stride + j] = - tmp[(i - 1) * tmp_stride + j] + src[i * src_stride + j]; + for (j = 0; j < width; ++j) { + a = src[j] * src[j]; + b = src[src_stride + j] * src[src_stride + j]; + c = src[2 * src_stride + j] * src[2 * src_stride + j]; + + dst[j] = a + b; + for (i = 1; i < height - 2; ++i) { + dst[i * dst_stride + j] = a + b + c; + a = b; + b = c; + c = src[(i + 2) * src_stride + j] * src[(i + 2) * src_stride + j]; + } + dst[i * dst_stride + j] = a + b + c; + dst[(i + 1) * dst_stride + j] = b + c; + } } - for (i = 0; i <= r; ++i) - memcpy(&dst[i * dst_stride], &tmp[(i + r) * tmp_stride], - sizeof(*tmp) * width); - for (i = r + 1; i < height - r; ++i) - for (j = 0; j < width; ++j) - dst[i * dst_stride + j] = - tmp[(i + r) * tmp_stride + j] - tmp[(i - r - 1) * tmp_stride + j]; - for (i = height - r; i < height; ++i) - for (j = 0; j < width; ++j) - dst[i * dst_stride + j] = tmp[(height - 1) * tmp_stride + j] - - tmp[(i - r - 1) * tmp_stride + j]; - for (i = 0; i < height; ++i) tmp[i * tmp_stride] = dst[i * dst_stride]; - for (i = 0; i < height; ++i) - for (j = 1; j < width; ++j) - tmp[i * tmp_stride + j] = - tmp[i * tmp_stride + j - 1] + dst[i * src_stride + j]; + // Horizontal sum over 3-pixel regions of dst + for (i = 0; i < height; ++i) { + a = dst[i * dst_stride]; + b = dst[i * dst_stride + 1]; + c = dst[i * dst_stride + 2]; - for (j = 0; j <= r; ++j) - for (i = 0; i < height; ++i) - dst[i * dst_stride + j] = tmp[i * tmp_stride + j + r]; - for (j = r + 1; j < width - r; ++j) - for (i = 0; i < height; ++i) - dst[i * dst_stride + j] = - tmp[i * tmp_stride + j + r] - tmp[i * tmp_stride + j - r - 1]; - for (j = width - r; j < width; ++j) - for (i = 0; i < height; ++i) - dst[i * dst_stride + j] = - tmp[i * tmp_stride + width - 1] - tmp[i * tmp_stride + j - r - 1]; + dst[i * dst_stride] = a + b; + for (j = 1; j < width - 2; ++j) { + // Loop invariant: At the start of each iteration, + // a = src[i * src_stride + (j - 1)] + // b = src[i * src_stride + (j )] + // c = src[i * src_stride + (j + 1)] + dst[i * dst_stride + j] = a + b + c; + a = b; + b = c; + c = dst[i * dst_stride + (j + 2)]; + } + dst[i * dst_stride + j] = a + b + c; + dst[i * dst_stride + (j + 1)] = b + c; + } +} + +static void boxsum2(int32_t *src, int width, int height, int src_stride, + int sqr, int32_t *dst, int dst_stride) { + int i, j, a, b, c, d, e; + + // Vertical sum over 5-pixel regions, from src into dst. + if (!sqr) { + for (j = 0; j < width; ++j) { + a = src[j]; + b = src[src_stride + j]; + c = src[2 * src_stride + j]; + d = src[3 * src_stride + j]; + e = src[4 * src_stride + j]; + + dst[j] = a + b + c; + dst[dst_stride + j] = a + b + c + d; + for (i = 2; i < height - 3; ++i) { + // Loop invariant: At the start of each iteration, + // a = src[(i - 2) * src_stride + j] + // b = src[(i - 1) * src_stride + j] + // c = src[(i ) * src_stride + j] + // d = src[(i + 1) * src_stride + j] + // e = src[(i + 2) * src_stride + j] + dst[i * dst_stride + j] = a + b + c + d + e; + a = b; + b = c; + c = d; + d = e; + e = src[(i + 3) * src_stride + j]; + } + dst[i * dst_stride + j] = a + b + c + d + e; + dst[(i + 1) * dst_stride + j] = b + c + d + e; + dst[(i + 2) * dst_stride + j] = c + d + e; + } + } else { + for (j = 0; j < width; ++j) { + a = src[j] * src[j]; + b = src[src_stride + j] * src[src_stride + j]; + c = src[2 * src_stride + j] * src[2 * src_stride + j]; + d = src[3 * src_stride + j] * src[3 * src_stride + j]; + e = src[4 * src_stride + j] * src[4 * src_stride + j]; + + dst[j] = a + b + c; + dst[dst_stride + j] = a + b + c + d; + for (i = 2; i < height - 3; ++i) { + dst[i * dst_stride + j] = a + b + c + d + e; + a = b; + b = c; + c = d; + d = e; + e = src[(i + 3) * src_stride + j] * src[(i + 3) * src_stride + j]; + } + dst[i * dst_stride + j] = a + b + c + d + e; + dst[(i + 1) * dst_stride + j] = b + c + d + e; + dst[(i + 2) * dst_stride + j] = c + d + e; + } + } + + // Horizontal sum over 5-pixel regions of dst + for (i = 0; i < height; ++i) { + a = dst[i * dst_stride]; + b = dst[i * dst_stride + 1]; + c = dst[i * dst_stride + 2]; + d = dst[i * dst_stride + 3]; + e = dst[i * dst_stride + 4]; + + dst[i * dst_stride] = a + b + c; + dst[i * dst_stride + 1] = a + b + c + d; + for (j = 2; j < width - 3; ++j) { + // Loop invariant: At the start of each iteration, + // a = src[i * src_stride + (j - 2)] + // b = src[i * src_stride + (j - 1)] + // c = src[i * src_stride + (j )] + // d = src[i * src_stride + (j + 1)] + // e = src[i * src_stride + (j + 2)] + dst[i * dst_stride + j] = a + b + c + d + e; + a = b; + b = c; + c = d; + d = e; + e = dst[i * dst_stride + (j + 3)]; + } + dst[i * dst_stride + j] = a + b + c + d + e; + dst[i * dst_stride + (j + 1)] = b + c + d + e; + dst[i * dst_stride + (j + 2)] = c + d + e; + } +} + +static void boxsum(int32_t *src, int width, int height, int src_stride, int r, + int sqr, int32_t *dst, int dst_stride) { + if (r == 1) + boxsum1(src, width, height, src_stride, sqr, dst, dst_stride); + else if (r == 2) + boxsum2(src, width, height, src_stride, sqr, dst, dst_stride); + else { + assert(0 && "boxsum no longer supports r > 2"); + return; + } } static void boxnum(int width, int height, int r, int8_t *num, int num_stride) { int i, j; - for (i = 0; i <= AOMMIN(r, height - 1); ++i) { - for (j = 0; j <= AOMMIN(r, width - 1); ++j) { - num[i * num_stride + j] = - AOMMIN(r + 1 + i, height) * AOMMIN(r + 1 + j, width); + for (i = 0; i <= r; ++i) { + for (j = 0; j <= r; ++j) { + num[i * num_stride + j] = (r + 1 + i) * (r + 1 + j); num[i * num_stride + (width - 1 - j)] = num[i * num_stride + j]; num[(height - 1 - i) * num_stride + j] = num[i * num_stride + j]; num[(height - 1 - i) * num_stride + (width - 1 - j)] = num[i * num_stride + j]; } } - for (j = 0; j <= AOMMIN(r, width - 1); ++j) { - const int val = AOMMIN(2 * r + 1, height) * AOMMIN(r + 1 + j, width); + for (j = 0; j <= r; ++j) { + const int val = (2 * r + 1) * (r + 1 + j); for (i = r + 1; i < height - r; ++i) { num[i * num_stride + j] = val; num[i * num_stride + (width - 1 - j)] = val; } } - for (i = 0; i <= AOMMIN(r, height - 1); ++i) { - const int val = AOMMIN(2 * r + 1, width) * AOMMIN(r + 1 + i, height); + for (i = 0; i <= r; ++i) { + const int val = (2 * r + 1) * (r + 1 + i); for (j = r + 1; j < width - r; ++j) { num[i * num_stride + j] = val; num[(height - 1 - i) * num_stride + j] = val; @@ -271,8 +391,7 @@ } for (i = r + 1; i < height - r; ++i) { for (j = r + 1; j < width - r; ++j) { - num[i * num_stride + j] = - AOMMIN(2 * r + 1, height) * AOMMIN(2 * r + 1, width); + num[i * num_stride + j] = (2 * r + 1) * (2 * r + 1); } } } @@ -288,21 +407,40 @@ int32_t *tmpbuf) { int32_t *A = tmpbuf; int32_t *B = A + RESTORATION_TILEPELS_MAX; - int32_t *T = B + RESTORATION_TILEPELS_MAX; int8_t num[RESTORATION_TILEPELS_MAX]; int i, j; eps <<= 2 * (bit_depth - 8); - boxsum(dgd, width, height, stride, r, 0, B, width, T, width); - boxsum(dgd, width, height, stride, r, 1, A, width, T, width); + // Don't filter tiles with dimensions < 5 on any axis + if ((width < 5) || (height < 5)) return; + + boxsum(dgd, width, height, stride, r, 0, B, width); + boxsum(dgd, width, height, stride, r, 1, A, width); boxnum(width, height, r, num, width); + // The following loop is optimized assuming r <= 2. If we allow + // r > 2, then the loop will need modifying. + assert(r <= 2); for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) { const int k = i * width + j; const int n = num[k]; - const int64_t p = A[k] * n - B[k] * B[k]; - const int64_t q = p + n * n * eps; - A[k] = (int32_t)((p << SGRPROJ_SGR_BITS) + (q >> 1)) / q; + // Assuming that we only allow up to 12-bit depth and r <= 2, + // we calculate p = n^2 * Var(n-pixel block of original image) + // (where n = 2 * r + 1 <= 5). + // + // There is an inequality which gives a bound on the variance: + // https://en.wikipedia.org/wiki/Popoviciu's_inequality_on_variances + // In this case, since each pixel is in the range [0, 2^12), + // the variance is at most 1/4 * (2^12)^2 = 2^22. + // Then p <= 25^2 * 2^22 < 2^32, and also q <= p + 25^2 * 68 < 2^32. + // + // The point of all this is to guarantee that q < 2^32, so that + // platforms with a 64-bit by 32-bit divide unit (eg, x86) + // can do the division by q more efficiently. + const uint32_t p = (uint32_t)((uint64_t)A[k] * n - (uint64_t)B[k] * B[k]); + const uint32_t q = (uint32_t)(p + n * n * eps); + assert((uint64_t)A[k] * n - (uint64_t)B[k] * B[k] < (25 * 25U << 22)); + A[k] = (int32_t)(((uint64_t)p << SGRPROJ_SGR_BITS) + (q >> 1)) / q; B[k] = ((SGRPROJ_SGR - A[k]) * B[k] + (n >> 1)) / n; } } @@ -437,8 +575,8 @@ } #else if (r > 1) boxnum(width, height, r = 1, num, width); - boxsum(A, width, height, width, r, 0, A, width, T, width); - boxsum(B, width, height, width, r, 0, B, width, T, width); + boxsum(A, width, height, width, r, 0, A, width); + boxsum(B, width, height, width, r, 0, B, width); for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) { const int k = i * width + j; @@ -524,72 +662,85 @@ } } -static void apply_domaintxfmrf_hor(int iter, int param, uint8_t *img, int width, - int height, int img_stride, int32_t *dat, - int dat_stride) { - int i, j; - for (i = 0; i < height; ++i) { - uint8_t *ip = &img[i * img_stride]; - int32_t *dp = &dat[i * dat_stride]; - *dp *= DOMAINTXFMRF_VTABLE_PREC; - dp++; - ip++; +static void apply_domaintxfmrf(int iter, int param, uint8_t *diff_right, + uint8_t *diff_down, int width, int height, + int32_t *dat, int dat_stride) { + int i, j, acc; + // Do first row separately, to initialize the top to bottom filter + i = 0; + { // left to right - for (j = 1; j < width; ++j, dp++, ip++) { - const int v = domaintxfmrf_vtable[iter][param][abs(ip[0] - ip[-1])]; - dp[0] = dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + - ((v * dp[-1] + DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS); + acc = dat[i * dat_stride] * DOMAINTXFMRF_VTABLE_PREC; + dat[i * dat_stride] = acc; + for (j = 1; j < width; ++j) { + const int in = dat[i * dat_stride + j]; + const int diff = + diff_right[i * width + j - 1]; // Left absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = in * (DOMAINTXFMRF_VTABLE_PREC - v) + + ROUND_POWER_OF_TWO(v * acc, DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; } // right to left - dp -= 2; - ip -= 2; - for (j = width - 2; j >= 0; --j, dp--, ip--) { - const int v = domaintxfmrf_vtable[iter][param][abs(ip[1] - ip[0])]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + v * dp[1] + - DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS; + for (j = width - 2; j >= 0; --j) { + const int in = dat[i * dat_stride + j]; + const int diff = diff_right[i * width + j]; // Right absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = ROUND_POWER_OF_TWO(in * (DOMAINTXFMRF_VTABLE_PREC - v) + acc * v, + DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; } } -} -static void apply_domaintxfmrf_ver(int iter, int param, uint8_t *img, int width, - int height, int img_stride, int32_t *dat, - int dat_stride) { - int i, j; - for (j = 0; j < width; ++j) { - uint8_t *ip = &img[j]; - int32_t *dp = &dat[j]; - dp += dat_stride; - ip += img_stride; + for (i = 1; i < height; ++i) { + // left to right + acc = dat[i * dat_stride] * DOMAINTXFMRF_VTABLE_PREC; + dat[i * dat_stride] = acc; + for (j = 1; j < width; ++j) { + const int in = dat[i * dat_stride + j]; + const int diff = + diff_right[i * width + j - 1]; // Left absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = in * (DOMAINTXFMRF_VTABLE_PREC - v) + + ROUND_POWER_OF_TWO(v * acc, DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; + } + // right to left + for (j = width - 2; j >= 0; --j) { + const int in = dat[i * dat_stride + j]; + const int diff = diff_right[i * width + j]; // Right absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = ROUND_POWER_OF_TWO(in * (DOMAINTXFMRF_VTABLE_PREC - v) + acc * v, + DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; + } // top to bottom - for (i = 1; i < height; ++i, dp += dat_stride, ip += img_stride) { - const int v = - domaintxfmrf_vtable[iter][param][abs(ip[0] - ip[-img_stride])]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + - (dp[-dat_stride] * v + DOMAINTXFMRF_VTABLE_PREC / 2)) >> - DOMAINTXFMRF_VTABLE_PRECBITS; - } - // bottom to top - dp -= 2 * dat_stride; - ip -= 2 * img_stride; - for (i = height - 2; i >= 0; --i, dp -= dat_stride, ip -= img_stride) { - const int v = - domaintxfmrf_vtable[iter][param][abs(ip[img_stride] - ip[0])]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + dp[dat_stride] * v + - DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS; + for (j = 0; j < width; ++j) { + const int in = dat[i * dat_stride + j]; + const int in_above = dat[(i - 1) * dat_stride + j]; + const int diff = + diff_down[(i - 1) * width + j]; // Upward absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = + ROUND_POWER_OF_TWO(in * (DOMAINTXFMRF_VTABLE_PREC - v) + in_above * v, + DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; } } -} - -static void apply_domaintxfmrf_reduce_prec(int32_t *dat, int width, int height, - int dat_stride) { - int i, j; - for (i = 0; i < height; ++i) { - for (j = 0; j < width; ++j) { - dat[i * dat_stride + j] = ROUND_POWER_OF_TWO_SIGNED( - dat[i * dat_stride + j], DOMAINTXFMRF_VTABLE_PRECBITS); + for (j = 0; j < width; ++j) { + // bottom to top + output rounding + acc = dat[(height - 1) * dat_stride + j]; + dat[(height - 1) * dat_stride + j] = + ROUND_POWER_OF_TWO(acc, DOMAINTXFMRF_VTABLE_PRECBITS); + for (i = height - 2; i >= 0; --i) { + const int in = dat[i * dat_stride + j]; + const int diff = + diff_down[i * width + j]; // Downward absolute difference + const int v = domaintxfmrf_vtable[iter][param][diff]; + acc = ROUND_POWER_OF_TWO(in * (DOMAINTXFMRF_VTABLE_PREC - v) + acc * v, + DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = + ROUND_POWER_OF_TWO(acc, DOMAINTXFMRF_VTABLE_PRECBITS); } } } @@ -598,16 +749,35 @@ int stride, int param, uint8_t *dst, int dst_stride, int32_t *tmpbuf) { int32_t *dat = tmpbuf; + uint8_t *diff_right = (uint8_t *)(tmpbuf + RESTORATION_TILEPELS_MAX); + uint8_t *diff_down = diff_right + RESTORATION_TILEPELS_MAX; int i, j, t; + + for (i = 0; i < height; ++i) { + int cur_px = dgd[i * stride]; + for (j = 0; j < width - 1; ++j) { + const int next_px = dgd[i * stride + j + 1]; + diff_right[i * width + j] = abs(cur_px - next_px); + cur_px = next_px; + } + } + for (j = 0; j < width; ++j) { + int cur_px = dgd[j]; + for (i = 0; i < height - 1; ++i) { + const int next_px = dgd[(i + 1) * stride + j]; + diff_down[i * width + j] = abs(cur_px - next_px); + cur_px = next_px; + } + } for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) { dat[i * width + j] = dgd[i * stride + j]; } } + for (t = 0; t < DOMAINTXFMRF_ITERS; ++t) { - apply_domaintxfmrf_hor(t, param, dgd, width, height, stride, dat, width); - apply_domaintxfmrf_ver(t, param, dgd, width, height, stride, dat, width); - apply_domaintxfmrf_reduce_prec(dat, width, height, width); + apply_domaintxfmrf(t, param, diff_right, diff_down, width, height, dat, + width); } for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) { @@ -848,32 +1018,30 @@ int32_t *dat, int dat_stride, int bd) { const int shift = (bd - 8); - int i, j; + int i, j, acc, old_px; for (i = 0; i < height; ++i) { - uint16_t *ip = &img[i * img_stride]; - int32_t *dp = &dat[i * dat_stride]; - *dp *= DOMAINTXFMRF_VTABLE_PREC; - dp++; - ip++; // left to right - for (j = 1; j < width; ++j, dp++, ip++) { - const int v = - domaintxfmrf_vtable[iter][param] - [abs((ip[0] >> shift) - (ip[-1] >> shift))]; - dp[0] = dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + - ((v * dp[-1] + DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS); + acc = dat[i * dat_stride] * DOMAINTXFMRF_VTABLE_PREC; + dat[i * dat_stride] = acc; + old_px = img[i * img_stride] >> shift; + for (j = 1; j < width; ++j) { + const int cur_px = img[i * img_stride + j] >> shift; + const int v = domaintxfmrf_vtable[iter][param][abs(cur_px - old_px)]; + acc = dat[i * dat_stride + j] * (DOMAINTXFMRF_VTABLE_PREC - v) + + ((v * acc + DOMAINTXFMRF_VTABLE_PREC / 2) >> + DOMAINTXFMRF_VTABLE_PRECBITS); + dat[i * dat_stride + j] = acc; + old_px = cur_px; } // right to left - dp -= 2; - ip -= 2; - for (j = width - 2; j >= 0; --j, dp--, ip--) { - const int v = - domaintxfmrf_vtable[iter][param] - [abs((ip[1] >> shift) - (ip[0] >> shift))]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + v * dp[1] + - DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS; + for (j = width - 2; j >= 0; --j) { + const int cur_px = img[i * img_stride + j] >> shift; + const int v = domaintxfmrf_vtable[iter][param][abs(cur_px - old_px)]; + acc = (dat[i * dat_stride + j] * (DOMAINTXFMRF_VTABLE_PREC - v) + + v * acc + DOMAINTXFMRF_VTABLE_PREC / 2) >> + DOMAINTXFMRF_VTABLE_PRECBITS; + dat[i * dat_stride + j] = acc; + old_px = cur_px; } } } @@ -882,30 +1050,33 @@ int width, int height, int img_stride, int32_t *dat, int dat_stride, int bd) { - int i, j; const int shift = (bd - 8); + int i, j, old_px; for (j = 0; j < width; ++j) { - uint16_t *ip = &img[j]; - int32_t *dp = &dat[j]; - dp += dat_stride; - ip += img_stride; // top to bottom - for (i = 1; i < height; ++i, dp += dat_stride, ip += img_stride) { - const int v = domaintxfmrf_vtable[iter][param][abs( - (ip[0] >> shift) - (ip[-img_stride] >> shift))]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + - (dp[-dat_stride] * v + DOMAINTXFMRF_VTABLE_PREC / 2)) >> - DOMAINTXFMRF_VTABLE_PRECBITS; + acc = dat[j]; + old_px = img[j] >> shift; + for (i = 1; i < height; ++i) { + const int cur_px = img[i * img_stride + j] >> shift; + const int v = domaintxfmrf_vtable[iter][param][abs(cur_px - old_px)]; + acc = (dat[i * dat_stride + j] * (DOMAINTXFMRF_VTABLE_PREC - v) + + (acc * v + DOMAINTXFMRF_VTABLE_PREC / 2)) >> + DOMAINTXFMRF_VTABLE_PRECBITS; + dat[i * dat_stride + j] = acc; + old_px = cur_px; } // bottom to top - dp -= 2 * dat_stride; - ip -= 2 * img_stride; - for (i = height - 2; i >= 0; --i, dp -= dat_stride, ip -= img_stride) { - const int v = domaintxfmrf_vtable[iter][param][abs( - (ip[img_stride] >> shift) - (ip[0] >> shift))]; - dp[0] = (dp[0] * (DOMAINTXFMRF_VTABLE_PREC - v) + dp[dat_stride] * v + - DOMAINTXFMRF_VTABLE_PREC / 2) >> - DOMAINTXFMRF_VTABLE_PRECBITS; + dat[(height - 1) * dat_stride + j] = + ROUND_POWER_OF_TWO(acc, DOMAINTXFMRF_VTABLE_PRECBITS); + for (i = height - 2; i >= 0; --i) { + const int cur_px = img[i * img_stride + j] >> shift; + const int v = domaintxfmrf_vtable[iter][param][abs(old_px - cur_px)]; + acc = (dat[i * dat_stride + j] * (DOMAINTXFMRF_VTABLE_PREC - v) + + acc * v + DOMAINTXFMRF_VTABLE_PREC / 2) >> + DOMAINTXFMRF_VTABLE_PRECBITS; + dat[i * dat_stride + j] = + ROUND_POWER_OF_TWO(acc, DOMAINTXFMRF_VTABLE_PRECBITS); + old_px = cur_px; } } } @@ -926,7 +1097,6 @@ width, bit_depth); apply_domaintxfmrf_ver_highbd(t, param, dgd, width, height, stride, dat, width, bit_depth); - apply_domaintxfmrf_reduce_prec(dat, width, height, width); } for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) {
diff --git a/av1/common/restoration.h b/av1/common/restoration.h index cf44962..cb1d11e 100644 --- a/av1/common/restoration.h +++ b/av1/common/restoration.h
@@ -38,8 +38,9 @@ #define DOMAINTXFMRF_VTABLE_PREC (1 << DOMAINTXFMRF_VTABLE_PRECBITS) #define DOMAINTXFMRF_MULT \ sqrt(((1 << (DOMAINTXFMRF_ITERS * 2)) - 1) * 2.0 / 3.0) -// A single 32 bit buffer needed for the filter -#define DOMAINTXFMRF_TMPBUF_SIZE (RESTORATION_TILEPELS_MAX * sizeof(int32_t)) +// 1 32-bit and 2 8-bit buffers needed for the filter +#define DOMAINTXFMRF_TMPBUF_SIZE \ + (RESTORATION_TILEPELS_MAX * (sizeof(int32_t) + 2 * sizeof(uint8_t))) // One extra buffer needed in encoder, which is either 8-bit or 16-bit // depending on the video bit depth. #if CONFIG_AOM_HIGHBITDEPTH @@ -49,10 +50,10 @@ #endif #define DOMAINTXFMRF_BITS (DOMAINTXFMRF_PARAMS_BITS) -// 5 32-bit buffers needed for the filter: +// 4 32-bit buffers needed for the filter: // 2 for the restored versions of the frame and -// 3 for each restoration operation -#define SGRPROJ_TMPBUF_SIZE (RESTORATION_TILEPELS_MAX * 5 * sizeof(int32_t)) +// 2 for each restoration operation +#define SGRPROJ_TMPBUF_SIZE (RESTORATION_TILEPELS_MAX * 4 * sizeof(int32_t)) #define SGRPROJ_EXTBUF_SIZE (0) #define SGRPROJ_PARAMS_BITS 3 #define SGRPROJ_PARAMS (1 << SGRPROJ_PARAMS_BITS)