summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/dsp/filters_sse2.c
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-12-13 06:35:54 +0100
committerJani Heikkinen <jani.heikkinen@qt.io>2016-12-13 11:05:49 +0000
commita4125f0c4e8988012fe2bf5b9f933ed63c3c97d0 (patch)
tree7b183f687bd0ba111ec50d406226283c980e03a5 /src/3rdparty/libwebp/src/dsp/filters_sse2.c
parent5976c46685b1335c86ce702e3af69262de97096c (diff)
Bundled libwebp updated to version 0.5.1
This commit imports libwebp 0.5.1, including AUTHORS, COPYING, ChangeLog, NEWS, PATENTS, README and src directories. In src, only includes header and source files. Upstream changes since 0.5.0 have been merged in. Also updated version in qt_attribution.json. Conflicts: src/3rdparty/libwebp.pri src/3rdparty/libwebp/qt_attribution.json src/3rdparty/libwebp/src/webp/config.h Change-Id: I7d0c15400154c3b4ee8ff37665303307c4b84f9f Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src/3rdparty/libwebp/src/dsp/filters_sse2.c')
-rw-r--r--src/3rdparty/libwebp/src/dsp/filters_sse2.c272
1 files changed, 125 insertions, 147 deletions
diff --git a/src/3rdparty/libwebp/src/dsp/filters_sse2.c b/src/3rdparty/libwebp/src/dsp/filters_sse2.c
index bf93342..67f7799 100644
--- a/src/3rdparty/libwebp/src/dsp/filters_sse2.c
+++ b/src/3rdparty/libwebp/src/dsp/filters_sse2.c
@@ -33,82 +33,39 @@
(void)height; // Silence unused warning.
static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length, int inverse) {
+ uint8_t* dst, int length) {
int i;
const int max_pos = length & ~31;
assert(length >= 0);
- if (inverse) {
- for (i = 0; i < max_pos; i += 32) {
- const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]);
- const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]);
- const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]);
- const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]);
- const __m128i C0 = _mm_add_epi8(A0, B0);
- const __m128i C1 = _mm_add_epi8(A1, B1);
- _mm_storeu_si128((__m128i*)&dst[i + 0], C0);
- _mm_storeu_si128((__m128i*)&dst[i + 16], C1);
- }
- for (; i < length; ++i) dst[i] = src[i] + pred[i];
- } else {
- for (i = 0; i < max_pos; i += 32) {
- const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]);
- const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]);
- const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]);
- const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]);
- const __m128i C0 = _mm_sub_epi8(A0, B0);
- const __m128i C1 = _mm_sub_epi8(A1, B1);
- _mm_storeu_si128((__m128i*)&dst[i + 0], C0);
- _mm_storeu_si128((__m128i*)&dst[i + 16], C1);
- }
- for (; i < length; ++i) dst[i] = src[i] - pred[i];
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]);
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]);
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]);
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]);
+ const __m128i C0 = _mm_sub_epi8(A0, B0);
+ const __m128i C1 = _mm_sub_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)&dst[i + 0], C0);
+ _mm_storeu_si128((__m128i*)&dst[i + 16], C1);
}
+ for (; i < length; ++i) dst[i] = src[i] - pred[i];
}
// Special case for left-based prediction (when preds==dst-1 or preds==src-1).
-static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length,
- int inverse) {
+static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length) {
int i;
- if (length <= 0) return;
- if (inverse) {
- const int max_pos = length & ~7;
- __m128i last = _mm_set_epi32(0, 0, 0, dst[-1]);
- for (i = 0; i < max_pos; i += 8) {
- const __m128i A0 = _mm_loadl_epi64((const __m128i*)(src + i));
- const __m128i A1 = _mm_add_epi8(A0, last);
- const __m128i A2 = _mm_slli_si128(A1, 1);
- const __m128i A3 = _mm_add_epi8(A1, A2);
- const __m128i A4 = _mm_slli_si128(A3, 2);
- const __m128i A5 = _mm_add_epi8(A3, A4);
- const __m128i A6 = _mm_slli_si128(A5, 4);
- const __m128i A7 = _mm_add_epi8(A5, A6);
- _mm_storel_epi64((__m128i*)(dst + i), A7);
- last = _mm_srli_epi64(A7, 56);
- }
- for (; i < length; ++i) dst[i] = src[i] + dst[i - 1];
- } else {
- const int max_pos = length & ~31;
- for (i = 0; i < max_pos; i += 32) {
- const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + i + 0 ));
- const __m128i B0 = _mm_loadu_si128((const __m128i*)(src + i + 0 - 1));
- const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + i + 16 ));
- const __m128i B1 = _mm_loadu_si128((const __m128i*)(src + i + 16 - 1));
- const __m128i C0 = _mm_sub_epi8(A0, B0);
- const __m128i C1 = _mm_sub_epi8(A1, B1);
- _mm_storeu_si128((__m128i*)(dst + i + 0), C0);
- _mm_storeu_si128((__m128i*)(dst + i + 16), C1);
- }
- for (; i < length; ++i) dst[i] = src[i] - src[i - 1];
- }
-}
-
-static void PredictLineC(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length, int inverse) {
- int i;
- if (inverse) {
- for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
- } else {
- for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
+ const int max_pos = length & ~31;
+ assert(length >= 0);
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + i + 0 ));
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)(src + i + 0 - 1));
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + i + 16 ));
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)(src + i + 16 - 1));
+ const __m128i C0 = _mm_sub_epi8(A0, B0);
+ const __m128i C1 = _mm_sub_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)(dst + i + 0), C0);
+ _mm_storeu_si128((__m128i*)(dst + i + 16), C1);
}
+ for (; i < length; ++i) dst[i] = src[i] - src[i - 1];
}
//------------------------------------------------------------------------------
@@ -117,21 +74,18 @@ static void PredictLineC(const uint8_t* src, const uint8_t* pred,
static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
int width, int height, int stride,
int row, int num_rows,
- int inverse, uint8_t* out) {
- const uint8_t* preds;
+ uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
in += start_offset;
out += start_offset;
- preds = inverse ? out : in;
if (row == 0) {
// Leftmost pixel is the same as input for topmost scanline.
out[0] = in[0];
- PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ PredictLineLeft(in + 1, out + 1, width - 1);
row = 1;
- preds += stride;
in += stride;
out += stride;
}
@@ -139,10 +93,9 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
// Leftmost pixel is predicted from above.
- PredictLineC(in, preds - stride, out, 1, inverse);
- PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ out[0] = in[0] - in[-stride];
+ PredictLineLeft(in + 1, out + 1, width - 1);
++row;
- preds += stride;
in += stride;
out += stride;
}
@@ -153,34 +106,27 @@ static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
int width, int height, int stride,
- int row, int num_rows,
- int inverse, uint8_t* out) {
- const uint8_t* preds;
+ int row, int num_rows, uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
in += start_offset;
out += start_offset;
- preds = inverse ? out : in;
if (row == 0) {
// Very first top-left pixel is copied.
out[0] = in[0];
// Rest of top scan-line is left-predicted.
- PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ PredictLineLeft(in + 1, out + 1, width - 1);
row = 1;
in += stride;
out += stride;
- } else {
- // We are starting from in-between. Make sure 'preds' points to prev row.
- preds -= stride;
}
// Filter line-by-line.
while (row < last_row) {
- PredictLineTop(in, preds, out, width, inverse);
+ PredictLineTop(in, in - stride, out, width);
++row;
- preds += stride;
in += stride;
out += stride;
}
@@ -219,49 +165,10 @@ static void GradientPredictDirect(const uint8_t* const row,
}
}
-static void GradientPredictInverse(const uint8_t* const in,
- const uint8_t* const top,
- uint8_t* const row, int length) {
- if (length > 0) {
- int i;
- const int max_pos = length & ~7;
- const __m128i zero = _mm_setzero_si128();
- __m128i A = _mm_set_epi32(0, 0, 0, row[-1]); // left sample
- for (i = 0; i < max_pos; i += 8) {
- const __m128i tmp0 = _mm_loadl_epi64((const __m128i*)&top[i]);
- const __m128i tmp1 = _mm_loadl_epi64((const __m128i*)&top[i - 1]);
- const __m128i B = _mm_unpacklo_epi8(tmp0, zero);
- const __m128i C = _mm_unpacklo_epi8(tmp1, zero);
- const __m128i tmp2 = _mm_loadl_epi64((const __m128i*)&in[i]);
- const __m128i D = _mm_unpacklo_epi8(tmp2, zero); // base input
- const __m128i E = _mm_sub_epi16(B, C); // unclipped gradient basis B - C
- __m128i out = zero; // accumulator for output
- __m128i mask_hi = _mm_set_epi32(0, 0, 0, 0xff);
- int k = 8;
- while (1) {
- const __m128i tmp3 = _mm_add_epi16(A, E); // delta = A + B - C
- const __m128i tmp4 = _mm_min_epi16(tmp3, mask_hi);
- const __m128i tmp5 = _mm_max_epi16(tmp4, zero); // clipped delta
- const __m128i tmp6 = _mm_add_epi16(tmp5, D); // add to in[] values
- A = _mm_and_si128(tmp6, mask_hi); // 1-complement clip
- out = _mm_or_si128(out, A); // accumulate output
- if (--k == 0) break;
- A = _mm_slli_si128(A, 2); // rotate left sample
- mask_hi = _mm_slli_si128(mask_hi, 2); // rotate mask
- }
- A = _mm_srli_si128(A, 14); // prepare left sample for next iteration
- _mm_storel_epi64((__m128i*)&row[i], _mm_packus_epi16(out, zero));
- }
- for (; i < length; ++i) {
- row[i] = in[i] + GradientPredictorC(row[i - 1], top[i], top[i - 1]);
- }
- }
-}
-
static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
int width, int height, int stride,
int row, int num_rows,
- int inverse, uint8_t* out) {
+ uint8_t* out) {
const size_t start_offset = row * stride;
const int last_row = row + num_rows;
SANITY_CHECK(in, out);
@@ -271,7 +178,7 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
// left prediction for top scan-line
if (row == 0) {
out[0] = in[0];
- PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ PredictLineLeft(in + 1, out + 1, width - 1);
row = 1;
in += stride;
out += stride;
@@ -279,13 +186,8 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
// Filter line-by-line.
while (row < last_row) {
- if (inverse) {
- PredictLineC(in, out - stride, out, 1, inverse); // predict from above
- GradientPredictInverse(in + 1, out + 1 - stride, out + 1, width - 1);
- } else {
- PredictLineC(in, in - stride, out, 1, inverse);
- GradientPredictDirect(in + 1, in + 1 - stride, out + 1, width - 1);
- }
+ out[0] = in[0] - in[-stride];
+ GradientPredictDirect(in + 1, in + 1 - stride, out + 1, width - 1);
++row;
in += stride;
out += stride;
@@ -298,36 +200,112 @@ static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
static void HorizontalFilter(const uint8_t* data, int width, int height,
int stride, uint8_t* filtered_data) {
- DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+ DoHorizontalFilter(data, width, height, stride, 0, height, filtered_data);
}
static void VerticalFilter(const uint8_t* data, int width, int height,
int stride, uint8_t* filtered_data) {
- DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+ DoVerticalFilter(data, width, height, stride, 0, height, filtered_data);
}
-
static void GradientFilter(const uint8_t* data, int width, int height,
int stride, uint8_t* filtered_data) {
- DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
+ DoGradientFilter(data, width, height, stride, 0, height, filtered_data);
}
-
//------------------------------------------------------------------------------
+// Inverse transforms
-static void VerticalUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
+static void HorizontalUnfilter(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
+ int i;
+ __m128i last;
+ out[0] = in[0] + (prev == NULL ? 0 : prev[0]);
+ if (width <= 1) return;
+ last = _mm_set_epi32(0, 0, 0, out[0]);
+ for (i = 1; i + 8 <= width; i += 8) {
+ const __m128i A0 = _mm_loadl_epi64((const __m128i*)(in + i));
+ const __m128i A1 = _mm_add_epi8(A0, last);
+ const __m128i A2 = _mm_slli_si128(A1, 1);
+ const __m128i A3 = _mm_add_epi8(A1, A2);
+ const __m128i A4 = _mm_slli_si128(A3, 2);
+ const __m128i A5 = _mm_add_epi8(A3, A4);
+ const __m128i A6 = _mm_slli_si128(A5, 4);
+ const __m128i A7 = _mm_add_epi8(A5, A6);
+ _mm_storel_epi64((__m128i*)(out + i), A7);
+ last = _mm_srli_epi64(A7, 56);
+ }
+ for (; i < width; ++i) out[i] = in[i] + out[i - 1];
}
-static void HorizontalUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
+static void VerticalUnfilter(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
+ if (prev == NULL) {
+ HorizontalUnfilter(NULL, in, out, width);
+ } else {
+ int i;
+ const int max_pos = width & ~31;
+ assert(width >= 0);
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)&in[i + 0]);
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)&in[i + 16]);
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)&prev[i + 0]);
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)&prev[i + 16]);
+ const __m128i C0 = _mm_add_epi8(A0, B0);
+ const __m128i C1 = _mm_add_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)&out[i + 0], C0);
+ _mm_storeu_si128((__m128i*)&out[i + 16], C1);
+ }
+ for (; i < width; ++i) out[i] = in[i] + prev[i];
+ }
}
-static void GradientUnfilter(int width, int height, int stride, int row,
- int num_rows, uint8_t* data) {
- DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
+static void GradientPredictInverse(const uint8_t* const in,
+ const uint8_t* const top,
+ uint8_t* const row, int length) {
+ if (length > 0) {
+ int i;
+ const int max_pos = length & ~7;
+ const __m128i zero = _mm_setzero_si128();
+ __m128i A = _mm_set_epi32(0, 0, 0, row[-1]); // left sample
+ for (i = 0; i < max_pos; i += 8) {
+ const __m128i tmp0 = _mm_loadl_epi64((const __m128i*)&top[i]);
+ const __m128i tmp1 = _mm_loadl_epi64((const __m128i*)&top[i - 1]);
+ const __m128i B = _mm_unpacklo_epi8(tmp0, zero);
+ const __m128i C = _mm_unpacklo_epi8(tmp1, zero);
+ const __m128i D = _mm_loadl_epi64((const __m128i*)&in[i]); // base input
+ const __m128i E = _mm_sub_epi16(B, C); // unclipped gradient basis B - C
+ __m128i out = zero; // accumulator for output
+ __m128i mask_hi = _mm_set_epi32(0, 0, 0, 0xff);
+ int k = 8;
+ while (1) {
+ const __m128i tmp3 = _mm_add_epi16(A, E); // delta = A + B - C
+ const __m128i tmp4 = _mm_packus_epi16(tmp3, zero); // saturate delta
+ const __m128i tmp5 = _mm_add_epi8(tmp4, D); // add to in[]
+ A = _mm_and_si128(tmp5, mask_hi); // 1-complement clip
+ out = _mm_or_si128(out, A); // accumulate output
+ if (--k == 0) break;
+ A = _mm_slli_si128(A, 1); // rotate left sample
+ mask_hi = _mm_slli_si128(mask_hi, 1); // rotate mask
+ A = _mm_unpacklo_epi8(A, zero); // convert 8b->16b
+ }
+ A = _mm_srli_si128(A, 7); // prepare left sample for next iteration
+ _mm_storel_epi64((__m128i*)&row[i], out);
+ }
+ for (; i < length; ++i) {
+ row[i] = in[i] + GradientPredictorC(row[i - 1], top[i], top[i - 1]);
+ }
+ }
+}
+
+static void GradientUnfilter(const uint8_t* prev, const uint8_t* in,
+ uint8_t* out, int width) {
+ if (prev == NULL) {
+ HorizontalUnfilter(NULL, in, out, width);
+ } else {
+ out[0] = in[0] + prev[0]; // predict from above
+ GradientPredictInverse(in + 1, prev + 1, out + 1, width - 1);
+ }
}
//------------------------------------------------------------------------------