| Index: third_party/libwebp/dsp/dec_neon.c
|
| diff --git a/third_party/libwebp/dsp/dec_neon.c b/third_party/libwebp/dsp/dec_neon.c
|
| index e633a30750d7438a5991584796e17c423a4c261e..ec824b790ba3d87a7996c61639cb94e5aa080faa 100644
|
| --- a/third_party/libwebp/dsp/dec_neon.c
|
| +++ b/third_party/libwebp/dsp/dec_neon.c
|
| @@ -1,4 +1,4 @@
|
| -// Copyright 2011 Google Inc.
|
| +// Copyright 2012 Google Inc. All Rights Reserved.
|
| //
|
| // This code is licensed under the same terms as WebM:
|
| // Software License Agreement: http://www.webmproject.org/license/software/
|
| @@ -7,9 +7,12 @@
|
| //
|
| // ARM NEON version of dsp functions and loop filtering.
|
| //
|
| -// Author: somnath@google.com (Somnath Banerjee)
|
| +// Authors: Somnath Banerjee (somnath@google.com)
|
| +// Johann Koenig (johannkoenig@google.com)
|
|
|
| -#if defined(__GNUC__) && defined(__ARM_NEON__)
|
| +#include "./dsp.h"
|
| +
|
| +#if defined(WEBP_USE_NEON)
|
|
|
| #include "../dec/vp8i.h"
|
|
|
| @@ -152,9 +155,167 @@ static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) {
|
| }
|
| }
|
|
|
| +static void TransformOneNEON(const int16_t *in, uint8_t *dst) {
|
| + const int kBPS = BPS;
|
| + const int16_t constants[] = {20091, 17734, 0, 0};
|
| + /* kC1, kC2. Padded because vld1.16 loads 8 bytes
|
| + * Technically these are unsigned but vqdmulh is only available in signed.
|
| + * vqdmulh returns high half (effectively >> 16) but also doubles the value,
|
| + * changing the >> 16 to >> 15 and requiring an additional >> 1.
|
| + * We use this to our advantage with kC2. The canonical value is 35468.
|
| + * However, the high bit is set so treating it as signed will give incorrect
|
| + * results. We avoid this by down shifting by 1 here to clear the highest bit.
|
| + * Combined with the doubling effect of vqdmulh we get >> 16.
|
| + * This can not be applied to kC1 because the lowest bit is set. Down shifting
|
| + * the constant would reduce precision.
|
| + */
|
| +
|
| + /* libwebp uses a trick to avoid some extra addition that libvpx does.
|
| + * Instead of:
|
| + * temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
|
| + * libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
|
| + * same issue with kC1 and vqdmulh that we work around by down shifting kC2
|
| + */
|
| +
|
| + /* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */
|
| + __asm__ volatile (
|
| + "vld1.16 {q1, q2}, [%[in]] \n"
|
| + "vld1.16 {d0}, [%[constants]] \n"
|
| +
|
| + /* d2: in[0]
|
| + * d3: in[8]
|
| + * d4: in[4]
|
| + * d5: in[12]
|
| + */
|
| + "vswp d3, d4 \n"
|
| +
|
| + /* q8 = {in[4], in[12]} * kC1 * 2 >> 16
|
| + * q9 = {in[4], in[12]} * kC2 >> 16
|
| + */
|
| + "vqdmulh.s16 q8, q2, d0[0] \n"
|
| + "vqdmulh.s16 q9, q2, d0[1] \n"
|
| +
|
| + /* d22 = a = in[0] + in[8]
|
| + * d23 = b = in[0] - in[8]
|
| + */
|
| + "vqadd.s16 d22, d2, d3 \n"
|
| + "vqsub.s16 d23, d2, d3 \n"
|
| +
|
| + /* The multiplication should be x * kC1 >> 16
|
| + * However, with vqdmulh we get x * kC1 * 2 >> 16
|
| + * (multiply, double, return high half)
|
| + * We avoided this in kC2 by pre-shifting the constant.
|
| + * q8 = in[4]/[12] * kC1 >> 16
|
| + */
|
| + "vshr.s16 q8, q8, #1 \n"
|
| +
|
| + /* Add {in[4], in[12]} back after the multiplication. This is handled by
|
| + * adding 1 << 16 to kC1 in the libwebp C code.
|
| + */
|
| + "vqadd.s16 q8, q2, q8 \n"
|
| +
|
| + /* d20 = c = in[4]*kC2 - in[12]*kC1
|
| + * d21 = d = in[4]*kC1 + in[12]*kC2
|
| + */
|
| + "vqsub.s16 d20, d18, d17 \n"
|
| + "vqadd.s16 d21, d19, d16 \n"
|
| +
|
| + /* d2 = tmp[0] = a + d
|
| + * d3 = tmp[1] = b + c
|
| + * d4 = tmp[2] = b - c
|
| + * d5 = tmp[3] = a - d
|
| + */
|
| + "vqadd.s16 d2, d22, d21 \n"
|
| + "vqadd.s16 d3, d23, d20 \n"
|
| + "vqsub.s16 d4, d23, d20 \n"
|
| + "vqsub.s16 d5, d22, d21 \n"
|
| +
|
| + "vzip.16 q1, q2 \n"
|
| + "vzip.16 q1, q2 \n"
|
| +
|
| + "vswp d3, d4 \n"
|
| +
|
| + /* q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
|
| + * q9 = {tmp[4], tmp[12]} * kC2 >> 16
|
| + */
|
| + "vqdmulh.s16 q8, q2, d0[0] \n"
|
| + "vqdmulh.s16 q9, q2, d0[1] \n"
|
| +
|
| + /* d22 = a = tmp[0] + tmp[8]
|
| + * d23 = b = tmp[0] - tmp[8]
|
| + */
|
| + "vqadd.s16 d22, d2, d3 \n"
|
| + "vqsub.s16 d23, d2, d3 \n"
|
| +
|
| + /* See long winded explanations prior */
|
| + "vshr.s16 q8, q8, #1 \n"
|
| + "vqadd.s16 q8, q2, q8 \n"
|
| +
|
| + /* d20 = c = in[4]*kC2 - in[12]*kC1
|
| + * d21 = d = in[4]*kC1 + in[12]*kC2
|
| + */
|
| + "vqsub.s16 d20, d18, d17 \n"
|
| + "vqadd.s16 d21, d19, d16 \n"
|
| +
|
| + /* d2 = tmp[0] = a + d
|
| + * d3 = tmp[1] = b + c
|
| + * d4 = tmp[2] = b - c
|
| + * d5 = tmp[3] = a - d
|
| + */
|
| + "vqadd.s16 d2, d22, d21 \n"
|
| + "vqadd.s16 d3, d23, d20 \n"
|
| + "vqsub.s16 d4, d23, d20 \n"
|
| + "vqsub.s16 d5, d22, d21 \n"
|
| +
|
| + "vld1.32 d6[0], [%[dst]], %[kBPS] \n"
|
| + "vld1.32 d6[1], [%[dst]], %[kBPS] \n"
|
| + "vld1.32 d7[0], [%[dst]], %[kBPS] \n"
|
| + "vld1.32 d7[1], [%[dst]], %[kBPS] \n"
|
| +
|
| + "sub %[dst], %[dst], %[kBPS], lsl #2 \n"
|
| +
|
| + /* (val) + 4 >> 3 */
|
| + "vrshr.s16 d2, d2, #3 \n"
|
| + "vrshr.s16 d3, d3, #3 \n"
|
| + "vrshr.s16 d4, d4, #3 \n"
|
| + "vrshr.s16 d5, d5, #3 \n"
|
| +
|
| + "vzip.16 q1, q2 \n"
|
| + "vzip.16 q1, q2 \n"
|
| +
|
| + /* Must accumulate before saturating */
|
| + "vmovl.u8 q8, d6 \n"
|
| + "vmovl.u8 q9, d7 \n"
|
| +
|
| + "vqadd.s16 q1, q1, q8 \n"
|
| + "vqadd.s16 q2, q2, q9 \n"
|
| +
|
| + "vqmovun.s16 d0, q1 \n"
|
| + "vqmovun.s16 d1, q2 \n"
|
| +
|
| + "vst1.32 d0[0], [%[dst]], %[kBPS] \n"
|
| + "vst1.32 d0[1], [%[dst]], %[kBPS] \n"
|
| + "vst1.32 d1[0], [%[dst]], %[kBPS] \n"
|
| + "vst1.32 d1[1], [%[dst]] \n"
|
| +
|
| + : [in] "+r"(in), [dst] "+r"(dst) /* modified registers */
|
| + : [kBPS] "r"(kBPS), [constants] "r"(constants) /* constants */
|
| + : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" /* clobbered */
|
| + );
|
| +}
|
| +
|
| +static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) {
|
| + TransformOneNEON(in, dst);
|
| + if (do_two) {
|
| + TransformOneNEON(in + 16, dst + 4);
|
| + }
|
| +}
|
| +
|
| extern void VP8DspInitNEON(void);
|
|
|
| void VP8DspInitNEON(void) {
|
| + VP8Transform = TransformTwoNEON;
|
| +
|
| VP8SimpleVFilter16 = SimpleVFilter16NEON;
|
| VP8SimpleHFilter16 = SimpleHFilter16NEON;
|
| VP8SimpleVFilter16i = SimpleVFilter16iNEON;
|
| @@ -165,4 +326,4 @@ void VP8DspInitNEON(void) {
|
| } // extern "C"
|
| #endif
|
|
|
| -#endif // __GNUC__ && __ARM_NEON__
|
| +#endif // WEBP_USE_NEON
|
|
|