Commit 3d7920e6 authored by Luc Trudeau's avatar Luc Trudeau

Remove VLAs from Loop Restoration

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