summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libwebp/src/dsp
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-06-03 10:58:45 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-06-03 10:58:45 +0200
commit6727ae3172aa7c3a791efd839ebefe24a4b8134c (patch)
tree63ecf158da5ba45bc5501e7bcaf7f57df2ed56f8 /src/3rdparty/libwebp/src/dsp
parent405bfa87e6f1c5b7fe89efa4b566f99d01375567 (diff)
parent454fb13c465e29f0d0f9a295bdb822b4a09c7e48 (diff)
Merge remote-tracking branch 'origin/5.5' into dev
Diffstat (limited to 'src/3rdparty/libwebp/src/dsp')
-rw-r--r--src/3rdparty/libwebp/src/dsp/alpha_processing.c335
-rw-r--r--src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c77
-rw-r--r--src/3rdparty/libwebp/src/dsp/cpu.c62
-rw-r--r--src/3rdparty/libwebp/src/dsp/dec.c138
-rw-r--r--src/3rdparty/libwebp/src/dsp/dec_clip_tables.c366
-rw-r--r--src/3rdparty/libwebp/src/dsp/dec_mips32.c578
-rw-r--r--src/3rdparty/libwebp/src/dsp/dec_neon.c1157
-rw-r--r--src/3rdparty/libwebp/src/dsp/dec_sse2.c526
-rw-r--r--src/3rdparty/libwebp/src/dsp/dsp.h120
-rw-r--r--src/3rdparty/libwebp/src/dsp/enc.c96
-rw-r--r--src/3rdparty/libwebp/src/dsp/enc_avx2.c24
-rw-r--r--src/3rdparty/libwebp/src/dsp/enc_mips32.c776
-rw-r--r--src/3rdparty/libwebp/src/dsp/enc_neon.c713
-rw-r--r--src/3rdparty/libwebp/src/dsp/enc_sse2.c175
-rw-r--r--src/3rdparty/libwebp/src/dsp/lossless.c981
-rw-r--r--src/3rdparty/libwebp/src/dsp/lossless.h135
-rw-r--r--src/3rdparty/libwebp/src/dsp/lossless_mips32.c416
-rw-r--r--src/3rdparty/libwebp/src/dsp/lossless_neon.c357
-rw-r--r--src/3rdparty/libwebp/src/dsp/lossless_sse2.c535
-rw-r--r--src/3rdparty/libwebp/src/dsp/neon.h82
-rw-r--r--src/3rdparty/libwebp/src/dsp/upsampling.c162
-rw-r--r--src/3rdparty/libwebp/src/dsp/upsampling_neon.c56
-rw-r--r--src/3rdparty/libwebp/src/dsp/upsampling_sse2.c30
-rw-r--r--src/3rdparty/libwebp/src/dsp/yuv.c205
-rw-r--r--src/3rdparty/libwebp/src/dsp/yuv.h8
-rw-r--r--src/3rdparty/libwebp/src/dsp/yuv_mips32.c100
-rw-r--r--src/3rdparty/libwebp/src/dsp/yuv_sse2.c322
-rw-r--r--src/3rdparty/libwebp/src/dsp/yuv_tables_sse2.h536
28 files changed, 7492 insertions, 1576 deletions
diff --git a/src/3rdparty/libwebp/src/dsp/alpha_processing.c b/src/3rdparty/libwebp/src/dsp/alpha_processing.c
new file mode 100644
index 0000000..c8e0b4b
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/alpha_processing.c
@@ -0,0 +1,335 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include "./dsp.h"
+
+// Tables can be faster on some platform but incur some extra binary size (~2k).
+// #define USE_TABLES_FOR_ALPHA_MULT
+
+// -----------------------------------------------------------------------------
+
+#define MFIX 24 // 24bit fixed-point arithmetic
+#define HALF ((1u << MFIX) >> 1)
+#define KINV_255 ((1u << MFIX) / 255u)
+
+static uint32_t Mult(uint8_t x, uint32_t mult) {
+ const uint32_t v = (x * mult + HALF) >> MFIX;
+ assert(v <= 255); // <- 24bit precision is enough to ensure that.
+ return v;
+}
+
+#ifdef USE_TABLES_FOR_ALPHA_MULT
+
+static const uint32_t kMultTables[2][256] = {
+ { // (255u << MFIX) / alpha
+ 0x00000000, 0xff000000, 0x7f800000, 0x55000000, 0x3fc00000, 0x33000000,
+ 0x2a800000, 0x246db6db, 0x1fe00000, 0x1c555555, 0x19800000, 0x172e8ba2,
+ 0x15400000, 0x139d89d8, 0x1236db6d, 0x11000000, 0x0ff00000, 0x0f000000,
+ 0x0e2aaaaa, 0x0d6bca1a, 0x0cc00000, 0x0c249249, 0x0b9745d1, 0x0b1642c8,
+ 0x0aa00000, 0x0a333333, 0x09cec4ec, 0x0971c71c, 0x091b6db6, 0x08cb08d3,
+ 0x08800000, 0x0839ce73, 0x07f80000, 0x07ba2e8b, 0x07800000, 0x07492492,
+ 0x07155555, 0x06e45306, 0x06b5e50d, 0x0689d89d, 0x06600000, 0x063831f3,
+ 0x06124924, 0x05ee23b8, 0x05cba2e8, 0x05aaaaaa, 0x058b2164, 0x056cefa8,
+ 0x05500000, 0x05343eb1, 0x05199999, 0x05000000, 0x04e76276, 0x04cfb2b7,
+ 0x04b8e38e, 0x04a2e8ba, 0x048db6db, 0x0479435e, 0x04658469, 0x045270d0,
+ 0x04400000, 0x042e29f7, 0x041ce739, 0x040c30c3, 0x03fc0000, 0x03ec4ec4,
+ 0x03dd1745, 0x03ce540f, 0x03c00000, 0x03b21642, 0x03a49249, 0x03976fc6,
+ 0x038aaaaa, 0x037e3f1f, 0x03722983, 0x03666666, 0x035af286, 0x034fcace,
+ 0x0344ec4e, 0x033a5440, 0x03300000, 0x0325ed09, 0x031c18f9, 0x0312818a,
+ 0x03092492, 0x03000000, 0x02f711dc, 0x02ee5846, 0x02e5d174, 0x02dd7baf,
+ 0x02d55555, 0x02cd5cd5, 0x02c590b2, 0x02bdef7b, 0x02b677d4, 0x02af286b,
+ 0x02a80000, 0x02a0fd5c, 0x029a1f58, 0x029364d9, 0x028ccccc, 0x0286562d,
+ 0x02800000, 0x0279c952, 0x0273b13b, 0x026db6db, 0x0267d95b, 0x026217ec,
+ 0x025c71c7, 0x0256e62a, 0x0251745d, 0x024c1bac, 0x0246db6d, 0x0241b2f9,
+ 0x023ca1af, 0x0237a6f4, 0x0232c234, 0x022df2df, 0x02293868, 0x02249249,
+ 0x02200000, 0x021b810e, 0x021714fb, 0x0212bb51, 0x020e739c, 0x020a3d70,
+ 0x02061861, 0x02020408, 0x01fe0000, 0x01fa0be8, 0x01f62762, 0x01f25213,
+ 0x01ee8ba2, 0x01ead3ba, 0x01e72a07, 0x01e38e38, 0x01e00000, 0x01dc7f10,
+ 0x01d90b21, 0x01d5a3e9, 0x01d24924, 0x01cefa8d, 0x01cbb7e3, 0x01c880e5,
+ 0x01c55555, 0x01c234f7, 0x01bf1f8f, 0x01bc14e5, 0x01b914c1, 0x01b61eed,
+ 0x01b33333, 0x01b05160, 0x01ad7943, 0x01aaaaaa, 0x01a7e567, 0x01a5294a,
+ 0x01a27627, 0x019fcbd2, 0x019d2a20, 0x019a90e7, 0x01980000, 0x01957741,
+ 0x0192f684, 0x01907da4, 0x018e0c7c, 0x018ba2e8, 0x018940c5, 0x0186e5f0,
+ 0x01849249, 0x018245ae, 0x01800000, 0x017dc11f, 0x017b88ee, 0x0179574e,
+ 0x01772c23, 0x01750750, 0x0172e8ba, 0x0170d045, 0x016ebdd7, 0x016cb157,
+ 0x016aaaaa, 0x0168a9b9, 0x0166ae6a, 0x0164b8a7, 0x0162c859, 0x0160dd67,
+ 0x015ef7bd, 0x015d1745, 0x015b3bea, 0x01596596, 0x01579435, 0x0155c7b4,
+ 0x01540000, 0x01523d03, 0x01507eae, 0x014ec4ec, 0x014d0fac, 0x014b5edc,
+ 0x0149b26c, 0x01480a4a, 0x01466666, 0x0144c6af, 0x01432b16, 0x0141938b,
+ 0x01400000, 0x013e7063, 0x013ce4a9, 0x013b5cc0, 0x0139d89d, 0x01385830,
+ 0x0136db6d, 0x01356246, 0x0133ecad, 0x01327a97, 0x01310bf6, 0x012fa0be,
+ 0x012e38e3, 0x012cd459, 0x012b7315, 0x012a150a, 0x0128ba2e, 0x01276276,
+ 0x01260dd6, 0x0124bc44, 0x01236db6, 0x01222222, 0x0120d97c, 0x011f93bc,
+ 0x011e50d7, 0x011d10c4, 0x011bd37a, 0x011a98ef, 0x0119611a, 0x01182bf2,
+ 0x0116f96f, 0x0115c988, 0x01149c34, 0x0113716a, 0x01124924, 0x01112358,
+ 0x01100000, 0x010edf12, 0x010dc087, 0x010ca458, 0x010b8a7d, 0x010a72f0,
+ 0x01095da8, 0x01084a9f, 0x010739ce, 0x01062b2e, 0x01051eb8, 0x01041465,
+ 0x01030c30, 0x01020612, 0x01010204, 0x01000000 },
+ { // alpha * KINV_255
+ 0x00000000, 0x00010101, 0x00020202, 0x00030303, 0x00040404, 0x00050505,
+ 0x00060606, 0x00070707, 0x00080808, 0x00090909, 0x000a0a0a, 0x000b0b0b,
+ 0x000c0c0c, 0x000d0d0d, 0x000e0e0e, 0x000f0f0f, 0x00101010, 0x00111111,
+ 0x00121212, 0x00131313, 0x00141414, 0x00151515, 0x00161616, 0x00171717,
+ 0x00181818, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d,
+ 0x001e1e1e, 0x001f1f1f, 0x00202020, 0x00212121, 0x00222222, 0x00232323,
+ 0x00242424, 0x00252525, 0x00262626, 0x00272727, 0x00282828, 0x00292929,
+ 0x002a2a2a, 0x002b2b2b, 0x002c2c2c, 0x002d2d2d, 0x002e2e2e, 0x002f2f2f,
+ 0x00303030, 0x00313131, 0x00323232, 0x00333333, 0x00343434, 0x00353535,
+ 0x00363636, 0x00373737, 0x00383838, 0x00393939, 0x003a3a3a, 0x003b3b3b,
+ 0x003c3c3c, 0x003d3d3d, 0x003e3e3e, 0x003f3f3f, 0x00404040, 0x00414141,
+ 0x00424242, 0x00434343, 0x00444444, 0x00454545, 0x00464646, 0x00474747,
+ 0x00484848, 0x00494949, 0x004a4a4a, 0x004b4b4b, 0x004c4c4c, 0x004d4d4d,
+ 0x004e4e4e, 0x004f4f4f, 0x00505050, 0x00515151, 0x00525252, 0x00535353,
+ 0x00545454, 0x00555555, 0x00565656, 0x00575757, 0x00585858, 0x00595959,
+ 0x005a5a5a, 0x005b5b5b, 0x005c5c5c, 0x005d5d5d, 0x005e5e5e, 0x005f5f5f,
+ 0x00606060, 0x00616161, 0x00626262, 0x00636363, 0x00646464, 0x00656565,
+ 0x00666666, 0x00676767, 0x00686868, 0x00696969, 0x006a6a6a, 0x006b6b6b,
+ 0x006c6c6c, 0x006d6d6d, 0x006e6e6e, 0x006f6f6f, 0x00707070, 0x00717171,
+ 0x00727272, 0x00737373, 0x00747474, 0x00757575, 0x00767676, 0x00777777,
+ 0x00787878, 0x00797979, 0x007a7a7a, 0x007b7b7b, 0x007c7c7c, 0x007d7d7d,
+ 0x007e7e7e, 0x007f7f7f, 0x00808080, 0x00818181, 0x00828282, 0x00838383,
+ 0x00848484, 0x00858585, 0x00868686, 0x00878787, 0x00888888, 0x00898989,
+ 0x008a8a8a, 0x008b8b8b, 0x008c8c8c, 0x008d8d8d, 0x008e8e8e, 0x008f8f8f,
+ 0x00909090, 0x00919191, 0x00929292, 0x00939393, 0x00949494, 0x00959595,
+ 0x00969696, 0x00979797, 0x00989898, 0x00999999, 0x009a9a9a, 0x009b9b9b,
+ 0x009c9c9c, 0x009d9d9d, 0x009e9e9e, 0x009f9f9f, 0x00a0a0a0, 0x00a1a1a1,
+ 0x00a2a2a2, 0x00a3a3a3, 0x00a4a4a4, 0x00a5a5a5, 0x00a6a6a6, 0x00a7a7a7,
+ 0x00a8a8a8, 0x00a9a9a9, 0x00aaaaaa, 0x00ababab, 0x00acacac, 0x00adadad,
+ 0x00aeaeae, 0x00afafaf, 0x00b0b0b0, 0x00b1b1b1, 0x00b2b2b2, 0x00b3b3b3,
+ 0x00b4b4b4, 0x00b5b5b5, 0x00b6b6b6, 0x00b7b7b7, 0x00b8b8b8, 0x00b9b9b9,
+ 0x00bababa, 0x00bbbbbb, 0x00bcbcbc, 0x00bdbdbd, 0x00bebebe, 0x00bfbfbf,
+ 0x00c0c0c0, 0x00c1c1c1, 0x00c2c2c2, 0x00c3c3c3, 0x00c4c4c4, 0x00c5c5c5,
+ 0x00c6c6c6, 0x00c7c7c7, 0x00c8c8c8, 0x00c9c9c9, 0x00cacaca, 0x00cbcbcb,
+ 0x00cccccc, 0x00cdcdcd, 0x00cecece, 0x00cfcfcf, 0x00d0d0d0, 0x00d1d1d1,
+ 0x00d2d2d2, 0x00d3d3d3, 0x00d4d4d4, 0x00d5d5d5, 0x00d6d6d6, 0x00d7d7d7,
+ 0x00d8d8d8, 0x00d9d9d9, 0x00dadada, 0x00dbdbdb, 0x00dcdcdc, 0x00dddddd,
+ 0x00dedede, 0x00dfdfdf, 0x00e0e0e0, 0x00e1e1e1, 0x00e2e2e2, 0x00e3e3e3,
+ 0x00e4e4e4, 0x00e5e5e5, 0x00e6e6e6, 0x00e7e7e7, 0x00e8e8e8, 0x00e9e9e9,
+ 0x00eaeaea, 0x00ebebeb, 0x00ececec, 0x00ededed, 0x00eeeeee, 0x00efefef,
+ 0x00f0f0f0, 0x00f1f1f1, 0x00f2f2f2, 0x00f3f3f3, 0x00f4f4f4, 0x00f5f5f5,
+ 0x00f6f6f6, 0x00f7f7f7, 0x00f8f8f8, 0x00f9f9f9, 0x00fafafa, 0x00fbfbfb,
+ 0x00fcfcfc, 0x00fdfdfd, 0x00fefefe, 0x00ffffff }
+};
+
+static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
+ return kMultTables[!inverse][a];
+}
+
+#else
+
+static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
+ return inverse ? (255u << MFIX) / a : a * KINV_255;
+}
+
+#endif // USE_TABLES_FOR_ALPHA_MULT
+
+static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ const uint32_t argb = ptr[x];
+ if (argb < 0xff000000u) { // alpha < 255
+ if (argb <= 0x00ffffffu) { // alpha == 0
+ ptr[x] = 0;
+ } else {
+ const uint32_t alpha = (argb >> 24) & 0xff;
+ const uint32_t scale = GetScale(alpha, inverse);
+ uint32_t out = argb & 0xff000000u;
+ out |= Mult(argb >> 0, scale) << 0;
+ out |= Mult(argb >> 8, scale) << 8;
+ out |= Mult(argb >> 16, scale) << 16;
+ ptr[x] = out;
+ }
+ }
+ }
+}
+
+static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ const uint32_t a = alpha[x];
+ if (a != 255) {
+ if (a == 0) {
+ ptr[x] = 0;
+ } else {
+ const uint32_t scale = GetScale(a, inverse);
+ ptr[x] = Mult(ptr[x], scale);
+ }
+ }
+ }
+}
+
+#undef KINV_255
+#undef HALF
+#undef MFIX
+
+void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
+void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+
+//------------------------------------------------------------------------------
+// Generic per-plane calls
+
+void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
+ int inverse) {
+ int n;
+ for (n = 0; n < num_rows; ++n) {
+ WebPMultARGBRow((uint32_t*)ptr, width, inverse);
+ ptr += stride;
+ }
+}
+
+void WebPMultRows(uint8_t* ptr, int stride,
+ const uint8_t* alpha, int alpha_stride,
+ int width, int num_rows, int inverse) {
+ int n;
+ for (n = 0; n < num_rows; ++n) {
+ WebPMultRow(ptr, alpha, width, inverse);
+ ptr += stride;
+ alpha += alpha_stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Premultiplied modes
+
+// non dithered-modes
+
+// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
+// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
+// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
+#if 1 // (int)(x * a / 255.)
+#define MULTIPLIER(a) ((a) * 32897U)
+#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
+#else // (int)(x * a / 255. + .5)
+#define MULTIPLIER(a) ((a) * 65793U)
+#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
+#endif
+
+static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
+ int w, int h, int stride) {
+ while (h-- > 0) {
+ uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
+ const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t a = alpha[4 * i];
+ if (a != 0xff) {
+ const uint32_t mult = MULTIPLIER(a);
+ rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
+ rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
+ rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
+ }
+ }
+ rgba += stride;
+ }
+}
+#undef MULTIPLIER
+#undef PREMULTIPLY
+
+// rgbA4444
+
+#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
+
+static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
+ return (x & 0xf0) | (x >> 4);
+}
+
+static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
+ return (x & 0x0f) | (x << 4);
+}
+
+static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
+ return (x * m) >> 16;
+}
+
+static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
+ int w, int h, int stride,
+ int rg_byte_pos /* 0 or 1 */) {
+ while (h-- > 0) {
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
+ const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
+ const uint8_t a = ba & 0x0f;
+ const uint32_t mult = MULTIPLIER(a);
+ const uint8_t r = multiply(dither_hi(rg), mult);
+ const uint8_t g = multiply(dither_lo(rg), mult);
+ const uint8_t b = multiply(dither_hi(ba), mult);
+ rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
+ rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
+ }
+ rgba4444 += stride;
+ }
+}
+#undef MULTIPLIER
+
+static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
+ int w, int h, int stride) {
+#ifdef WEBP_SWAP_16BIT_CSP
+ ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
+#else
+ ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
+#endif
+}
+
+static int ExtractAlpha(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
+ uint8_t alpha_mask = 0xff;
+ int i, j;
+
+ for (j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ const uint8_t alpha_value = argb[4 * i];
+ alpha[i] = alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ argb += argb_stride;
+ alpha += alpha_stride;
+ }
+ return (alpha_mask == 0xff);
+}
+
+void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
+void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
+int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
+
+//------------------------------------------------------------------------------
+// Init function
+
+extern void WebPInitAlphaProcessingSSE2(void);
+
+static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
+ (VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
+
+void WebPInitAlphaProcessing(void) {
+ if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPMultARGBRow = MultARGBRow;
+ WebPMultRow = MultRow;
+ WebPApplyAlphaMultiply = ApplyAlphaMultiply;
+ WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
+ WebPExtractAlpha = ExtractAlpha;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitAlphaProcessingSSE2();
+ }
+#endif
+ }
+ alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c b/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c
new file mode 100644
index 0000000..3d0a9b5
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/alpha_processing_sse2.c
@@ -0,0 +1,77 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <emmintrin.h>
+
+//------------------------------------------------------------------------------
+
+static int ExtractAlpha(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
+ // alpha_and stores an 'and' operation of all the alpha[] values. The final
+ // value is not 0xff if any of the alpha[] is not equal to 0xff.
+ uint32_t alpha_and = 0xff;
+ int i, j;
+ const __m128i a_mask = _mm_set1_epi32(0xffu); // to preserve alpha
+ const __m128i all_0xff = _mm_set_epi32(0, 0, ~0u, ~0u);
+ __m128i all_alphas = all_0xff;
+
+ // We must be able to access 3 extra bytes after the last written byte
+ // 'src[4 * width - 4]', because we don't know if alpha is the first or the
+ // last byte of the quadruplet.
+ const int limit = (width - 1) & ~7;
+
+ for (j = 0; j < height; ++j) {
+ const __m128i* src = (const __m128i*)argb;
+ for (i = 0; i < limit; i += 8) {
+ // load 32 argb bytes
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i b0 = _mm_and_si128(a0, a_mask);
+ const __m128i b1 = _mm_and_si128(a1, a_mask);
+ const __m128i c0 = _mm_packs_epi32(b0, b1);
+ const __m128i d0 = _mm_packus_epi16(c0, c0);
+ // store
+ _mm_storel_epi64((__m128i*)&alpha[i], d0);
+ // accumulate eight alpha 'and' in parallel
+ all_alphas = _mm_and_si128(all_alphas, d0);
+ src += 2;
+ }
+ for (; i < width; ++i) {
+ const uint32_t alpha_value = argb[4 * i];
+ alpha[i] = alpha_value;
+ alpha_and &= alpha_value;
+ }
+ argb += argb_stride;
+ alpha += alpha_stride;
+ }
+ // Combine the eight alpha 'and' into a 8-bit mask.
+ alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff));
+ return (alpha_and == 0xff);
+}
+
+#endif // WEBP_USE_SSE2
+
+//------------------------------------------------------------------------------
+// Init function
+
+extern void WebPInitAlphaProcessingSSE2(void);
+
+void WebPInitAlphaProcessingSSE2(void) {
+#if defined(WEBP_USE_SSE2)
+ WebPExtractAlpha = ExtractAlpha;
+#endif
+}
diff --git a/src/3rdparty/libwebp/src/dsp/cpu.c b/src/3rdparty/libwebp/src/dsp/cpu.c
index 7a1f417..ef04a75 100644
--- a/src/3rdparty/libwebp/src/dsp/cpu.c
+++ b/src/3rdparty/libwebp/src/dsp/cpu.c
@@ -29,19 +29,54 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ : "a"(info_type), "c"(0));
}
#elif defined(__i386__) || defined(__x86_64__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ : "a"(info_type), "c"(0));
}
+#elif (defined(_M_X64) || defined(_M_IX86)) && \
+ defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1
+#include <intrin.h>
+#define GetCPUInfo(info, type) __cpuidex(info, type, 0) // set ecx=0
#elif defined(WEBP_MSC_SSE2)
#define GetCPUInfo __cpuid
#endif
+// NaCl has no support for xgetbv or the raw opcode.
+#if !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__))
+static WEBP_INLINE uint64_t xgetbv(void) {
+ const uint32_t ecx = 0;
+ uint32_t eax, edx;
+ // Use the raw opcode for xgetbv for compatibility with older toolchains.
+ __asm__ volatile (
+ ".byte 0x0f, 0x01, 0xd0\n"
+ : "=a"(eax), "=d"(edx) : "c" (ecx));
+ return ((uint64_t)edx << 32) | eax;
+}
+#elif (defined(_M_X64) || defined(_M_IX86)) && \
+ defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219 // >= VS2010 SP1
+#include <immintrin.h>
+#define xgetbv() _xgetbv(0)
+#elif defined(_MSC_VER) && defined(_M_IX86)
+static WEBP_INLINE uint64_t xgetbv(void) {
+ uint32_t eax_, edx_;
+ __asm {
+ xor ecx, ecx // ecx = 0
+ // Use the raw opcode for xgetbv for compatibility with older toolchains.
+ __asm _emit 0x0f __asm _emit 0x01 __asm _emit 0xd0
+ mov eax_, eax
+ mov edx_, edx
+ }
+ return ((uint64_t)edx_ << 32) | eax_;
+}
+#else
+#define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains.
+#endif
+
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
static int x86CPUInfo(CPUFeature feature) {
int cpu_info[4];
@@ -52,10 +87,23 @@ static int x86CPUInfo(CPUFeature feature) {
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
+ if (feature == kAVX) {
+ // bits 27 (OSXSAVE) & 28 (256-bit AVX)
+ if ((cpu_info[2] & 0x18000000) == 0x18000000) {
+ // XMM state and YMM state enabled by the OS.
+ return (xgetbv() & 0x6) == 0x6;
+ }
+ }
+ if (feature == kAVX2) {
+ if (x86CPUInfo(kAVX)) {
+ GetCPUInfo(cpu_info, 7);
+ return ((cpu_info[1] & 0x00000020) == 0x00000020);
+ }
+ }
return 0;
}
VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
-#elif defined(WEBP_ANDROID_NEON)
+#elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test.
static int AndroidCPUInfo(CPUFeature feature) {
const AndroidCpuFamily cpu_family = android_getCpuFamily();
const uint64_t cpu_features = android_getCpuFeatures();
@@ -66,7 +114,7 @@ static int AndroidCPUInfo(CPUFeature feature) {
return 0;
}
VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
-#elif defined(__ARM_NEON__)
+#elif defined(WEBP_USE_NEON)
// define a dummy function to enable turning off NEON at runtime by setting
// VP8DecGetCPUInfo = NULL
static int armCPUInfo(CPUFeature feature) {
@@ -74,6 +122,12 @@ static int armCPUInfo(CPUFeature feature) {
return 1;
}
VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
+#elif defined(WEBP_USE_MIPS32)
+static int mipsCPUInfo(CPUFeature feature) {
+ (void)feature;
+ return 1;
+}
+VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo;
#else
VP8CPUInfo VP8GetCPUInfo = NULL;
#endif
diff --git a/src/3rdparty/libwebp/src/dsp/dec.c b/src/3rdparty/libwebp/src/dsp/dec.c
index 8b246fa..3a8dc81 100644
--- a/src/3rdparty/libwebp/src/dsp/dec.c
+++ b/src/3rdparty/libwebp/src/dsp/dec.c
@@ -15,37 +15,6 @@
#include "../dec/vp8i.h"
//------------------------------------------------------------------------------
-// run-time tables (~4k)
-
-static uint8_t abs0[255 + 255 + 1]; // abs(i)
-static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
-static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
-static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
-static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
-
-// We declare this variable 'volatile' to prevent instruction reordering
-// and make sure it's set to true _last_ (so as to be thread-safe)
-static volatile int tables_ok = 0;
-
-static void DspInitTables(void) {
- if (!tables_ok) {
- int i;
- for (i = -255; i <= 255; ++i) {
- abs0[255 + i] = (i < 0) ? -i : i;
- abs1[255 + i] = abs0[255 + i] >> 1;
- }
- for (i = -1020; i <= 1020; ++i) {
- sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
- }
- for (i = -112; i <= 112; ++i) {
- sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
- }
- for (i = -255; i <= 255 + 255; ++i) {
- clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
- }
- tables_ok = 1;
- }
-}
static WEBP_INLINE uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
@@ -146,10 +115,10 @@ static void TransformDC(const int16_t *in, uint8_t* dst) {
}
static void TransformDCUV(const int16_t* in, uint8_t* dst) {
- if (in[0 * 16]) TransformDC(in + 0 * 16, dst);
- if (in[1 * 16]) TransformDC(in + 1 * 16, dst + 4);
- if (in[2 * 16]) TransformDC(in + 2 * 16, dst + 4 * BPS);
- if (in[3 * 16]) TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
+ if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst);
+ if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4);
+ if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS);
+ if (in[3 * 16]) VP8TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
}
#undef STORE
@@ -184,7 +153,7 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
}
}
-void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
+void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
//------------------------------------------------------------------------------
// Intra predictions
@@ -193,7 +162,7 @@ void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) {
const uint8_t* top = dst - BPS;
- const uint8_t* const clip0 = clip1 + 255 - top[-1];
+ const uint8_t* const clip0 = VP8kclip1 - top[-1];
int y;
for (y = 0; y < size; ++y) {
const uint8_t* const clip = clip0 + dst[-1];
@@ -448,14 +417,9 @@ static void HE8uv(uint8_t *dst) { // horizontal
// helper for chroma-DC predictions
static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) {
int j;
-#ifndef WEBP_REFERENCE_IMPLEMENTATION
- const uint64_t v = (uint64_t)value * 0x0101010101010101ULL;
for (j = 0; j < 8; ++j) {
- *(uint64_t*)(dst + j * BPS) = v;
+ memset(dst + j * BPS, value, 8);
}
-#else
- for (j = 0; j < 8; ++j) memset(dst + j * BPS, value, 8);
-#endif
}
static void DC8uv(uint8_t *dst) { // DC
@@ -512,61 +476,62 @@ const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
// 4 pixels in, 2 pixels out
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
- p[-step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
+ const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
+ const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ p[-step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
}
// 4 pixels in, 4 pixels out
static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0);
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
const int a3 = (a1 + 1) >> 1;
- p[-2*step] = clip1[255 + p1 + a3];
- p[- step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
- p[ step] = clip1[255 + q1 - a3];
+ p[-2*step] = VP8kclip1[p1 + a3];
+ p[- step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a3];
}
// 6 pixels in, 6 pixels out
static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
- const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]];
+ const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
+ // a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9]
const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
- p[-3*step] = clip1[255 + p2 + a3];
- p[-2*step] = clip1[255 + p1 + a2];
- p[- step] = clip1[255 + p0 + a1];
- p[ 0] = clip1[255 + q0 - a1];
- p[ step] = clip1[255 + q1 - a2];
- p[ 2*step] = clip1[255 + q2 - a3];
+ p[-3*step] = VP8kclip1[p2 + a3];
+ p[-2*step] = VP8kclip1[p1 + a2];
+ p[- step] = VP8kclip1[p0 + a1];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a2];
+ p[ 2*step] = VP8kclip1[q2 - a3];
}
static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
+ return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh);
}
-static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t);
}
static WEBP_INLINE int needs_filter2(const uint8_t* p,
int step, int t, int it) {
- const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
- const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
- if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
- return 0;
- return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
- abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
- abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+ const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step];
+ const int p0 = p[-step], q0 = p[0];
+ const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
+ if ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) > t) return 0;
+ return VP8kabs0[p3 - p2] <= it && VP8kabs0[p2 - p1] <= it &&
+ VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it &&
+ VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it;
}
//------------------------------------------------------------------------------
@@ -574,8 +539,9 @@ static WEBP_INLINE int needs_filter2(const uint8_t* p,
static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
int i;
+ const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i, stride, thresh)) {
+ if (needs_filter(p + i, stride, thresh2)) {
do_filter2(p + i, stride);
}
}
@@ -583,8 +549,9 @@ static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
int i;
+ const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i * stride, 1, thresh)) {
+ if (needs_filter(p + i * stride, 1, thresh2)) {
do_filter2(p + i * stride, 1);
}
}
@@ -612,8 +579,9 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
static WEBP_INLINE void FilterLoop26(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
do_filter2(p, hstride);
} else {
@@ -627,8 +595,9 @@ static WEBP_INLINE void FilterLoop26(uint8_t* p,
static WEBP_INLINE void FilterLoop24(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
do_filter2(p, hstride);
} else {
@@ -717,10 +686,17 @@ VP8SimpleFilterFunc VP8SimpleHFilter16i;
extern void VP8DspInitSSE2(void);
extern void VP8DspInitNEON(void);
+extern void VP8DspInitMIPS32(void);
+
+static volatile VP8CPUInfo dec_last_cpuinfo_used =
+ (VP8CPUInfo)&dec_last_cpuinfo_used;
void VP8DspInit(void) {
- DspInitTables();
+ if (dec_last_cpuinfo_used == VP8GetCPUInfo) return;
+ VP8InitClipTables();
+
+ VP8TransformWHT = TransformWHT;
VP8Transform = TransformTwo;
VP8TransformUV = TransformUV;
VP8TransformDC = TransformDC;
@@ -741,7 +717,7 @@ void VP8DspInit(void) {
VP8SimpleHFilter16i = SimpleHFilter16i;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo) {
+ if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8DspInitSSE2();
@@ -750,7 +726,11 @@ void VP8DspInit(void) {
if (VP8GetCPUInfo(kNEON)) {
VP8DspInitNEON();
}
+#elif defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8DspInitMIPS32();
+ }
#endif
}
+ dec_last_cpuinfo_used = VP8GetCPUInfo;
}
-
diff --git a/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c b/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c
new file mode 100644
index 0000000..eec5a6d
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/dec_clip_tables.c
@@ -0,0 +1,366 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Clipping tables for filtering
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#define USE_STATIC_TABLES // undefine to have run-time table initialization
+
+#ifdef USE_STATIC_TABLES
+
+static const uint8_t abs0[255 + 255 + 1] = {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
+ 0xf3, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
+ 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xdf, 0xde, 0xdd, 0xdc,
+ 0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 0xc7, 0xc6, 0xc5, 0xc4,
+ 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad, 0xac,
+ 0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
+ 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94,
+ 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
+ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c,
+ 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
+ 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
+ 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c,
+ 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
+ 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c,
+ 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+ 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
+ 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
+ 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+ 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
+ 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static const int8_t sclip1[1020 + 1020 + 1] = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
+};
+
+static const int8_t sclip2[112 + 112 + 1] = {
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
+ 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f
+};
+
+static const uint8_t clip1[255 + 511 + 1] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+ 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
+ 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
+ 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+ 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
+ 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+#else
+
+// uninitialized tables
+static uint8_t abs0[255 + 255 + 1];
+static int8_t sclip1[1020 + 1020 + 1];
+static int8_t sclip2[112 + 112 + 1];
+static uint8_t clip1[255 + 511 + 1];
+
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
+
+#endif
+
+const int8_t* const VP8ksclip1 = &sclip1[1020];
+const int8_t* const VP8ksclip2 = &sclip2[112];
+const uint8_t* const VP8kclip1 = &clip1[255];
+const uint8_t* const VP8kabs0 = &abs0[255];
+
+void VP8InitClipTables(void) {
+#if !defined(USE_STATIC_TABLES)
+ int i;
+ if (!tables_ok) {
+ for (i = -255; i <= 255; ++i) {
+ abs0[255 + i] = (i < 0) ? -i : i;
+ }
+ for (i = -1020; i <= 1020; ++i) {
+ sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
+ }
+ for (i = -112; i <= 112; ++i) {
+ sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
+ }
+ for (i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+#endif // USE_STATIC_TABLES
+}
diff --git a/src/3rdparty/libwebp/src/dsp/dec_mips32.c b/src/3rdparty/libwebp/src/dsp/dec_mips32.c
new file mode 100644
index 0000000..3e89ed3
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/dec_mips32.c
@@ -0,0 +1,578 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of dsp functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+static WEBP_INLINE int abs_mips32(int x) {
+ const int sign = x >> 31;
+ return (x ^ sign) - sign;
+}
+
+// 4 pixels in, 2 pixels out
+static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1];
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ p[-step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+}
+
+// 4 pixels in, 4 pixels out
+static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0);
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ const int a3 = (a1 + 1) >> 1;
+ p[-2 * step] = VP8kclip1[p1 + a3];
+ p[- step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a3];
+}
+
+// 6 pixels in, 6 pixels out
+static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
+ const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2 * step];
+ const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
+ const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
+ const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
+ const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
+ p[-3 * step] = VP8kclip1[p2 + a3];
+ p[-2 * step] = VP8kclip1[p1 + a2];
+ p[- step] = VP8kclip1[p0 + a1];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a2];
+ p[ 2 * step] = VP8kclip1[q2 - a3];
+}
+
+static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (abs_mips32(p1 - p0) > thresh) || (abs_mips32(q1 - q0) > thresh);
+}
+
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return ((2 * abs_mips32(p0 - q0) + (abs_mips32(p1 - q1) >> 1)) <= thresh);
+}
+
+static WEBP_INLINE int needs_filter2(const uint8_t* p,
+ int step, int t, int it) {
+ const int p3 = p[-4 * step], p2 = p[-3 * step];
+ const int p1 = p[-2 * step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
+ if ((2 * abs_mips32(p0 - q0) + (abs_mips32(p1 - q1) >> 1)) > t) {
+ return 0;
+ }
+ return abs_mips32(p3 - p2) <= it && abs_mips32(p2 - p1) <= it &&
+ abs_mips32(p1 - p0) <= it && abs_mips32(q3 - q2) <= it &&
+ abs_mips32(q2 - q1) <= it && abs_mips32(q1 - q0) <= it;
+}
+
+static WEBP_INLINE void FilterLoop26(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter6(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+static WEBP_INLINE void FilterLoop24(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter4(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+// on macroblock edges
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i, stride, thresh)) {
+ do_filter2(p + i, stride);
+ }
+ }
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i * stride, 1, thresh)) {
+ do_filter2(p + i * stride, 1);
+ }
+ }
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14;
+ int temp15, temp16, temp17, temp18;
+ int16_t* p_in = (int16_t*)in;
+
+ // loops unrolled and merged to avoid usage of tmp buffer
+ // and to reduce number of stalls. MUL macro is written
+ // in assembler and inlined
+ __asm__ volatile(
+ "lh %[temp0], 0(%[in]) \n\t"
+ "lh %[temp8], 16(%[in]) \n\t"
+ "lh %[temp4], 8(%[in]) \n\t"
+ "lh %[temp12], 24(%[in]) \n\t"
+ "addu %[temp16], %[temp0], %[temp8] \n\t"
+ "subu %[temp0], %[temp0], %[temp8] \n\t"
+ "mul %[temp8], %[temp4], %[kC2] \n\t"
+ "mul %[temp17], %[temp12], %[kC1] \n\t"
+ "mul %[temp4], %[temp4], %[kC1] \n\t"
+ "mul %[temp12], %[temp12], %[kC2] \n\t"
+ "lh %[temp1], 2(%[in]) \n\t"
+ "lh %[temp5], 10(%[in]) \n\t"
+ "lh %[temp9], 18(%[in]) \n\t"
+ "lh %[temp13], 26(%[in]) \n\t"
+ "sra %[temp8], %[temp8], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp4], %[temp4], 16 \n\t"
+ "sra %[temp12], %[temp12], 16 \n\t"
+ "lh %[temp2], 4(%[in]) \n\t"
+ "lh %[temp6], 12(%[in]) \n\t"
+ "lh %[temp10], 20(%[in]) \n\t"
+ "lh %[temp14], 28(%[in]) \n\t"
+ "subu %[temp17], %[temp8], %[temp17] \n\t"
+ "addu %[temp4], %[temp4], %[temp12] \n\t"
+ "addu %[temp8], %[temp16], %[temp4] \n\t"
+ "subu %[temp4], %[temp16], %[temp4] \n\t"
+ "addu %[temp16], %[temp1], %[temp9] \n\t"
+ "subu %[temp1], %[temp1], %[temp9] \n\t"
+ "lh %[temp3], 6(%[in]) \n\t"
+ "lh %[temp7], 14(%[in]) \n\t"
+ "lh %[temp11], 22(%[in]) \n\t"
+ "lh %[temp15], 30(%[in]) \n\t"
+ "addu %[temp12], %[temp0], %[temp17] \n\t"
+ "subu %[temp0], %[temp0], %[temp17] \n\t"
+ "mul %[temp9], %[temp5], %[kC2] \n\t"
+ "mul %[temp17], %[temp13], %[kC1] \n\t"
+ "mul %[temp5], %[temp5], %[kC1] \n\t"
+ "mul %[temp13], %[temp13], %[kC2] \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "subu %[temp17], %[temp9], %[temp17] \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "addu %[temp5], %[temp5], %[temp13] \n\t"
+ "addu %[temp13], %[temp1], %[temp17] \n\t"
+ "subu %[temp1], %[temp1], %[temp17] \n\t"
+ "mul %[temp17], %[temp14], %[kC1] \n\t"
+ "mul %[temp14], %[temp14], %[kC2] \n\t"
+ "addu %[temp9], %[temp16], %[temp5] \n\t"
+ "subu %[temp5], %[temp16], %[temp5] \n\t"
+ "addu %[temp16], %[temp2], %[temp10] \n\t"
+ "subu %[temp2], %[temp2], %[temp10] \n\t"
+ "mul %[temp10], %[temp6], %[kC2] \n\t"
+ "mul %[temp6], %[temp6], %[kC1] \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp14], %[temp14], 16 \n\t"
+ "sra %[temp10], %[temp10], 16 \n\t"
+ "sra %[temp6], %[temp6], 16 \n\t"
+ "subu %[temp17], %[temp10], %[temp17] \n\t"
+ "addu %[temp6], %[temp6], %[temp14] \n\t"
+ "addu %[temp10], %[temp16], %[temp6] \n\t"
+ "subu %[temp6], %[temp16], %[temp6] \n\t"
+ "addu %[temp14], %[temp2], %[temp17] \n\t"
+ "subu %[temp2], %[temp2], %[temp17] \n\t"
+ "mul %[temp17], %[temp15], %[kC1] \n\t"
+ "mul %[temp15], %[temp15], %[kC2] \n\t"
+ "addu %[temp16], %[temp3], %[temp11] \n\t"
+ "subu %[temp3], %[temp3], %[temp11] \n\t"
+ "mul %[temp11], %[temp7], %[kC2] \n\t"
+ "mul %[temp7], %[temp7], %[kC1] \n\t"
+ "addiu %[temp8], %[temp8], 4 \n\t"
+ "addiu %[temp12], %[temp12], 4 \n\t"
+ "addiu %[temp0], %[temp0], 4 \n\t"
+ "addiu %[temp4], %[temp4], 4 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp15], %[temp15], 16 \n\t"
+ "sra %[temp11], %[temp11], 16 \n\t"
+ "sra %[temp7], %[temp7], 16 \n\t"
+ "subu %[temp17], %[temp11], %[temp17] \n\t"
+ "addu %[temp7], %[temp7], %[temp15] \n\t"
+ "addu %[temp15], %[temp3], %[temp17] \n\t"
+ "subu %[temp3], %[temp3], %[temp17] \n\t"
+ "addu %[temp11], %[temp16], %[temp7] \n\t"
+ "subu %[temp7], %[temp16], %[temp7] \n\t"
+ "addu %[temp16], %[temp8], %[temp10] \n\t"
+ "subu %[temp8], %[temp8], %[temp10] \n\t"
+ "mul %[temp10], %[temp9], %[kC2] \n\t"
+ "mul %[temp17], %[temp11], %[kC1] \n\t"
+ "mul %[temp9], %[temp9], %[kC1] \n\t"
+ "mul %[temp11], %[temp11], %[kC2] \n\t"
+ "sra %[temp10], %[temp10], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp11], %[temp11], 16 \n\t"
+ "subu %[temp17], %[temp10], %[temp17] \n\t"
+ "addu %[temp11], %[temp9], %[temp11] \n\t"
+ "addu %[temp10], %[temp12], %[temp14] \n\t"
+ "subu %[temp12], %[temp12], %[temp14] \n\t"
+ "mul %[temp14], %[temp13], %[kC2] \n\t"
+ "mul %[temp9], %[temp15], %[kC1] \n\t"
+ "mul %[temp13], %[temp13], %[kC1] \n\t"
+ "mul %[temp15], %[temp15], %[kC2] \n\t"
+ "sra %[temp14], %[temp14], 16 \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "sra %[temp15], %[temp15], 16 \n\t"
+ "subu %[temp9], %[temp14], %[temp9] \n\t"
+ "addu %[temp15], %[temp13], %[temp15] \n\t"
+ "addu %[temp14], %[temp0], %[temp2] \n\t"
+ "subu %[temp0], %[temp0], %[temp2] \n\t"
+ "mul %[temp2], %[temp1], %[kC2] \n\t"
+ "mul %[temp13], %[temp3], %[kC1] \n\t"
+ "mul %[temp1], %[temp1], %[kC1] \n\t"
+ "mul %[temp3], %[temp3], %[kC2] \n\t"
+ "sra %[temp2], %[temp2], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "sra %[temp1], %[temp1], 16 \n\t"
+ "sra %[temp3], %[temp3], 16 \n\t"
+ "subu %[temp13], %[temp2], %[temp13] \n\t"
+ "addu %[temp3], %[temp1], %[temp3] \n\t"
+ "addu %[temp2], %[temp4], %[temp6] \n\t"
+ "subu %[temp4], %[temp4], %[temp6] \n\t"
+ "mul %[temp6], %[temp5], %[kC2] \n\t"
+ "mul %[temp1], %[temp7], %[kC1] \n\t"
+ "mul %[temp5], %[temp5], %[kC1] \n\t"
+ "mul %[temp7], %[temp7], %[kC2] \n\t"
+ "sra %[temp6], %[temp6], 16 \n\t"
+ "sra %[temp1], %[temp1], 16 \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "sra %[temp7], %[temp7], 16 \n\t"
+ "subu %[temp1], %[temp6], %[temp1] \n\t"
+ "addu %[temp7], %[temp5], %[temp7] \n\t"
+ "addu %[temp5], %[temp16], %[temp11] \n\t"
+ "subu %[temp16], %[temp16], %[temp11] \n\t"
+ "addu %[temp11], %[temp8], %[temp17] \n\t"
+ "subu %[temp8], %[temp8], %[temp17] \n\t"
+ "sra %[temp5], %[temp5], 3 \n\t"
+ "sra %[temp16], %[temp16], 3 \n\t"
+ "sra %[temp11], %[temp11], 3 \n\t"
+ "sra %[temp8], %[temp8], 3 \n\t"
+ "addu %[temp17], %[temp10], %[temp15] \n\t"
+ "subu %[temp10], %[temp10], %[temp15] \n\t"
+ "addu %[temp15], %[temp12], %[temp9] \n\t"
+ "subu %[temp12], %[temp12], %[temp9] \n\t"
+ "sra %[temp17], %[temp17], 3 \n\t"
+ "sra %[temp10], %[temp10], 3 \n\t"
+ "sra %[temp15], %[temp15], 3 \n\t"
+ "sra %[temp12], %[temp12], 3 \n\t"
+ "addu %[temp9], %[temp14], %[temp3] \n\t"
+ "subu %[temp14], %[temp14], %[temp3] \n\t"
+ "addu %[temp3], %[temp0], %[temp13] \n\t"
+ "subu %[temp0], %[temp0], %[temp13] \n\t"
+ "sra %[temp9], %[temp9], 3 \n\t"
+ "sra %[temp14], %[temp14], 3 \n\t"
+ "sra %[temp3], %[temp3], 3 \n\t"
+ "sra %[temp0], %[temp0], 3 \n\t"
+ "addu %[temp13], %[temp2], %[temp7] \n\t"
+ "subu %[temp2], %[temp2], %[temp7] \n\t"
+ "addu %[temp7], %[temp4], %[temp1] \n\t"
+ "subu %[temp4], %[temp4], %[temp1] \n\t"
+ "sra %[temp13], %[temp13], 3 \n\t"
+ "sra %[temp2], %[temp2], 3 \n\t"
+ "sra %[temp7], %[temp7], 3 \n\t"
+ "sra %[temp4], %[temp4], 3 \n\t"
+ "addiu %[temp6], $zero, 255 \n\t"
+ "lbu %[temp1], 0(%[dst]) \n\t"
+ "addu %[temp1], %[temp1], %[temp5] \n\t"
+ "sra %[temp5], %[temp1], 8 \n\t"
+ "sra %[temp18], %[temp1], 31 \n\t"
+ "beqz %[temp5], 1f \n\t"
+ "xor %[temp1], %[temp1], %[temp1] \n\t"
+ "movz %[temp1], %[temp6], %[temp18] \n\t"
+ "1: \n\t"
+ "lbu %[temp18], 1(%[dst]) \n\t"
+ "sb %[temp1], 0(%[dst]) \n\t"
+ "addu %[temp18], %[temp18], %[temp11] \n\t"
+ "sra %[temp11], %[temp18], 8 \n\t"
+ "sra %[temp1], %[temp18], 31 \n\t"
+ "beqz %[temp11], 2f \n\t"
+ "xor %[temp18], %[temp18], %[temp18] \n\t"
+ "movz %[temp18], %[temp6], %[temp1] \n\t"
+ "2: \n\t"
+ "lbu %[temp1], 2(%[dst]) \n\t"
+ "sb %[temp18], 1(%[dst]) \n\t"
+ "addu %[temp1], %[temp1], %[temp8] \n\t"
+ "sra %[temp8], %[temp1], 8 \n\t"
+ "sra %[temp18], %[temp1], 31 \n\t"
+ "beqz %[temp8], 3f \n\t"
+ "xor %[temp1], %[temp1], %[temp1] \n\t"
+ "movz %[temp1], %[temp6], %[temp18] \n\t"
+ "3: \n\t"
+ "lbu %[temp18], 3(%[dst]) \n\t"
+ "sb %[temp1], 2(%[dst]) \n\t"
+ "addu %[temp18], %[temp18], %[temp16] \n\t"
+ "sra %[temp16], %[temp18], 8 \n\t"
+ "sra %[temp1], %[temp18], 31 \n\t"
+ "beqz %[temp16], 4f \n\t"
+ "xor %[temp18], %[temp18], %[temp18] \n\t"
+ "movz %[temp18], %[temp6], %[temp1] \n\t"
+ "4: \n\t"
+ "sb %[temp18], 3(%[dst]) \n\t"
+ "lbu %[temp5], 32(%[dst]) \n\t"
+ "lbu %[temp8], 33(%[dst]) \n\t"
+ "lbu %[temp11], 34(%[dst]) \n\t"
+ "lbu %[temp16], 35(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp17] \n\t"
+ "addu %[temp8], %[temp8], %[temp15] \n\t"
+ "addu %[temp11], %[temp11], %[temp12] \n\t"
+ "addu %[temp16], %[temp16], %[temp10] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "beqz %[temp18], 5f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "5: \n\t"
+ "sra %[temp18], %[temp8], 8 \n\t"
+ "sra %[temp1], %[temp8], 31 \n\t"
+ "beqz %[temp18], 6f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp1] \n\t"
+ "6: \n\t"
+ "sra %[temp18], %[temp11], 8 \n\t"
+ "sra %[temp1], %[temp11], 31 \n\t"
+ "sra %[temp17], %[temp16], 8 \n\t"
+ "sra %[temp15], %[temp16], 31 \n\t"
+ "beqz %[temp18], 7f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp1] \n\t"
+ "7: \n\t"
+ "beqz %[temp17], 8f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp15] \n\t"
+ "8: \n\t"
+ "sb %[temp5], 32(%[dst]) \n\t"
+ "sb %[temp8], 33(%[dst]) \n\t"
+ "sb %[temp11], 34(%[dst]) \n\t"
+ "sb %[temp16], 35(%[dst]) \n\t"
+ "lbu %[temp5], 64(%[dst]) \n\t"
+ "lbu %[temp8], 65(%[dst]) \n\t"
+ "lbu %[temp11], 66(%[dst]) \n\t"
+ "lbu %[temp16], 67(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp9] \n\t"
+ "addu %[temp8], %[temp8], %[temp3] \n\t"
+ "addu %[temp11], %[temp11], %[temp0] \n\t"
+ "addu %[temp16], %[temp16], %[temp14] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "sra %[temp17], %[temp8], 8 \n\t"
+ "sra %[temp15], %[temp8], 31 \n\t"
+ "sra %[temp12], %[temp11], 8 \n\t"
+ "sra %[temp10], %[temp11], 31 \n\t"
+ "sra %[temp9], %[temp16], 8 \n\t"
+ "sra %[temp3], %[temp16], 31 \n\t"
+ "beqz %[temp18], 9f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "9: \n\t"
+ "beqz %[temp17], 10f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp15] \n\t"
+ "10: \n\t"
+ "beqz %[temp12], 11f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp10] \n\t"
+ "11: \n\t"
+ "beqz %[temp9], 12f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp3] \n\t"
+ "12: \n\t"
+ "sb %[temp5], 64(%[dst]) \n\t"
+ "sb %[temp8], 65(%[dst]) \n\t"
+ "sb %[temp11], 66(%[dst]) \n\t"
+ "sb %[temp16], 67(%[dst]) \n\t"
+ "lbu %[temp5], 96(%[dst]) \n\t"
+ "lbu %[temp8], 97(%[dst]) \n\t"
+ "lbu %[temp11], 98(%[dst]) \n\t"
+ "lbu %[temp16], 99(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp13] \n\t"
+ "addu %[temp8], %[temp8], %[temp7] \n\t"
+ "addu %[temp11], %[temp11], %[temp4] \n\t"
+ "addu %[temp16], %[temp16], %[temp2] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "sra %[temp17], %[temp8], 8 \n\t"
+ "sra %[temp15], %[temp8], 31 \n\t"
+ "sra %[temp12], %[temp11], 8 \n\t"
+ "sra %[temp10], %[temp11], 31 \n\t"
+ "sra %[temp9], %[temp16], 8 \n\t"
+ "sra %[temp3], %[temp16], 31 \n\t"
+ "beqz %[temp18], 13f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "13: \n\t"
+ "beqz %[temp17], 14f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp15] \n\t"
+ "14: \n\t"
+ "beqz %[temp12], 15f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp10] \n\t"
+ "15: \n\t"
+ "beqz %[temp9], 16f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp3] \n\t"
+ "16: \n\t"
+ "sb %[temp5], 96(%[dst]) \n\t"
+ "sb %[temp8], 97(%[dst]) \n\t"
+ "sb %[temp11], 98(%[dst]) \n\t"
+ "sb %[temp16], 99(%[dst]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18)
+ : [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne(in, dst);
+ if (do_two) {
+ TransformOne(in + 16, dst + 4);
+ }
+}
+
+#endif // WEBP_USE_MIPS32
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitMIPS32(void);
+
+void VP8DspInitMIPS32(void) {
+#if defined(WEBP_USE_MIPS32)
+ VP8InitClipTables();
+
+ VP8Transform = TransformTwo;
+
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+#endif // WEBP_USE_MIPS32
+}
diff --git a/src/3rdparty/libwebp/src/dsp/dec_neon.c b/src/3rdparty/libwebp/src/dsp/dec_neon.c
index 9c3d8cc..9c5bc1c 100644
--- a/src/3rdparty/libwebp/src/dsp/dec_neon.c
+++ b/src/3rdparty/libwebp/src/dsp/dec_neon.c
@@ -16,8 +16,521 @@
#if defined(WEBP_USE_NEON)
+#include "./neon.h"
#include "../dec/vp8i.h"
+//------------------------------------------------------------------------------
+// NxM Loading functions
+
+// Load/Store vertical edge
+#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
+ "vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
+
+#define STORE8x2(c1, c2, p, stride) \
+ "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n"
+
+#if !defined(WORK_AROUND_GCC)
+
+// This intrinsics version makes gcc-4.6.3 crash during Load4x??() compilation
+// (register alloc, probably). The variants somewhat mitigate the problem, but
+// not quite. HFilter16i() remains problematic.
+static WEBP_INLINE uint8x8x4_t Load4x8(const uint8_t* const src, int stride) {
+ const uint8x8_t zero = vdup_n_u8(0);
+ uint8x8x4_t out;
+ INIT_VECTOR4(out, zero, zero, zero, zero);
+ out = vld4_lane_u8(src + 0 * stride, out, 0);
+ out = vld4_lane_u8(src + 1 * stride, out, 1);
+ out = vld4_lane_u8(src + 2 * stride, out, 2);
+ out = vld4_lane_u8(src + 3 * stride, out, 3);
+ out = vld4_lane_u8(src + 4 * stride, out, 4);
+ out = vld4_lane_u8(src + 5 * stride, out, 5);
+ out = vld4_lane_u8(src + 6 * stride, out, 6);
+ out = vld4_lane_u8(src + 7 * stride, out, 7);
+ return out;
+}
+
+static WEBP_INLINE void Load4x16(const uint8_t* const src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ // row0 = p1[0..7]|p0[0..7]|q0[0..7]|q1[0..7]
+ // row8 = p1[8..15]|p0[8..15]|q0[8..15]|q1[8..15]
+ const uint8x8x4_t row0 = Load4x8(src - 2 + 0 * stride, stride);
+ const uint8x8x4_t row8 = Load4x8(src - 2 + 8 * stride, stride);
+ *p1 = vcombine_u8(row0.val[0], row8.val[0]);
+ *p0 = vcombine_u8(row0.val[1], row8.val[1]);
+ *q0 = vcombine_u8(row0.val[2], row8.val[2]);
+ *q1 = vcombine_u8(row0.val[3], row8.val[3]);
+}
+
+#else // WORK_AROUND_GCC
+
+#define LOADQ_LANE_32b(VALUE, LANE) do { \
+ (VALUE) = vld1q_lane_u32((const uint32_t*)src, (VALUE), (LANE)); \
+ src += stride; \
+} while (0)
+
+static WEBP_INLINE void Load4x16(const uint8_t* src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ const uint32x4_t zero = vdupq_n_u32(0);
+ uint32x4x4_t in;
+ INIT_VECTOR4(in, zero, zero, zero, zero);
+ src -= 2;
+ LOADQ_LANE_32b(in.val[0], 0);
+ LOADQ_LANE_32b(in.val[1], 0);
+ LOADQ_LANE_32b(in.val[2], 0);
+ LOADQ_LANE_32b(in.val[3], 0);
+ LOADQ_LANE_32b(in.val[0], 1);
+ LOADQ_LANE_32b(in.val[1], 1);
+ LOADQ_LANE_32b(in.val[2], 1);
+ LOADQ_LANE_32b(in.val[3], 1);
+ LOADQ_LANE_32b(in.val[0], 2);
+ LOADQ_LANE_32b(in.val[1], 2);
+ LOADQ_LANE_32b(in.val[2], 2);
+ LOADQ_LANE_32b(in.val[3], 2);
+ LOADQ_LANE_32b(in.val[0], 3);
+ LOADQ_LANE_32b(in.val[1], 3);
+ LOADQ_LANE_32b(in.val[2], 3);
+ LOADQ_LANE_32b(in.val[3], 3);
+ // Transpose four 4x4 parts:
+ {
+ const uint8x16x2_t row01 = vtrnq_u8(vreinterpretq_u8_u32(in.val[0]),
+ vreinterpretq_u8_u32(in.val[1]));
+ const uint8x16x2_t row23 = vtrnq_u8(vreinterpretq_u8_u32(in.val[2]),
+ vreinterpretq_u8_u32(in.val[3]));
+ const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]),
+ vreinterpretq_u16_u8(row23.val[0]));
+ const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]),
+ vreinterpretq_u16_u8(row23.val[1]));
+ *p1 = vreinterpretq_u8_u16(row02.val[0]);
+ *p0 = vreinterpretq_u8_u16(row13.val[0]);
+ *q0 = vreinterpretq_u8_u16(row02.val[1]);
+ *q1 = vreinterpretq_u8_u16(row13.val[1]);
+ }
+}
+#undef LOADQ_LANE_32b
+
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Load8x16(const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load4x16(src - 2, stride, p3, p2, p1, p0);
+ Load4x16(src + 2, stride, q0, q1, q2, q3);
+}
+
+static WEBP_INLINE void Load16x4(const uint8_t* const src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ *p1 = vld1q_u8(src - 2 * stride);
+ *p0 = vld1q_u8(src - 1 * stride);
+ *q0 = vld1q_u8(src + 0 * stride);
+ *q1 = vld1q_u8(src + 1 * stride);
+}
+
+static WEBP_INLINE void Load16x8(const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load16x4(src - 2 * stride, stride, p3, p2, p1, p0);
+ Load16x4(src + 2 * stride, stride, q0, q1, q2, q3);
+}
+
+static WEBP_INLINE void Load8x8x2(const uint8_t* const u,
+ const uint8_t* const v,
+ int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
+ // and the v-samples on the higher half.
+ *p3 = vcombine_u8(vld1_u8(u - 4 * stride), vld1_u8(v - 4 * stride));
+ *p2 = vcombine_u8(vld1_u8(u - 3 * stride), vld1_u8(v - 3 * stride));
+ *p1 = vcombine_u8(vld1_u8(u - 2 * stride), vld1_u8(v - 2 * stride));
+ *p0 = vcombine_u8(vld1_u8(u - 1 * stride), vld1_u8(v - 1 * stride));
+ *q0 = vcombine_u8(vld1_u8(u + 0 * stride), vld1_u8(v + 0 * stride));
+ *q1 = vcombine_u8(vld1_u8(u + 1 * stride), vld1_u8(v + 1 * stride));
+ *q2 = vcombine_u8(vld1_u8(u + 2 * stride), vld1_u8(v + 2 * stride));
+ *q3 = vcombine_u8(vld1_u8(u + 3 * stride), vld1_u8(v + 3 * stride));
+}
+
+#if !defined(WORK_AROUND_GCC)
+
+#define LOAD_UV_8(ROW) \
+ vcombine_u8(vld1_u8(u - 4 + (ROW) * stride), vld1_u8(v - 4 + (ROW) * stride))
+
+static WEBP_INLINE void Load8x8x2T(const uint8_t* const u,
+ const uint8_t* const v,
+ int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
+ // and the v-samples on the higher half.
+ const uint8x16_t row0 = LOAD_UV_8(0);
+ const uint8x16_t row1 = LOAD_UV_8(1);
+ const uint8x16_t row2 = LOAD_UV_8(2);
+ const uint8x16_t row3 = LOAD_UV_8(3);
+ const uint8x16_t row4 = LOAD_UV_8(4);
+ const uint8x16_t row5 = LOAD_UV_8(5);
+ const uint8x16_t row6 = LOAD_UV_8(6);
+ const uint8x16_t row7 = LOAD_UV_8(7);
+ // Perform two side-by-side 8x8 transposes
+ // u00 u01 u02 u03 u04 u05 u06 u07 | v00 v01 v02 v03 v04 v05 v06 v07
+ // u10 u11 u12 u13 u14 u15 u16 u17 | v10 v11 v12 ...
+ // u20 u21 u22 u23 u24 u25 u26 u27 | v20 v21 ...
+ // u30 u31 u32 u33 u34 u35 u36 u37 | ...
+ // u40 u41 u42 u43 u44 u45 u46 u47 | ...
+ // u50 u51 u52 u53 u54 u55 u56 u57 | ...
+ // u60 u61 u62 u63 u64 u65 u66 u67 | v60 ...
+ // u70 u71 u72 u73 u74 u75 u76 u77 | v70 v71 v72 ...
+ const uint8x16x2_t row01 = vtrnq_u8(row0, row1); // u00 u10 u02 u12 ...
+ // u01 u11 u03 u13 ...
+ const uint8x16x2_t row23 = vtrnq_u8(row2, row3); // u20 u30 u22 u32 ...
+ // u21 u31 u23 u33 ...
+ const uint8x16x2_t row45 = vtrnq_u8(row4, row5); // ...
+ const uint8x16x2_t row67 = vtrnq_u8(row6, row7); // ...
+ const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]),
+ vreinterpretq_u16_u8(row23.val[0]));
+ const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]),
+ vreinterpretq_u16_u8(row23.val[1]));
+ const uint16x8x2_t row46 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[0]),
+ vreinterpretq_u16_u8(row67.val[0]));
+ const uint16x8x2_t row57 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[1]),
+ vreinterpretq_u16_u8(row67.val[1]));
+ const uint32x4x2_t row04 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[0]),
+ vreinterpretq_u32_u16(row46.val[0]));
+ const uint32x4x2_t row26 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[1]),
+ vreinterpretq_u32_u16(row46.val[1]));
+ const uint32x4x2_t row15 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[0]),
+ vreinterpretq_u32_u16(row57.val[0]));
+ const uint32x4x2_t row37 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[1]),
+ vreinterpretq_u32_u16(row57.val[1]));
+ *p3 = vreinterpretq_u8_u32(row04.val[0]);
+ *p2 = vreinterpretq_u8_u32(row15.val[0]);
+ *p1 = vreinterpretq_u8_u32(row26.val[0]);
+ *p0 = vreinterpretq_u8_u32(row37.val[0]);
+ *q0 = vreinterpretq_u8_u32(row04.val[1]);
+ *q1 = vreinterpretq_u8_u32(row15.val[1]);
+ *q2 = vreinterpretq_u8_u32(row26.val[1]);
+ *q3 = vreinterpretq_u8_u32(row37.val[1]);
+}
+#undef LOAD_UV_8
+
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Store2x8(const uint8x8x2_t v,
+ uint8_t* const dst, int stride) {
+ vst2_lane_u8(dst + 0 * stride, v, 0);
+ vst2_lane_u8(dst + 1 * stride, v, 1);
+ vst2_lane_u8(dst + 2 * stride, v, 2);
+ vst2_lane_u8(dst + 3 * stride, v, 3);
+ vst2_lane_u8(dst + 4 * stride, v, 4);
+ vst2_lane_u8(dst + 5 * stride, v, 5);
+ vst2_lane_u8(dst + 6 * stride, v, 6);
+ vst2_lane_u8(dst + 7 * stride, v, 7);
+}
+
+static WEBP_INLINE void Store2x16(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
+ uint8x8x2_t lo, hi;
+ lo.val[0] = vget_low_u8(p0);
+ lo.val[1] = vget_low_u8(q0);
+ hi.val[0] = vget_high_u8(p0);
+ hi.val[1] = vget_high_u8(q0);
+ Store2x8(lo, dst - 1 + 0 * stride, stride);
+ Store2x8(hi, dst - 1 + 8 * stride, stride);
+}
+
+#if !defined(WORK_AROUND_GCC)
+static WEBP_INLINE void Store4x8(const uint8x8x4_t v,
+ uint8_t* const dst, int stride) {
+ vst4_lane_u8(dst + 0 * stride, v, 0);
+ vst4_lane_u8(dst + 1 * stride, v, 1);
+ vst4_lane_u8(dst + 2 * stride, v, 2);
+ vst4_lane_u8(dst + 3 * stride, v, 3);
+ vst4_lane_u8(dst + 4 * stride, v, 4);
+ vst4_lane_u8(dst + 5 * stride, v, 5);
+ vst4_lane_u8(dst + 6 * stride, v, 6);
+ vst4_lane_u8(dst + 7 * stride, v, 7);
+}
+
+static WEBP_INLINE void Store4x16(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
+ uint8x8x4_t lo, hi;
+ INIT_VECTOR4(lo,
+ vget_low_u8(p1), vget_low_u8(p0),
+ vget_low_u8(q0), vget_low_u8(q1));
+ INIT_VECTOR4(hi,
+ vget_high_u8(p1), vget_high_u8(p0),
+ vget_high_u8(q0), vget_high_u8(q1));
+ Store4x8(lo, dst - 2 + 0 * stride, stride);
+ Store4x8(hi, dst - 2 + 8 * stride, stride);
+}
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Store16x2(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
+ vst1q_u8(dst - stride, p0);
+ vst1q_u8(dst, q0);
+}
+
+static WEBP_INLINE void Store16x4(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
+ Store16x2(p1, p0, dst - stride, stride);
+ Store16x2(q0, q1, dst + stride, stride);
+}
+
+static WEBP_INLINE void Store8x2x2(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ // p0 and q0 contain the u+v samples packed in low/high halves.
+ vst1_u8(u - stride, vget_low_u8(p0));
+ vst1_u8(u, vget_low_u8(q0));
+ vst1_u8(v - stride, vget_high_u8(p0));
+ vst1_u8(v, vget_high_u8(q0));
+}
+
+static WEBP_INLINE void Store8x4x2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ // The p1...q1 registers contain the u+v samples packed in low/high halves.
+ Store8x2x2(p1, p0, u - stride, v - stride, stride);
+ Store8x2x2(q0, q1, u + stride, v + stride, stride);
+}
+
+#if !defined(WORK_AROUND_GCC)
+
+#define STORE6_LANE(DST, VAL0, VAL1, LANE) do { \
+ vst3_lane_u8((DST) - 3, (VAL0), (LANE)); \
+ vst3_lane_u8((DST) + 0, (VAL1), (LANE)); \
+ (DST) += stride; \
+} while (0)
+
+static WEBP_INLINE void Store6x8x2(const uint8x16_t p2, const uint8x16_t p1,
+ const uint8x16_t p0, const uint8x16_t q0,
+ const uint8x16_t q1, const uint8x16_t q2,
+ uint8_t* u, uint8_t* v,
+ int stride) {
+ uint8x8x3_t u0, u1, v0, v1;
+ INIT_VECTOR3(u0, vget_low_u8(p2), vget_low_u8(p1), vget_low_u8(p0));
+ INIT_VECTOR3(u1, vget_low_u8(q0), vget_low_u8(q1), vget_low_u8(q2));
+ INIT_VECTOR3(v0, vget_high_u8(p2), vget_high_u8(p1), vget_high_u8(p0));
+ INIT_VECTOR3(v1, vget_high_u8(q0), vget_high_u8(q1), vget_high_u8(q2));
+ STORE6_LANE(u, u0, u1, 0);
+ STORE6_LANE(u, u0, u1, 1);
+ STORE6_LANE(u, u0, u1, 2);
+ STORE6_LANE(u, u0, u1, 3);
+ STORE6_LANE(u, u0, u1, 4);
+ STORE6_LANE(u, u0, u1, 5);
+ STORE6_LANE(u, u0, u1, 6);
+ STORE6_LANE(u, u0, u1, 7);
+ STORE6_LANE(v, v0, v1, 0);
+ STORE6_LANE(v, v0, v1, 1);
+ STORE6_LANE(v, v0, v1, 2);
+ STORE6_LANE(v, v0, v1, 3);
+ STORE6_LANE(v, v0, v1, 4);
+ STORE6_LANE(v, v0, v1, 5);
+ STORE6_LANE(v, v0, v1, 6);
+ STORE6_LANE(v, v0, v1, 7);
+}
+#undef STORE6_LANE
+
+static WEBP_INLINE void Store4x8x2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ uint8x8x4_t u0, v0;
+ INIT_VECTOR4(u0,
+ vget_low_u8(p1), vget_low_u8(p0),
+ vget_low_u8(q0), vget_low_u8(q1));
+ INIT_VECTOR4(v0,
+ vget_high_u8(p1), vget_high_u8(p0),
+ vget_high_u8(q0), vget_high_u8(q1));
+ vst4_lane_u8(u - 2 + 0 * stride, u0, 0);
+ vst4_lane_u8(u - 2 + 1 * stride, u0, 1);
+ vst4_lane_u8(u - 2 + 2 * stride, u0, 2);
+ vst4_lane_u8(u - 2 + 3 * stride, u0, 3);
+ vst4_lane_u8(u - 2 + 4 * stride, u0, 4);
+ vst4_lane_u8(u - 2 + 5 * stride, u0, 5);
+ vst4_lane_u8(u - 2 + 6 * stride, u0, 6);
+ vst4_lane_u8(u - 2 + 7 * stride, u0, 7);
+ vst4_lane_u8(v - 2 + 0 * stride, v0, 0);
+ vst4_lane_u8(v - 2 + 1 * stride, v0, 1);
+ vst4_lane_u8(v - 2 + 2 * stride, v0, 2);
+ vst4_lane_u8(v - 2 + 3 * stride, v0, 3);
+ vst4_lane_u8(v - 2 + 4 * stride, v0, 4);
+ vst4_lane_u8(v - 2 + 5 * stride, v0, 5);
+ vst4_lane_u8(v - 2 + 6 * stride, v0, 6);
+ vst4_lane_u8(v - 2 + 7 * stride, v0, 7);
+}
+
+#endif // !WORK_AROUND_GCC
+
+// Treats 'v' as an uint8x8_t and zero extends to an int16x8_t.
+static WEBP_INLINE int16x8_t ConvertU8ToS16(uint32x2_t v) {
+ return vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(v)));
+}
+
+// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result
+// to the corresponding rows of 'dst'.
+static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
+ const int16x8_t dst01,
+ const int16x8_t dst23) {
+ // Unsigned saturate to 8b.
+ const uint8x8_t dst01_u8 = vqmovun_s16(dst01);
+ const uint8x8_t dst23_u8 = vqmovun_s16(dst23);
+
+ // Store the results.
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1);
+}
+
+static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
+ uint8_t* const dst) {
+ uint32x2_t dst01 = vdup_n_u32(0);
+ uint32x2_t dst23 = vdup_n_u32(0);
+
+ // Load the source pixels.
+ dst01 = vld1_lane_u32((uint32_t*)(dst + 0 * BPS), dst01, 0);
+ dst23 = vld1_lane_u32((uint32_t*)(dst + 2 * BPS), dst23, 0);
+ dst01 = vld1_lane_u32((uint32_t*)(dst + 1 * BPS), dst01, 1);
+ dst23 = vld1_lane_u32((uint32_t*)(dst + 3 * BPS), dst23, 1);
+
+ {
+ // Convert to 16b.
+ const int16x8_t dst01_s16 = ConvertU8ToS16(dst01);
+ const int16x8_t dst23_s16 = ConvertU8ToS16(dst23);
+
+ // Descale with rounding.
+ const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3);
+ const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3);
+ // Add the inverse transform.
+ SaturateAndStore4x4(dst, out01, out23);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static uint8x16_t NeedsFilter(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int thresh) {
+ const uint8x16_t thresh_v = vdupq_n_u8((uint8_t)thresh);
+ const uint8x16_t a_p0_q0 = vabdq_u8(p0, q0); // abs(p0-q0)
+ const uint8x16_t a_p1_q1 = vabdq_u8(p1, q1); // abs(p1-q1)
+ const uint8x16_t a_p0_q0_2 = vqaddq_u8(a_p0_q0, a_p0_q0); // 2 * abs(p0-q0)
+ const uint8x16_t a_p1_q1_2 = vshrq_n_u8(a_p1_q1, 1); // abs(p1-q1) / 2
+ const uint8x16_t sum = vqaddq_u8(a_p0_q0_2, a_p1_q1_2);
+ const uint8x16_t mask = vcgeq_u8(thresh_v, sum);
+ return mask;
+}
+
+static int8x16_t FlipSign(const uint8x16_t v) {
+ const uint8x16_t sign_bit = vdupq_n_u8(0x80);
+ return vreinterpretq_s8_u8(veorq_u8(v, sign_bit));
+}
+
+static uint8x16_t FlipSignBack(const int8x16_t v) {
+ const int8x16_t sign_bit = vdupq_n_s8(0x80);
+ return vreinterpretq_u8_s8(veorq_s8(v, sign_bit));
+}
+
+static int8x16_t GetBaseDelta(const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1) {
+ const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
+ const int8x16_t p1_q1 = vqsubq_s8(p1, q1); // (p1-q1)
+ const int8x16_t s1 = vqaddq_s8(p1_q1, q0_p0); // (p1-q1) + 1 * (q0 - p0)
+ const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // (p1-q1) + 2 * (q0 - p0)
+ const int8x16_t s3 = vqaddq_s8(q0_p0, s2); // (p1-q1) + 3 * (q0 - p0)
+ return s3;
+}
+
+static int8x16_t GetBaseDelta0(const int8x16_t p0, const int8x16_t q0) {
+ const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
+ const int8x16_t s1 = vqaddq_s8(q0_p0, q0_p0); // 2 * (q0 - p0)
+ const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // 3 * (q0 - p0)
+ return s2;
+}
+
+//------------------------------------------------------------------------------
+
+static void ApplyFilter2(const int8x16_t p0s, const int8x16_t q0s,
+ const int8x16_t delta,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
+ const int8x16_t kCst3 = vdupq_n_s8(0x03);
+ const int8x16_t kCst4 = vdupq_n_s8(0x04);
+ const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3);
+ const int8x16_t delta_p4 = vqaddq_s8(delta, kCst4);
+ const int8x16_t delta3 = vshrq_n_s8(delta_p3, 3);
+ const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3);
+ const int8x16_t sp0 = vqaddq_s8(p0s, delta3);
+ const int8x16_t sq0 = vqsubq_s8(q0s, delta4);
+ *op0 = FlipSignBack(sp0);
+ *oq0 = FlipSignBack(sq0);
+}
+
+#if defined(USE_INTRINSICS)
+
+static void DoFilter2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t mask,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
+ const int8x16_t p1s = FlipSign(p1);
+ const int8x16_t p0s = FlipSign(p0);
+ const int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t delta1 = vandq_s8(delta0, vreinterpretq_s8_u8(mask));
+ ApplyFilter2(p0s, q0s, delta1, op0, oq0);
+}
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ uint8x16_t p1, p0, q0, q1, op0, oq0;
+ Load16x4(p, stride, &p1, &p0, &q0, &q1);
+ {
+ const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
+ DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ }
+ Store16x2(op0, oq0, p, stride);
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ uint8x16_t p1, p0, q0, q1, oq0, op0;
+ Load4x16(p, stride, &p1, &p0, &q0, &q1);
+ {
+ const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
+ DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ }
+ Store2x16(op0, oq0, p, stride);
+}
+
+#else
+
#define QRegs "q0", "q1", "q2", "q3", \
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
@@ -66,31 +579,7 @@
DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \
FLIP_SIGN_BIT2(p0, q0, q10)
-// Load/Store vertical edge
-#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
- "vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
-
-#define STORE8x2(c1, c2, p, stride) \
- "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n"
-
-//-----------------------------------------------------------------------------
-// Simple In-loop filtering (Paragraph 15.2)
-
-static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
@@ -111,7 +600,7 @@ static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
);
}
-static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub r4, %[p], #2 \n" // base1 = p - 2
"lsl r6, %[stride], #1 \n" // r6 = 2 * stride
@@ -137,47 +626,416 @@ static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
);
}
-static void SimpleVFilter16iNEON(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
+#endif // USE_INTRINSICS
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ uint32_t k;
+ for (k = 3; k != 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ uint32_t k;
+ for (k = 3; k != 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+static uint8x16_t NeedsHev(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int hev_thresh) {
+ const uint8x16_t hev_thresh_v = vdupq_n_u8((uint8_t)hev_thresh);
+ const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0)
+ const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0)
+ const uint8x16_t mask1 = vcgtq_u8(a_p1_p0, hev_thresh_v);
+ const uint8x16_t mask2 = vcgtq_u8(a_q1_q0, hev_thresh_v);
+ const uint8x16_t mask = vorrq_u8(mask1, mask2);
+ return mask;
+}
+
+static uint8x16_t NeedsFilter2(const uint8x16_t p3, const uint8x16_t p2,
+ const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t q2, const uint8x16_t q3,
+ int ithresh, int thresh) {
+ const uint8x16_t ithresh_v = vdupq_n_u8((uint8_t)ithresh);
+ const uint8x16_t a_p3_p2 = vabdq_u8(p3, p2); // abs(p3 - p2)
+ const uint8x16_t a_p2_p1 = vabdq_u8(p2, p1); // abs(p2 - p1)
+ const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0)
+ const uint8x16_t a_q3_q2 = vabdq_u8(q3, q2); // abs(q3 - q2)
+ const uint8x16_t a_q2_q1 = vabdq_u8(q2, q1); // abs(q2 - q1)
+ const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0)
+ const uint8x16_t max1 = vmaxq_u8(a_p3_p2, a_p2_p1);
+ const uint8x16_t max2 = vmaxq_u8(a_p1_p0, a_q3_q2);
+ const uint8x16_t max3 = vmaxq_u8(a_q2_q1, a_q1_q0);
+ const uint8x16_t max12 = vmaxq_u8(max1, max2);
+ const uint8x16_t max123 = vmaxq_u8(max12, max3);
+ const uint8x16_t mask2 = vcgeq_u8(ithresh_v, max123);
+ const uint8x16_t mask1 = NeedsFilter(p1, p0, q0, q1, thresh);
+ const uint8x16_t mask = vandq_u8(mask1, mask2);
+ return mask;
+}
+
+// 4-points filter
+
+static void ApplyFilter4(
+ const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1,
+ const int8x16_t delta0,
+ uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1) {
+ const int8x16_t kCst3 = vdupq_n_s8(0x03);
+ const int8x16_t kCst4 = vdupq_n_s8(0x04);
+ const int8x16_t delta1 = vqaddq_s8(delta0, kCst4);
+ const int8x16_t delta2 = vqaddq_s8(delta0, kCst3);
+ const int8x16_t a1 = vshrq_n_s8(delta1, 3);
+ const int8x16_t a2 = vshrq_n_s8(delta2, 3);
+ const int8x16_t a3 = vrshrq_n_s8(a1, 1); // a3 = (a1 + 1) >> 1
+ *op0 = FlipSignBack(vqaddq_s8(p0, a2)); // clip(p0 + a2)
+ *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - a1)
+ *op1 = FlipSignBack(vqaddq_s8(p1, a3)); // clip(p1 + a3)
+ *oq1 = FlipSignBack(vqsubq_s8(q1, a3)); // clip(q1 - a3)
+}
+
+static void DoFilter4(
+ const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t mask, const uint8x16_t hev_mask,
+ uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1) {
+ // This is a fused version of DoFilter2() calling ApplyFilter2 directly
+ const int8x16_t p1s = FlipSign(p1);
+ int8x16_t p0s = FlipSign(p0);
+ int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
+
+ // do_filter2 part (simple loopfilter on pixels with hev)
+ {
+ const int8x16_t delta = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t simple_lf_delta =
+ vandq_s8(delta, vreinterpretq_s8_u8(simple_lf_mask));
+ uint8x16_t tmp_p0, tmp_q0;
+ ApplyFilter2(p0s, q0s, simple_lf_delta, &tmp_p0, &tmp_q0);
+ // TODO(skal): avoid the double FlipSign() in ApplyFilter2() and here
+ p0s = FlipSign(tmp_p0);
+ q0s = FlipSign(tmp_q0);
+ }
+
+ // do_filter4 part (complex loopfilter on pixels without hev)
+ {
+ const int8x16_t delta0 = GetBaseDelta0(p0s, q0s);
+ // we use: (mask & hev_mask) ^ mask = mask & !hev_mask
+ const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
+ const int8x16_t complex_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
+ ApplyFilter4(p1s, p0s, q0s, q1s, complex_lf_delta, op1, op0, oq0, oq1);
+ }
+}
+
+// 6-points filter
+
+static void ApplyFilter6(
+ const int8x16_t p2, const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1, const int8x16_t q2,
+ const int8x16_t delta,
+ uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) {
+ const int16x8_t kCst63 = vdupq_n_s16(63);
+ const int8x8_t kCst27 = vdup_n_s8(27);
+ const int8x8_t kCst18 = vdup_n_s8(18);
+ const int8x8_t kCst9 = vdup_n_s8(9);
+ const int8x8_t delta_lo = vget_low_s8(delta);
+ const int8x8_t delta_hi = vget_high_s8(delta);
+ const int16x8_t s1_lo = vmlal_s8(kCst63, kCst27, delta_lo); // 63 + 27 * a
+ const int16x8_t s1_hi = vmlal_s8(kCst63, kCst27, delta_hi); // 63 + 27 * a
+ const int16x8_t s2_lo = vmlal_s8(kCst63, kCst18, delta_lo); // 63 + 18 * a
+ const int16x8_t s2_hi = vmlal_s8(kCst63, kCst18, delta_hi); // 63 + 18 * a
+ const int16x8_t s3_lo = vmlal_s8(kCst63, kCst9, delta_lo); // 63 + 9 * a
+ const int16x8_t s3_hi = vmlal_s8(kCst63, kCst9, delta_hi); // 63 + 9 * a
+ const int8x8_t a1_lo = vqshrn_n_s16(s1_lo, 7);
+ const int8x8_t a1_hi = vqshrn_n_s16(s1_hi, 7);
+ const int8x8_t a2_lo = vqshrn_n_s16(s2_lo, 7);
+ const int8x8_t a2_hi = vqshrn_n_s16(s2_hi, 7);
+ const int8x8_t a3_lo = vqshrn_n_s16(s3_lo, 7);
+ const int8x8_t a3_hi = vqshrn_n_s16(s3_hi, 7);
+ const int8x16_t a1 = vcombine_s8(a1_lo, a1_hi);
+ const int8x16_t a2 = vcombine_s8(a2_lo, a2_hi);
+ const int8x16_t a3 = vcombine_s8(a3_lo, a3_hi);
+
+ *op0 = FlipSignBack(vqaddq_s8(p0, a1)); // clip(p0 + a1)
+ *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - q1)
+ *oq1 = FlipSignBack(vqsubq_s8(q1, a2)); // clip(q1 - a2)
+ *op1 = FlipSignBack(vqaddq_s8(p1, a2)); // clip(p1 + a2)
+ *oq2 = FlipSignBack(vqsubq_s8(q2, a3)); // clip(q2 - a3)
+ *op2 = FlipSignBack(vqaddq_s8(p2, a3)); // clip(p2 + a3)
+}
+
+static void DoFilter6(
+ const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
+ const uint8x16_t mask, const uint8x16_t hev_mask,
+ uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) {
+ // This is a fused version of DoFilter2() calling ApplyFilter2 directly
+ const int8x16_t p2s = FlipSign(p2);
+ const int8x16_t p1s = FlipSign(p1);
+ int8x16_t p0s = FlipSign(p0);
+ int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const int8x16_t q2s = FlipSign(q2);
+ const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
+ const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+
+ // do_filter2 part (simple loopfilter on pixels with hev)
+ {
+ const int8x16_t simple_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(simple_lf_mask));
+ uint8x16_t tmp_p0, tmp_q0;
+ ApplyFilter2(p0s, q0s, simple_lf_delta, &tmp_p0, &tmp_q0);
+ // TODO(skal): avoid the double FlipSign() in ApplyFilter2() and here
+ p0s = FlipSign(tmp_p0);
+ q0s = FlipSign(tmp_q0);
+ }
+
+ // do_filter6 part (complex loopfilter on pixels without hev)
+ {
+ // we use: (mask & hev_mask) ^ mask = mask & !hev_mask
+ const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
+ const int8x16_t complex_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
+ ApplyFilter6(p2s, p1s, p0s, q0s, q1s, q2s, complex_lf_delta,
+ op2, op1, op0, oq0, oq1, oq2);
+ }
+}
+
+// on macroblock edges
+
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load16x8(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store16x2(op2, op1, p - 2 * stride, stride);
+ Store16x2(op0, oq0, p + 0 * stride, stride);
+ Store16x2(oq1, oq2, p + 2 * stride, stride);
+ }
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x16(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store2x16(op2, op1, p - 2, stride);
+ Store2x16(op0, oq0, p + 0, stride);
+ Store2x16(oq1, oq2, p + 2, stride);
+ }
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint32_t k;
+ uint8x16_t p3, p2, p1, p0;
+ Load16x4(p + 2 * stride, stride, &p3, &p2, &p1, &p0);
+ for (k = 3; k != 0; --k) {
+ uint8x16_t q0, q1, q2, q3;
p += 4 * stride;
- SimpleVFilter16NEON(p, stride, thresh);
+ Load16x4(p + 2 * stride, stride, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask =
+ NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ // p3 and p2 are not just temporary variables here: they will be
+ // re-used for next span. And q2/q3 will become p1/p0 accordingly.
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store16x4(p1, p0, p3, p2, p, stride);
+ p1 = q2;
+ p0 = q3;
+ }
}
}
-static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
+#if !defined(WORK_AROUND_GCC)
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint32_t k;
+ uint8x16_t p3, p2, p1, p0;
+ Load4x16(p + 2, stride, &p3, &p2, &p1, &p0);
+ for (k = 3; k != 0; --k) {
+ uint8x16_t q0, q1, q2, q3;
p += 4;
- SimpleHFilter16NEON(p, stride, thresh);
+ Load4x16(p + 2, stride, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask =
+ NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store4x16(p1, p0, p3, p2, p, stride);
+ p1 = q2;
+ p0 = q3;
+ }
+ }
+}
+#endif // !WORK_AROUND_GCC
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store8x2x2(op2, op1, u - 2 * stride, v - 2 * stride, stride);
+ Store8x2x2(op0, oq0, u + 0 * stride, v + 0 * stride, stride);
+ Store8x2x2(oq1, oq2, u + 2 * stride, v + 2 * stride, stride);
+ }
+}
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ u += 4 * stride;
+ v += 4 * stride;
+ Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op1, op0, oq0, oq1;
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store8x4x2(op1, op0, oq0, oq1, u, v, stride);
+ }
+}
+
+#if !defined(WORK_AROUND_GCC)
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store6x8x2(op2, op1, op0, oq0, oq1, oq2, u, v, stride);
+ }
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ u += 4;
+ v += 4;
+ Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op1, op0, oq0, oq1;
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store4x8x2(op1, op0, oq0, oq1, u, v, stride);
}
}
+#endif // !WORK_AROUND_GCC
//-----------------------------------------------------------------------------
// Inverse transforms (Paragraph 14.4)
+// 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
+
+static const int16_t kC1 = 20091;
+static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+
+#if defined(USE_INTRINSICS)
+static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
+ int16x8x2_t* const out) {
+ // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1
+ // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3
+ const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ...
+ // b0 d0 b1 d1 b2 d2 ...
+ *out = vzipq_s16(tmp0.val[0], tmp0.val[1]);
+}
+
+static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
+ // {rows} = in0 | in4
+ // in8 | in12
+ // B1 = in4 | in12
+ const int16x8_t B1 =
+ vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1]));
+ // C0 = kC1 * in4 | kC1 * in12
+ // C1 = kC2 * in4 | kC2 * in12
+ const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1);
+ const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2);
+ const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 + in8
+ const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 - in8
+ // c = kC2 * in4 - kC1 * in12
+ // d = kC1 * in4 + kC2 * in12
+ const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0));
+ const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1));
+ const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b
+ const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c
+ const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c
+ const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c
+ const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp));
+ Transpose8x2(E0, E1, rows);
+}
+
static void TransformOne(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
- */
+ int16x8x2_t rows;
+ INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8));
+ TransformPass(&rows);
+ TransformPass(&rows);
+ Add4x4(rows.val[0], rows.val[1], dst);
+}
+
+#else
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ const int kBPS = BPS;
+ // kC1, kC2. Padded because vld1.16 loads 8 bytes
+ const int16_t constants[4] = { kC1, kC2, 0, 0 };
/* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */
__asm__ volatile (
"vld1.16 {q1, q2}, [%[in]] \n"
@@ -305,6 +1163,8 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
);
}
+#endif // USE_INTRINSICS
+
static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
TransformOne(in, dst);
if (do_two) {
@@ -313,102 +1173,90 @@ static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
}
static void TransformDC(const int16_t* in, uint8_t* dst) {
- const int DC = (in[0] + 4) >> 3;
- const int kBPS = BPS;
- __asm__ volatile (
- "vdup.16 q1, %[DC] \n"
+ const int16x8_t DC = vdupq_n_s16(in[0]);
+ Add4x4(DC, DC, dst);
+}
- "vld1.32 d0[0], [%[dst]], %[kBPS] \n"
- "vld1.32 d1[0], [%[dst]], %[kBPS] \n"
- "vld1.32 d0[1], [%[dst]], %[kBPS] \n"
- "vld1.32 d1[1], [%[dst]], %[kBPS] \n"
+//------------------------------------------------------------------------------
- "sub %[dst], %[dst], %[kBPS], lsl #2 \n"
+#define STORE_WHT(dst, col, rows) do { \
+ *dst = vgetq_lane_s32(rows.val[0], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[1], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[2], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[3], col); (dst) += 16; \
+} while (0)
- // add DC and convert to s16.
- "vaddw.u8 q2, q1, d0 \n"
- "vaddw.u8 q3, q1, d1 \n"
- // convert back to u8 with saturation
- "vqmovun.s16 d0, q2 \n"
- "vqmovun.s16 d1, q3 \n"
+static void TransformWHT(const int16_t* in, int16_t* out) {
+ int32x4x4_t tmp;
+
+ {
+ // Load the source.
+ const int16x4_t in00_03 = vld1_s16(in + 0);
+ const int16x4_t in04_07 = vld1_s16(in + 4);
+ const int16x4_t in08_11 = vld1_s16(in + 8);
+ const int16x4_t in12_15 = vld1_s16(in + 12);
+ const int32x4_t a0 = vaddl_s16(in00_03, in12_15); // in[0..3] + in[12..15]
+ const int32x4_t a1 = vaddl_s16(in04_07, in08_11); // in[4..7] + in[8..11]
+ const int32x4_t a2 = vsubl_s16(in04_07, in08_11); // in[4..7] - in[8..11]
+ const int32x4_t a3 = vsubl_s16(in00_03, in12_15); // in[0..3] - in[12..15]
+ tmp.val[0] = vaddq_s32(a0, a1);
+ tmp.val[1] = vaddq_s32(a3, a2);
+ tmp.val[2] = vsubq_s32(a0, a1);
+ tmp.val[3] = vsubq_s32(a3, a2);
+ // Arrange the temporary results column-wise.
+ tmp = Transpose4x4(tmp);
+ }
- "vst1.32 d0[0], [%[dst]], %[kBPS] \n"
- "vst1.32 d1[0], [%[dst]], %[kBPS] \n"
- "vst1.32 d0[1], [%[dst]], %[kBPS] \n"
- "vst1.32 d1[1], [%[dst]] \n"
- : [in] "+r"(in), [dst] "+r"(dst) /* modified registers */
- : [kBPS] "r"(kBPS), /* constants */
- [DC] "r"(DC)
- : "memory", "q0", "q1", "q2", "q3" /* clobbered */
- );
+ {
+ const int32x4_t kCst3 = vdupq_n_s32(3);
+ const int32x4_t dc = vaddq_s32(tmp.val[0], kCst3); // add rounder
+ const int32x4_t a0 = vaddq_s32(dc, tmp.val[3]);
+ const int32x4_t a1 = vaddq_s32(tmp.val[1], tmp.val[2]);
+ const int32x4_t a2 = vsubq_s32(tmp.val[1], tmp.val[2]);
+ const int32x4_t a3 = vsubq_s32(dc, tmp.val[3]);
+
+ tmp.val[0] = vaddq_s32(a0, a1);
+ tmp.val[1] = vaddq_s32(a3, a2);
+ tmp.val[2] = vsubq_s32(a0, a1);
+ tmp.val[3] = vsubq_s32(a3, a2);
+
+ // right shift the results by 3.
+ tmp.val[0] = vshrq_n_s32(tmp.val[0], 3);
+ tmp.val[1] = vshrq_n_s32(tmp.val[1], 3);
+ tmp.val[2] = vshrq_n_s32(tmp.val[2], 3);
+ tmp.val[3] = vshrq_n_s32(tmp.val[3], 3);
+
+ STORE_WHT(out, 0, tmp);
+ STORE_WHT(out, 1, tmp);
+ STORE_WHT(out, 2, tmp);
+ STORE_WHT(out, 3, tmp);
+ }
}
-static void TransformWHT(const int16_t* in, int16_t* out) {
- const int kStep = 32; // The store is only incrementing the pointer as if we
- // had stored a single byte.
- __asm__ volatile (
- // part 1
- // load data into q0, q1
- "vld1.16 {q0, q1}, [%[in]] \n"
-
- "vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12]
- "vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8]
- "vsubl.s16 q10, d1, d2 \n" // a2 = in[4] - in[8]
- "vsubl.s16 q11, d0, d3 \n" // a3 = in[0] - in[12]
-
- "vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1
- "vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1
- "vadd.s32 q1, q11, q10 \n" // tmp[4] = a3 + a2
- "vsub.s32 q3, q11, q10 \n" // tmp[12] = a3 - a2
-
- // Transpose
- // q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
- // q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
- "vswp d1, d4 \n" // vtrn.64 q0, q2
- "vswp d3, d6 \n" // vtrn.64 q1, q3
- "vtrn.32 q0, q1 \n"
- "vtrn.32 q2, q3 \n"
-
- "vmov.s32 q10, #3 \n" // dc = 3
- "vadd.s32 q0, q0, q10 \n" // dc = tmp[0] + 3
- "vadd.s32 q12, q0, q3 \n" // a0 = dc + tmp[3]
- "vadd.s32 q13, q1, q2 \n" // a1 = tmp[1] + tmp[2]
- "vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2]
- "vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3]
-
- "vadd.s32 q0, q12, q13 \n"
- "vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3
- "vadd.s32 q1, q9, q8 \n"
- "vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3
- "vsub.s32 q2, q12, q13 \n"
- "vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3
- "vsub.s32 q3, q9, q8 \n"
- "vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3
-
- // set the results to output
- "vst1.16 d0[0], [%[out]], %[kStep] \n"
- "vst1.16 d1[0], [%[out]], %[kStep] \n"
- "vst1.16 d2[0], [%[out]], %[kStep] \n"
- "vst1.16 d3[0], [%[out]], %[kStep] \n"
- "vst1.16 d0[1], [%[out]], %[kStep] \n"
- "vst1.16 d1[1], [%[out]], %[kStep] \n"
- "vst1.16 d2[1], [%[out]], %[kStep] \n"
- "vst1.16 d3[1], [%[out]], %[kStep] \n"
- "vst1.16 d0[2], [%[out]], %[kStep] \n"
- "vst1.16 d1[2], [%[out]], %[kStep] \n"
- "vst1.16 d2[2], [%[out]], %[kStep] \n"
- "vst1.16 d3[2], [%[out]], %[kStep] \n"
- "vst1.16 d0[3], [%[out]], %[kStep] \n"
- "vst1.16 d1[3], [%[out]], %[kStep] \n"
- "vst1.16 d2[3], [%[out]], %[kStep] \n"
- "vst1.16 d3[3], [%[out]], %[kStep] \n"
-
- : [out] "+r"(out) // modified registers
- : [in] "r"(in), [kStep] "r"(kStep) // constants
- : "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13" // clobbered
- );
+#undef STORE_WHT
+
+//------------------------------------------------------------------------------
+
+#define MUL(a, b) (((a) * (b)) >> 16)
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
+ static const int kC1_full = 20091 + (1 << 16);
+ static const int kC2_full = 35468;
+ const int16x4_t A = vdup_n_s16(in[0]);
+ const int16x4_t c4 = vdup_n_s16(MUL(in[4], kC2_full));
+ const int16x4_t d4 = vdup_n_s16(MUL(in[4], kC1_full));
+ const int c1 = MUL(in[1], kC2_full);
+ const int d1 = MUL(in[1], kC1_full);
+ const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 |
+ (uint64_t)( c1 & 0xffff) << 16 |
+ (uint64_t)(-c1 & 0xffff) << 32 |
+ (uint64_t)(-d1 & 0xffff) << 48;
+ const int16x4_t CD = vcreate_s16(cd);
+ const int16x4_t B = vqadd_s16(A, CD);
+ const int16x8_t m0_m1 = vcombine_s16(vqadd_s16(B, d4), vqadd_s16(B, c4));
+ const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
+ Add4x4(m0_m1, m2_m3, dst);
}
+#undef MUL
#endif // WEBP_USE_NEON
@@ -420,14 +1268,25 @@ extern void VP8DspInitNEON(void);
void VP8DspInitNEON(void) {
#if defined(WEBP_USE_NEON)
VP8Transform = TransformTwo;
- VP8TransformAC3 = TransformOne; // no special code here
+ VP8TransformAC3 = TransformAC3;
VP8TransformDC = TransformDC;
VP8TransformWHT = TransformWHT;
- VP8SimpleVFilter16 = SimpleVFilter16NEON;
- VP8SimpleHFilter16 = SimpleHFilter16NEON;
- VP8SimpleVFilter16i = SimpleVFilter16iNEON;
- VP8SimpleHFilter16i = SimpleHFilter16iNEON;
+ VP8VFilter16 = VFilter16;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16 = HFilter16;
+#if !defined(WORK_AROUND_GCC)
+ VP8HFilter16i = HFilter16i;
+#endif
+ VP8VFilter8 = VFilter8;
+ VP8VFilter8i = VFilter8i;
+#if !defined(WORK_AROUND_GCC)
+ VP8HFilter8 = HFilter8;
+ VP8HFilter8i = HFilter8i;
+#endif
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
#endif // WEBP_USE_NEON
}
-
diff --git a/src/3rdparty/libwebp/src/dsp/dec_sse2.c b/src/3rdparty/libwebp/src/dsp/dec_sse2.c
index 150c559..c37a637 100644
--- a/src/3rdparty/libwebp/src/dsp/dec_sse2.c
+++ b/src/3rdparty/libwebp/src/dsp/dec_sse2.c
@@ -26,7 +26,7 @@
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
-static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
+static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -246,7 +246,7 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
#if defined(USE_TRANSFORM_AC3)
#define MUL(a, b) (((a) * (b)) >> 16)
-static void TransformAC3SSE2(const int16_t* in, uint8_t* dst) {
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
static const int kC1 = 20091 + (1 << 16);
static const int kC2 = 35468;
const __m128i A = _mm_set1_epi16(in[0] + 4);
@@ -298,20 +298,15 @@ static void TransformAC3SSE2(const int16_t* in, uint8_t* dst) {
_mm_subs_epu8((q), (p)), \
_mm_subs_epu8((p), (q)))
-// Shift each byte of "a" by N bits while preserving by the sign bit.
-//
-// It first shifts the lower bytes of the words and then the upper bytes and
-// then merges the results together.
-#define SIGNED_SHIFT_N(a, N) { \
- __m128i t = a; \
- t = _mm_slli_epi16(t, 8); \
- t = _mm_srai_epi16(t, N); \
- t = _mm_srli_epi16(t, 8); \
- \
- a = _mm_srai_epi16(a, N + 8); \
- a = _mm_slli_epi16(a, 8); \
- \
- a = _mm_or_si128(t, a); \
+// Shift each byte of "x" by 3 bits while preserving by the sign bit.
+static WEBP_INLINE void SignedShift8b(__m128i* const x) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i signs = _mm_cmpgt_epi8(zero, *x);
+ const __m128i lo_0 = _mm_unpacklo_epi8(*x, signs); // s8 -> s16 sign extend
+ const __m128i hi_0 = _mm_unpackhi_epi8(*x, signs);
+ const __m128i lo_1 = _mm_srai_epi16(lo_0, 3);
+ const __m128i hi_1 = _mm_srai_epi16(hi_0, 3);
+ *x = _mm_packs_epi16(lo_1, hi_1);
}
#define FLIP_SIGN_BIT2(a, b) { \
@@ -324,103 +319,123 @@ static void TransformAC3SSE2(const int16_t* in, uint8_t* dst) {
FLIP_SIGN_BIT2(c, d); \
}
-#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \
- const __m128i zero = _mm_setzero_si128(); \
- const __m128i t_1 = MM_ABS(p1, p0); \
- const __m128i t_2 = MM_ABS(q1, q0); \
- \
- const __m128i h = _mm_set1_epi8(hev_thresh); \
- const __m128i t_3 = _mm_subs_epu8(t_1, h); /* abs(p1 - p0) - hev_tresh */ \
- const __m128i t_4 = _mm_subs_epu8(t_2, h); /* abs(q1 - q0) - hev_tresh */ \
- \
- not_hev = _mm_or_si128(t_3, t_4); \
- not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\
-}
-
-#define GET_BASE_DELTA(p1, p0, q0, q1, o) { \
- const __m128i qp0 = _mm_subs_epi8(q0, p0); /* q0 - p0 */ \
- o = _mm_subs_epi8(p1, q1); /* p1 - q1 */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 1 * (q0 - p0) */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 2 * (q0 - p0) */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 3 * (q0 - p0) */ \
-}
-
-#define DO_SIMPLE_FILTER(p0, q0, fl) { \
- const __m128i three = _mm_set1_epi8(3); \
- const __m128i four = _mm_set1_epi8(4); \
- __m128i v3 = _mm_adds_epi8(fl, three); \
- __m128i v4 = _mm_adds_epi8(fl, four); \
- \
- /* Do +4 side */ \
- SIGNED_SHIFT_N(v4, 3); /* v4 >> 3 */ \
- q0 = _mm_subs_epi8(q0, v4); /* q0 -= v4 */ \
- \
- /* Now do +3 side */ \
- SIGNED_SHIFT_N(v3, 3); /* v3 >> 3 */ \
- p0 = _mm_adds_epi8(p0, v3); /* p0 += v3 */ \
+// input/output is uint8_t
+static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int hev_thresh, __m128i* const not_hev) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i t_1 = MM_ABS(*p1, *p0);
+ const __m128i t_2 = MM_ABS(*q1, *q0);
+
+ const __m128i h = _mm_set1_epi8(hev_thresh);
+ const __m128i t_3 = _mm_subs_epu8(t_1, h); // abs(p1 - p0) - hev_tresh
+ const __m128i t_4 = _mm_subs_epu8(t_2, h); // abs(q1 - q0) - hev_tresh
+
+ *not_hev = _mm_or_si128(t_3, t_4);
+ *not_hev = _mm_cmpeq_epi8(*not_hev, zero); // not_hev <= t1 && not_hev <= t2
+}
+
+// input pixels are int8_t
+static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ __m128i* const delta) {
+ // beware of addition order, for saturation!
+ const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
+ const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
+ const __m128i s1 = _mm_adds_epi8(p1_q1, q0_p0); // p1 - q1 + 1 * (q0 - p0)
+ const __m128i s2 = _mm_adds_epi8(q0_p0, s1); // p1 - q1 + 2 * (q0 - p0)
+ const __m128i s3 = _mm_adds_epi8(q0_p0, s2); // p1 - q1 + 3 * (q0 - p0)
+ *delta = s3;
+}
+
+// input and output are int8_t
+static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
+ const __m128i* const fl) {
+ const __m128i k3 = _mm_set1_epi8(3);
+ const __m128i k4 = _mm_set1_epi8(4);
+ __m128i v3 = _mm_adds_epi8(*fl, k3);
+ __m128i v4 = _mm_adds_epi8(*fl, k4);
+
+ SignedShift8b(&v4); // v4 >> 3
+ SignedShift8b(&v3); // v3 >> 3
+ *q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
+ *p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
}
// Updates values of 2 pixels at MB edge during complex filtering.
// Update operations:
// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
-#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \
- const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \
- const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \
- const __m128i delta = _mm_packs_epi16(a_lo7, a_hi7); \
- pi = _mm_adds_epi8(pi, delta); \
- qi = _mm_subs_epi8(qi, delta); \
+// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
+static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
+ const __m128i* const a0_lo,
+ const __m128i* const a0_hi) {
+ const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
+ const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
+ const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+ *pi = _mm_adds_epi8(*pi, delta);
+ *qi = _mm_subs_epi8(*qi, delta);
+ FLIP_SIGN_BIT2(*pi, *qi);
}
-static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
- const __m128i* q1, int thresh, __m128i *mask) {
- __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
- *mask = _mm_set1_epi8(0xFE);
- t1 = _mm_and_si128(t1, *mask); // set lsb of each byte to zero
- t1 = _mm_srli_epi16(t1, 1); // abs(p1 - q1) / 2
+// input pixels are uint8_t
+static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, __m128i* const mask) {
+ const __m128i m_thresh = _mm_set1_epi8(thresh);
+ const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
+ const __m128i kFE = _mm_set1_epi8(0xFE);
+ const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero
+ const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2
- *mask = MM_ABS(*p0, *q0); // abs(p0 - q0)
- *mask = _mm_adds_epu8(*mask, *mask); // abs(p0 - q0) * 2
- *mask = _mm_adds_epu8(*mask, t1); // abs(p0 - q0) * 2 + abs(p1 - q1) / 2
+ const __m128i t4 = MM_ABS(*p0, *q0); // abs(p0 - q0)
+ const __m128i t5 = _mm_adds_epu8(t4, t4); // abs(p0 - q0) * 2
+ const __m128i t6 = _mm_adds_epu8(t5, t3); // abs(p0-q0)*2 + abs(p1-q1)/2
- t1 = _mm_set1_epi8(thresh);
- *mask = _mm_subs_epu8(*mask, t1); // mask <= thresh
- *mask = _mm_cmpeq_epi8(*mask, _mm_setzero_si128());
+ const __m128i t7 = _mm_subs_epu8(t6, m_thresh); // mask <= m_thresh
+ *mask = _mm_cmpeq_epi8(t7, _mm_setzero_si128());
}
//------------------------------------------------------------------------------
// Edge filtering functions
// Applies filter on 2 pixels (p0 and q0)
-static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
- const __m128i* q1, int thresh) {
+static WEBP_INLINE void DoFilter2(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ int thresh) {
__m128i a, mask;
const __m128i sign_bit = _mm_set1_epi8(0x80);
+ // convert p1/q1 to int8_t (for GetBaseDelta)
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
NeedsFilter(p1, p0, q0, q1, thresh, &mask);
- // convert to signed values
FLIP_SIGN_BIT2(*p0, *q0);
-
- GET_BASE_DELTA(p1s, *p0, *q0, q1s, a);
+ GetBaseDelta(&p1s, p0, q0, &q1s, &a);
a = _mm_and_si128(a, mask); // mask filter values we don't care about
- DO_SIMPLE_FILTER(*p0, *q0, a);
-
- // unoffset
+ DoSimpleFilter(p0, q0, &a);
FLIP_SIGN_BIT2(*p0, *q0);
}
// Applies filter on 4 pixels (p1, p0, q0 and q1)
-static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
- __m128i* q0, __m128i* q1,
- const __m128i* mask, int hev_thresh) {
+static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ const __m128i* const mask, int hev_thresh) {
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+ const __m128i k64 = _mm_set1_epi8(0x40);
+ const __m128i zero = _mm_setzero_si128();
__m128i not_hev;
__m128i t1, t2, t3;
- const __m128i sign_bit = _mm_set1_epi8(0x80);
// compute hev mask
- GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+ GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
// convert to signed values
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
@@ -433,92 +448,83 @@ static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0)
t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about
- // Do +4 side
- t2 = _mm_set1_epi8(4);
- t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 4
- SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
- t3 = t2; // save t2
- *q0 = _mm_subs_epi8(*q0, t2); // q0 -= t2
-
- // Now do +3 side
t2 = _mm_set1_epi8(3);
- t2 = _mm_adds_epi8(t1, t2); // +3 instead of +4
- SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ t3 = _mm_set1_epi8(4);
+ t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 3
+ t3 = _mm_adds_epi8(t1, t3); // 3 * (q0 - p0) + (p1 - q1) + 4
+ SignedShift8b(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ SignedShift8b(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
+ *q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
+ FLIP_SIGN_BIT2(*p0, *q0);
- t2 = _mm_set1_epi8(1);
- t3 = _mm_adds_epi8(t3, t2);
- SIGNED_SHIFT_N(t3, 1); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 4
+ // this is equivalent to signed (a + 1) >> 1 calculation
+ t2 = _mm_add_epi8(t3, sign_bit);
+ t3 = _mm_avg_epu8(t2, zero);
+ t3 = _mm_sub_epi8(t3, k64);
t3 = _mm_and_si128(not_hev, t3); // if !hev
*q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3
*p1 = _mm_adds_epi8(*p1, t3); // p1 += t3
-
- // unoffset
- FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+ FLIP_SIGN_BIT2(*p1, *q1);
}
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
-static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
- __m128i* q0, __m128i* q1, __m128i *q2,
- const __m128i* mask, int hev_thresh) {
- __m128i a, not_hev;
+static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
+ __m128i* const p0, __m128i* const q0,
+ __m128i* const q1, __m128i* const q2,
+ const __m128i* const mask, int hev_thresh) {
+ const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80);
+ __m128i a, not_hev;
// compute hev mask
- GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+ GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
- // convert to signed values
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
FLIP_SIGN_BIT2(*p2, *q2);
-
- GET_BASE_DELTA(*p1, *p0, *q0, *q1, a);
+ GetBaseDelta(p1, p0, q0, q1, &a);
{ // do simple filter on pixels with hev
const __m128i m = _mm_andnot_si128(not_hev, *mask);
const __m128i f = _mm_and_si128(a, m);
- DO_SIMPLE_FILTER(*p0, *q0, f);
+ DoSimpleFilter(p0, q0, &f);
}
+
{ // do strong filter on pixels with not hev
- const __m128i zero = _mm_setzero_si128();
- const __m128i nine = _mm_set1_epi16(0x0900);
- const __m128i sixty_three = _mm_set1_epi16(63);
+ const __m128i k9 = _mm_set1_epi16(0x0900);
+ const __m128i k63 = _mm_set1_epi16(63);
const __m128i m = _mm_and_si128(not_hev, *mask);
const __m128i f = _mm_and_si128(a, m);
+
const __m128i f_lo = _mm_unpacklo_epi8(zero, f);
const __m128i f_hi = _mm_unpackhi_epi8(zero, f);
- const __m128i f9_lo = _mm_mulhi_epi16(f_lo, nine); // Filter (lo) * 9
- const __m128i f9_hi = _mm_mulhi_epi16(f_hi, nine); // Filter (hi) * 9
- const __m128i f18_lo = _mm_add_epi16(f9_lo, f9_lo); // Filter (lo) * 18
- const __m128i f18_hi = _mm_add_epi16(f9_hi, f9_hi); // Filter (hi) * 18
+ const __m128i f9_lo = _mm_mulhi_epi16(f_lo, k9); // Filter (lo) * 9
+ const __m128i f9_hi = _mm_mulhi_epi16(f_hi, k9); // Filter (hi) * 9
- const __m128i a2_lo = _mm_add_epi16(f9_lo, sixty_three); // Filter * 9 + 63
- const __m128i a2_hi = _mm_add_epi16(f9_hi, sixty_three); // Filter * 9 + 63
+ const __m128i a2_lo = _mm_add_epi16(f9_lo, k63); // Filter * 9 + 63
+ const __m128i a2_hi = _mm_add_epi16(f9_hi, k63); // Filter * 9 + 63
- const __m128i a1_lo = _mm_add_epi16(f18_lo, sixty_three); // F... * 18 + 63
- const __m128i a1_hi = _mm_add_epi16(f18_hi, sixty_three); // F... * 18 + 63
+ const __m128i a1_lo = _mm_add_epi16(a2_lo, f9_lo); // Filter * 18 + 63
+ const __m128i a1_hi = _mm_add_epi16(a2_hi, f9_hi); // Filter * 18 + 63
- const __m128i a0_lo = _mm_add_epi16(f18_lo, a2_lo); // Filter * 27 + 63
- const __m128i a0_hi = _mm_add_epi16(f18_hi, a2_hi); // Filter * 27 + 63
+ const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
+ const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
- UPDATE_2PIXELS(*p2, *q2, a2_lo, a2_hi);
- UPDATE_2PIXELS(*p1, *q1, a1_lo, a1_hi);
- UPDATE_2PIXELS(*p0, *q0, a0_lo, a0_hi);
+ Update2Pixels(p2, q2, &a2_lo, &a2_hi);
+ Update2Pixels(p1, q1, &a1_lo, &a1_hi);
+ Update2Pixels(p0, q0, &a0_lo, &a0_hi);
}
-
- // unoffset
- FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
- FLIP_SIGN_BIT2(*p2, *q2);
}
// reads 8 rows across a vertical edge.
//
// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
// two Load4x4() to avoid code duplication.
-static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
- __m128i* p, __m128i* q) {
+static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
+ __m128i* const p, __m128i* const q) {
__m128i t1, t2;
// Load 0th, 1st, 4th and 5th rows
@@ -557,10 +563,11 @@ static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
*q = _mm_unpackhi_epi32(t1, t2);
}
-static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
+static WEBP_INLINE void Load16x4(const uint8_t* const r0,
+ const uint8_t* const r8,
int stride,
- __m128i* p1, __m128i* p0,
- __m128i* q0, __m128i* q1) {
+ __m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1) {
__m128i t1, t2;
// Assume the pixels around the edge (|) are numbered as follows
// 00 01 | 02 03
@@ -592,7 +599,7 @@ static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
*q1 = _mm_unpackhi_epi64(t2, *q1);
}
-static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
+static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
int i;
for (i = 0; i < 4; ++i, dst += stride) {
*((int32_t*)dst) = _mm_cvtsi128_si32(*x);
@@ -601,48 +608,51 @@ static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
}
// Transpose back and store
-static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride,
- __m128i* p1, __m128i* p0,
- __m128i* q0, __m128i* q1) {
- __m128i t1;
+static WEBP_INLINE void Store16x4(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ uint8_t* r0, uint8_t* r8,
+ int stride) {
+ __m128i t1, p1_s, p0_s, q0_s, q1_s;
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
// p1 = f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80
t1 = *p0;
- *p0 = _mm_unpacklo_epi8(*p1, t1);
- *p1 = _mm_unpackhi_epi8(*p1, t1);
+ p0_s = _mm_unpacklo_epi8(*p1, t1);
+ p1_s = _mm_unpackhi_epi8(*p1, t1);
// q0 = 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
// q1 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82
t1 = *q0;
- *q0 = _mm_unpacklo_epi8(t1, *q1);
- *q1 = _mm_unpackhi_epi8(t1, *q1);
+ q0_s = _mm_unpacklo_epi8(t1, *q1);
+ q1_s = _mm_unpackhi_epi8(t1, *q1);
// p0 = 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00
// q0 = 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40
- t1 = *p0;
- *p0 = _mm_unpacklo_epi16(t1, *q0);
- *q0 = _mm_unpackhi_epi16(t1, *q0);
+ t1 = p0_s;
+ p0_s = _mm_unpacklo_epi16(t1, q0_s);
+ q0_s = _mm_unpackhi_epi16(t1, q0_s);
// p1 = b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
// q1 = f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0
- t1 = *p1;
- *p1 = _mm_unpacklo_epi16(t1, *q1);
- *q1 = _mm_unpackhi_epi16(t1, *q1);
+ t1 = p1_s;
+ p1_s = _mm_unpacklo_epi16(t1, q1_s);
+ q1_s = _mm_unpackhi_epi16(t1, q1_s);
- Store4x4(p0, r0, stride);
+ Store4x4(&p0_s, r0, stride);
r0 += 4 * stride;
- Store4x4(q0, r0, stride);
+ Store4x4(&q0_s, r0, stride);
- Store4x4(p1, r8, stride);
+ Store4x4(&p1_s, r8, stride);
r8 += 4 * stride;
- Store4x4(q1, r8, stride);
+ Store4x4(&q1_s, r8, stride);
}
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
-static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
// Load
__m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
__m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
@@ -653,49 +663,49 @@ static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) {
// Store
_mm_storeu_si128((__m128i*)&p[-stride], p0);
- _mm_storeu_si128((__m128i*)p, q0);
+ _mm_storeu_si128((__m128i*)&p[0], q0);
}
-static void SimpleHFilter16SSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
__m128i p1, p0, q0, q1;
p -= 2; // beginning of p1
- Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
DoFilter2(&p1, &p0, &q0, &q1, thresh);
- Store16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ Store16x4(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
}
-static void SimpleVFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
- SimpleVFilter16SSE2(p, stride, thresh);
+ SimpleVFilter16(p, stride, thresh);
}
}
-static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
- SimpleHFilter16SSE2(p, stride, thresh);
+ SimpleHFilter16(p, stride, thresh);
}
}
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
-#define MAX_DIFF1(p3, p2, p1, p0, m) { \
- m = MM_ABS(p3, p2); \
+#define MAX_DIFF1(p3, p2, p1, p0, m) do { \
+ m = MM_ABS(p1, p0); \
+ m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
- m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
-}
+} while (0)
-#define MAX_DIFF2(p3, p2, p1, p0, m) { \
+#define MAX_DIFF2(p3, p2, p1, p0, m) do { \
+ m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
- m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
-}
+} while (0)
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \
@@ -704,10 +714,11 @@ static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \
}
-#define LOADUV_H_EDGE(p, u, v, stride) { \
- p = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
- p = _mm_unpacklo_epi64(p, _mm_loadl_epi64((__m128i*)&(v)[(stride)])); \
-}
+#define LOADUV_H_EDGE(p, u, v, stride) do { \
+ const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
+ const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \
+ p = _mm_unpacklo_epi64(U, V); \
+} while (0)
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
LOADUV_H_EDGE(e1, u, v, 0 * stride); \
@@ -722,18 +733,23 @@ static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
_mm_storel_epi64((__m128i*)&v[(stride)], p); \
}
-#define COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask) { \
- __m128i fl_yes; \
- const __m128i it = _mm_set1_epi8(ithresh); \
- mask = _mm_subs_epu8(mask, it); \
- mask = _mm_cmpeq_epi8(mask, _mm_setzero_si128()); \
- NeedsFilter(&p1, &p0, &q0, &q1, thresh, &fl_yes); \
- mask = _mm_and_si128(mask, fl_yes); \
+static WEBP_INLINE void ComplexMask(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, int ithresh,
+ __m128i* const mask) {
+ const __m128i it = _mm_set1_epi8(ithresh);
+ const __m128i diff = _mm_subs_epu8(*mask, it);
+ const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
+ __m128i filter_mask;
+ NeedsFilter(p1, p0, q0, q1, thresh, &filter_mask);
+ *mask = _mm_and_si128(thresh_mask, filter_mask);
}
// on macroblock edges
-static void VFilter16SSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i t1;
__m128i mask;
__m128i p2, p1, p0, q0, q1, q2;
@@ -746,20 +762,20 @@ static void VFilter16SSE2(uint8_t* p, int stride,
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
_mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
_mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
- _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
- _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
- _mm_storeu_si128((__m128i*)&p[2 * stride], q2);
+ _mm_storeu_si128((__m128i*)&p[+0 * stride], q0);
+ _mm_storeu_si128((__m128i*)&p[+1 * stride], q1);
+ _mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
}
-static void HFilter16SSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
@@ -770,71 +786,78 @@ static void HFilter16SSE2(uint8_t* p, int stride,
Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
MAX_DIFF2(q3, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
- Store16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
+ Store16x4(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
+ Store16x4(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
}
// on three inner edges
-static void VFilter16iSSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
- __m128i mask;
- __m128i t1, t2, p1, p0, q0, q1;
+ __m128i p3, p2, p1, p0; // loop invariants
- for (k = 3; k > 0; --k) {
- // Load p3, p2, p1, p0
- LOAD_H_EDGES4(p, stride, t2, t1, p1, p0);
- MAX_DIFF1(t2, t1, p1, p0, mask);
+ LOAD_H_EDGES4(p, stride, p3, p2, p1, p0); // prologue
+ for (k = 3; k > 0; --k) {
+ __m128i mask, tmp1, tmp2;
+ uint8_t* const b = p + 2 * stride; // beginning of p1
p += 4 * stride;
- // Load q0, q1, q2, q3
- LOAD_H_EDGES4(p, stride, q0, q1, t1, t2);
- MAX_DIFF2(t2, t1, q1, q0, mask);
+ MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
+ LOAD_H_EDGES4(p, stride, p3, p2, tmp1, tmp2);
+ MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ // p3 and p2 are not just temporary variables here: they will be
+ // re-used for next span. And q2/q3 will become p1/p0 accordingly.
+ ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
// Store
- _mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
- _mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
- _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
- _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
+ _mm_storeu_si128((__m128i*)&b[0 * stride], p1);
+ _mm_storeu_si128((__m128i*)&b[1 * stride], p0);
+ _mm_storeu_si128((__m128i*)&b[2 * stride], p3);
+ _mm_storeu_si128((__m128i*)&b[3 * stride], p2);
+
+ // rotate samples
+ p1 = tmp1;
+ p0 = tmp2;
}
}
-static void HFilter16iSSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
- uint8_t* b;
- __m128i mask;
- __m128i t1, t2, p1, p0, q0, q1;
+ __m128i p3, p2, p1, p0; // loop invariants
+
+ Load16x4(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
for (k = 3; k > 0; --k) {
- b = p;
- Load16x4(b, b + 8 * stride, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
- MAX_DIFF1(t2, t1, p1, p0, mask);
+ __m128i mask, tmp1, tmp2;
+ uint8_t* const b = p + 2; // beginning of p1
- b += 4; // beginning of q0
- Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
- MAX_DIFF2(t2, t1, q1, q0, mask);
+ p += 4; // beginning of q0 (and next span)
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
+ Load16x4(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
+ MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
- b -= 2; // beginning of p1
- Store16x4(b, b + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
- p += 4;
+ Store16x4(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
+
+ // rotate samples
+ p1 = tmp1;
+ p0 = tmp2;
}
}
// 8-pixels wide variant, for chroma filtering
-static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, p2, p1, p0, q0, q1, q2;
@@ -846,7 +869,7 @@ static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
@@ -858,8 +881,8 @@ static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
STOREUV(q2, u, v, 2 * stride);
}
-static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
@@ -871,15 +894,15 @@ static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
MAX_DIFF2(q3, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(tu, tv, stride, &p3, &p2, &p1, &p0);
- Store16x4(u, v, stride, &q0, &q1, &q2, &q3);
+ Store16x4(&p3, &p2, &p1, &p0, tu, tv, stride);
+ Store16x4(&q0, &q1, &q2, &q3, u, v, stride);
}
-static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
@@ -894,7 +917,7 @@ static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
MAX_DIFF2(t2, t1, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
// Store
@@ -904,8 +927,8 @@ static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
STOREUV(q1, u, v, 1 * stride);
}
-static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
@@ -916,12 +939,12 @@ static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
MAX_DIFF2(t2, t1, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
u -= 2; // beginning of p1
v -= 2;
- Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
+ Store16x4(&p1, &p0, &q0, &q1, u, v, stride);
}
#endif // WEBP_USE_SSE2
@@ -933,24 +956,23 @@ extern void VP8DspInitSSE2(void);
void VP8DspInitSSE2(void) {
#if defined(WEBP_USE_SSE2)
- VP8Transform = TransformSSE2;
+ VP8Transform = Transform;
#if defined(USE_TRANSFORM_AC3)
- VP8TransformAC3 = TransformAC3SSE2;
+ VP8TransformAC3 = TransformAC3;
#endif
- VP8VFilter16 = VFilter16SSE2;
- VP8HFilter16 = HFilter16SSE2;
- VP8VFilter8 = VFilter8SSE2;
- VP8HFilter8 = HFilter8SSE2;
- VP8VFilter16i = VFilter16iSSE2;
- VP8HFilter16i = HFilter16iSSE2;
- VP8VFilter8i = VFilter8iSSE2;
- VP8HFilter8i = HFilter8iSSE2;
-
- VP8SimpleVFilter16 = SimpleVFilter16SSE2;
- VP8SimpleHFilter16 = SimpleHFilter16SSE2;
- VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
- VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
#endif // WEBP_USE_SSE2
}
-
diff --git a/src/3rdparty/libwebp/src/dsp/dsp.h b/src/3rdparty/libwebp/src/dsp/dsp.h
index 3be783a..2409bae 100644
--- a/src/3rdparty/libwebp/src/dsp/dsp.h
+++ b/src/3rdparty/libwebp/src/dsp/dsp.h
@@ -14,6 +14,10 @@
#ifndef WEBP_DSP_DSP_H_
#define WEBP_DSP_DSP_H_
+#ifdef HAVE_CONFIG_H
+#include "../webp/config.h"
+#endif
+
#include "../webp/types.h"
#ifdef __cplusplus
@@ -23,27 +27,66 @@ extern "C" {
//------------------------------------------------------------------------------
// CPU detection
+#if defined(__GNUC__)
+# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
+# define LOCAL_GCC_PREREQ(maj, min) \
+ (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
+#else
+# define LOCAL_GCC_VERSION 0
+# define LOCAL_GCC_PREREQ(maj, min) 0
+#endif
+
+#ifdef __clang__
+# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
+# define LOCAL_CLANG_PREREQ(maj, min) \
+ (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
+#else
+# define LOCAL_CLANG_VERSION 0
+# define LOCAL_CLANG_PREREQ(maj, min) 0
+#endif // __clang__
+
#if defined(_MSC_VER) && _MSC_VER > 1310 && \
(defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif
-#if defined(__SSE2__) || defined(WEBP_MSC_SSE2)
+// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
+// files without intrinsics, allowing the corresponding Init() to be called.
+// Files containing intrinsics will need to be built targeting the instruction
+// set so should succeed on one of the earlier tests.
+#if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
#define WEBP_USE_SSE2
#endif
+#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
+#define WEBP_USE_AVX2
+#endif
+
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
#define WEBP_ANDROID_NEON // Android targets that might support NEON
#endif
-#if defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON)
+// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
+// inline assembly would need to be modified for use with Native Client.
+#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON) || \
+ defined(__aarch64__)) && !defined(__native_client__)
#define WEBP_USE_NEON
#endif
+#if defined(__mips__) && !defined(__mips64) && (__mips_isa_rev < 6)
+#define WEBP_USE_MIPS32
+#if (__mips_isa_rev >= 2)
+#define WEBP_USE_MIPS32_R2
+#endif
+#endif
+
typedef enum {
kSSE2,
kSSE3,
- kNEON
+ kAVX,
+ kAVX2,
+ kNEON,
+ kMIPS32
} CPUFeature;
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
@@ -61,7 +104,6 @@ typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out);
typedef void (*VP8WHT)(const int16_t* in, int16_t* out);
extern VP8Idct VP8ITransform;
extern VP8Fdct VP8FTransform;
-extern VP8WHT VP8ITransformWHT;
extern VP8WHT VP8FTransformWHT;
// Predictions
// *dst is the destination block. *top and *left can be NULL.
@@ -83,7 +125,7 @@ extern VP8BlockCopy VP8Copy4x4;
// Quantization
struct VP8Matrix; // forward declaration
typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
- int n, const struct VP8Matrix* const mtx);
+ const struct VP8Matrix* const mtx);
extern VP8QuantizeBlock VP8EncQuantizeBlock;
// specific to 2nd transform:
@@ -121,6 +163,13 @@ extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
+// clipping tables (for filtering)
+extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127]
+extern const int8_t* const VP8ksclip2; // clips [-112, 112] to [-16, 15]
+extern const uint8_t* const VP8kclip1; // clips [-255,511] to [0,255]
+extern const uint8_t* const VP8kabs0; // abs(x) for x in [-255,255]
+void VP8InitClipTables(void); // must be called first
+
// simple filter (only for luma)
typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
extern VP8SimpleFilterFunc VP8SimpleVFilter16;
@@ -166,21 +215,20 @@ typedef void (*WebPUpsampleLinePairFunc)(
// Fancy upsampling functions to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
-// Initializes SSE2 version of the fancy upsamplers.
-void WebPInitUpsamplersSSE2(void);
-
-// NEON version
-void WebPInitUpsamplersNEON(void);
-
#endif // FANCY_UPSAMPLING
-// Point-sampling methods.
-typedef void (*WebPSampleLinePairFunc)(
- const uint8_t* top_y, const uint8_t* bottom_y,
- const uint8_t* u, const uint8_t* v,
- uint8_t* top_dst, uint8_t* bottom_dst, int len);
+// Per-row point-sampling methods.
+typedef void (*WebPSamplerRowFunc)(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len);
+// Generic function to apply 'WebPSamplerRowFunc' to the whole plane:
+void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
+ const uint8_t* u, const uint8_t* v, int uv_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height, WebPSamplerRowFunc func);
-extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
+// Sampling functions to convert rows of YUV to RGB(A)
+extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */];
// General function for converting two lines of ARGB or RGBA.
// 'alpha_is_last' should be true if 0xff000000 is stored in memory as
@@ -194,11 +242,14 @@ typedef void (*WebPYUV444Converter)(const uint8_t* y,
extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
-// Main function to be called
+// Must be called before using the WebPUpsamplers[] (and for premultiplied
+// colorspaces like rgbA, rgbA4444, etc)
void WebPInitUpsamplers(void);
+// Must be called before using WebPSamplers[]
+void WebPInitSamplers(void);
//------------------------------------------------------------------------------
-// Pre-multiply planes with alpha values
+// Utilities for processing transparent channel.
// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
@@ -209,13 +260,34 @@ extern void (*WebPApplyAlphaMultiply)(
extern void (*WebPApplyAlphaMultiply4444)(
uint8_t* rgba4444, int w, int h, int stride);
-// To be called first before using the above.
-void WebPInitPremultiply(void);
+// Extract the alpha values from 32b values in argb[] and pack them into alpha[]
+// (this is the opposite of WebPDispatchAlpha).
+// Returns true if there's only trivial 0xff alpha values.
+extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride);
-void WebPInitPremultiplySSE2(void); // should not be called directly.
-void WebPInitPremultiplyNEON(void);
+// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
+// Un-Multiply operation transforms x into x * 255 / A.
-//------------------------------------------------------------------------------
+// Pre-Multiply or Un-Multiply (if 'inverse' is true) argb values in a row.
+extern void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
+
+// Same a WebPMultARGBRow(), but for several rows.
+void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
+ int inverse);
+
+// Same for a row of single values, with side alpha values.
+extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+
+// Same a WebPMultRow(), but for several 'num_rows' rows.
+void WebPMultRows(uint8_t* ptr, int stride,
+ const uint8_t* alpha, int alpha_stride,
+ int width, int num_rows, int inverse);
+
+// To be called first before using the above.
+void WebPInitAlphaProcessing(void);
#ifdef __cplusplus
} // extern "C"
diff --git a/src/3rdparty/libwebp/src/dsp/enc.c b/src/3rdparty/libwebp/src/dsp/enc.c
index fcc6ec8..f4e72d4 100644
--- a/src/3rdparty/libwebp/src/dsp/enc.c
+++ b/src/3rdparty/libwebp/src/dsp/enc.c
@@ -159,33 +159,6 @@ static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
}
}
-static void ITransformWHT(const int16_t* in, int16_t* out) {
- int tmp[16];
- int i;
- for (i = 0; i < 4; ++i) {
- const int a0 = in[0 + i] + in[12 + i];
- const int a1 = in[4 + i] + in[ 8 + i];
- const int a2 = in[4 + i] - in[ 8 + i];
- const int a3 = in[0 + i] - in[12 + i];
- tmp[0 + i] = a0 + a1;
- tmp[8 + i] = a0 - a1;
- tmp[4 + i] = a3 + a2;
- tmp[12 + i] = a3 - a2;
- }
- for (i = 0; i < 4; ++i) {
- const int dc = tmp[0 + i * 4] + 3; // w/ rounder
- const int a0 = dc + tmp[3 + i * 4];
- const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
- const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
- const int a3 = dc - tmp[3 + i * 4];
- out[ 0] = (a0 + a1) >> 3;
- out[16] = (a3 + a2) >> 3;
- out[32] = (a0 - a1) >> 3;
- out[48] = (a3 - a2) >> 3;
- out += 64;
- }
-}
-
static void FTransformWHT(const int16_t* in, int16_t* out) {
// input is 12b signed
int32_t tmp[16];
@@ -627,21 +600,23 @@ static const uint8_t kZigzag[16] = {
// Simple quantization
static int QuantizeBlock(int16_t in[16], int16_t out[16],
- int n, const VP8Matrix* const mtx) {
+ const VP8Matrix* const mtx) {
int last = -1;
- for (; n < 16; ++n) {
+ int n;
+ for (n = 0; n < 16; ++n) {
const int j = kZigzag[n];
const int sign = (in[j] < 0);
- const int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
if (coeff > mtx->zthresh_[j]) {
- const int Q = mtx->q_[j];
- const int iQ = mtx->iq_[j];
- const int B = mtx->bias_[j];
- out[n] = QUANTDIV(coeff, iQ, B);
- if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
- if (sign) out[n] = -out[n];
- in[j] = out[n] * Q;
- if (out[n]) last = n;
+ const uint32_t Q = mtx->q_[j];
+ const uint32_t iQ = mtx->iq_[j];
+ const uint32_t B = mtx->bias_[j];
+ int level = QUANTDIV(coeff, iQ, B);
+ if (level > MAX_LEVEL) level = MAX_LEVEL;
+ if (sign) level = -level;
+ in[j] = level * Q;
+ out[n] = level;
+ if (level) last = n;
} else {
out[n] = 0;
in[j] = 0;
@@ -656,17 +631,18 @@ static int QuantizeBlockWHT(int16_t in[16], int16_t out[16],
for (n = 0; n < 16; ++n) {
const int j = kZigzag[n];
const int sign = (in[j] < 0);
- const int coeff = sign ? -in[j] : in[j];
+ const uint32_t coeff = sign ? -in[j] : in[j];
assert(mtx->sharpen_[j] == 0);
if (coeff > mtx->zthresh_[j]) {
- const int Q = mtx->q_[j];
- const int iQ = mtx->iq_[j];
- const int B = mtx->bias_[j];
- out[n] = QUANTDIV(coeff, iQ, B);
- if (out[n] > MAX_LEVEL) out[n] = MAX_LEVEL;
- if (sign) out[n] = -out[n];
- in[j] = out[n] * Q;
- if (out[n]) last = n;
+ const uint32_t Q = mtx->q_[j];
+ const uint32_t iQ = mtx->iq_[j];
+ const uint32_t B = mtx->bias_[j];
+ int level = QUANTDIV(coeff, iQ, B);
+ if (level > MAX_LEVEL) level = MAX_LEVEL;
+ if (sign) level = -level;
+ in[j] = level * Q;
+ out[n] = level;
+ if (level) last = n;
} else {
out[n] = 0;
in[j] = 0;
@@ -697,7 +673,6 @@ static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
VP8CHisto VP8CollectHistogram;
VP8Idct VP8ITransform;
VP8Fdct VP8FTransform;
-VP8WHT VP8ITransformWHT;
VP8WHT VP8FTransformWHT;
VP8Intra4Preds VP8EncPredLuma4;
VP8IntraPreds VP8EncPredLuma16;
@@ -713,16 +688,23 @@ VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
VP8BlockCopy VP8Copy4x4;
extern void VP8EncDspInitSSE2(void);
+extern void VP8EncDspInitAVX2(void);
extern void VP8EncDspInitNEON(void);
+extern void VP8EncDspInitMIPS32(void);
+
+static volatile VP8CPUInfo enc_last_cpuinfo_used =
+ (VP8CPUInfo)&enc_last_cpuinfo_used;
void VP8EncDspInit(void) {
+ if (enc_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8DspInit(); // common inverse transforms
InitTables();
// default C implementations
VP8CollectHistogram = CollectHistogram;
VP8ITransform = ITransform;
VP8FTransform = FTransform;
- VP8ITransformWHT = ITransformWHT;
VP8FTransformWHT = FTransformWHT;
VP8EncPredLuma4 = Intra4Preds;
VP8EncPredLuma16 = Intra16Preds;
@@ -738,16 +720,28 @@ void VP8EncDspInit(void) {
VP8Copy4x4 = Copy4x4;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo) {
+ if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspInitSSE2();
}
-#elif defined(WEBP_USE_NEON)
+#endif
+#if defined(WEBP_USE_AVX2)
+ if (VP8GetCPUInfo(kAVX2)) {
+ VP8EncDspInitAVX2();
+ }
+#endif
+#if defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8EncDspInitNEON();
}
#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8EncDspInitMIPS32();
+ }
+#endif
}
+ enc_last_cpuinfo_used = VP8GetCPUInfo;
}
diff --git a/src/3rdparty/libwebp/src/dsp/enc_avx2.c b/src/3rdparty/libwebp/src/dsp/enc_avx2.c
new file mode 100644
index 0000000..372e616
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/enc_avx2.c
@@ -0,0 +1,24 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// AVX2 version of speed-critical encoding functions.
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_AVX2)
+
+#endif // WEBP_USE_AVX2
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitAVX2(void);
+
+void VP8EncDspInitAVX2(void) {
+}
diff --git a/src/3rdparty/libwebp/src/dsp/enc_mips32.c b/src/3rdparty/libwebp/src/dsp/enc_mips32.c
new file mode 100644
index 0000000..def9a16
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/enc_mips32.c
@@ -0,0 +1,776 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of speed-critical encoding functions.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+// Slobodan Prijic (slobodan.prijic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "../enc/vp8enci.h"
+#include "../enc/cost.h"
+
+#if defined(__GNUC__) && defined(__ANDROID__) && LOCAL_GCC_VERSION == 0x409
+#define WORK_AROUND_GCC
+#endif
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+// macro for one vertical pass in ITransformOne
+// MUL macro inlined
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to load from in buffer
+// TEMP0..TEMP3 - registers for corresponding tmp elements
+// TEMP4..TEMP5 - temporary registers
+#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
+ "lh %[temp16], "#A"(%[temp20]) \n\t" \
+ "lh %[temp18], "#B"(%[temp20]) \n\t" \
+ "lh %[temp17], "#C"(%[temp20]) \n\t" \
+ "lh %[temp19], "#D"(%[temp20]) \n\t" \
+ "addu %["#TEMP4"], %[temp16], %[temp18] \n\t" \
+ "subu %[temp16], %[temp16], %[temp18] \n\t" \
+ "mul %["#TEMP0"], %[temp17], %[kC2] \n\t" \
+ "mul %[temp18], %[temp19], %[kC1] \n\t" \
+ "mul %[temp17], %[temp17], %[kC1] \n\t" \
+ "mul %[temp19], %[temp19], %[kC2] \n\t" \
+ "sra %["#TEMP0"], %["#TEMP0"], 16 \n\n" \
+ "sra %[temp18], %[temp18], 16 \n\n" \
+ "sra %[temp17], %[temp17], 16 \n\n" \
+ "sra %[temp19], %[temp19], 16 \n\n" \
+ "subu %["#TEMP2"], %["#TEMP0"], %[temp18] \n\t" \
+ "addu %["#TEMP3"], %[temp17], %[temp19] \n\t" \
+ "addu %["#TEMP0"], %["#TEMP4"], %["#TEMP3"] \n\t" \
+ "addu %["#TEMP1"], %[temp16], %["#TEMP2"] \n\t" \
+ "subu %["#TEMP2"], %[temp16], %["#TEMP2"] \n\t" \
+ "subu %["#TEMP3"], %["#TEMP4"], %["#TEMP3"] \n\t"
+
+// macro for one horizontal pass in ITransformOne
+// MUL and STORE macros inlined
+// a = clip_8b(a) is replaced with: a = max(a, 0); a = min(a, 255)
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to load from ref and store to dst buffer
+// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \
+ "addiu %["#TEMP0"], %["#TEMP0"], 4 \n\t" \
+ "addu %[temp16], %["#TEMP0"], %["#TEMP8"] \n\t" \
+ "subu %[temp17], %["#TEMP0"], %["#TEMP8"] \n\t" \
+ "mul %["#TEMP0"], %["#TEMP4"], %[kC2] \n\t" \
+ "mul %["#TEMP8"], %["#TEMP12"], %[kC1] \n\t" \
+ "mul %["#TEMP4"], %["#TEMP4"], %[kC1] \n\t" \
+ "mul %["#TEMP12"], %["#TEMP12"], %[kC2] \n\t" \
+ "sra %["#TEMP0"], %["#TEMP0"], 16 \n\t" \
+ "sra %["#TEMP8"], %["#TEMP8"], 16 \n\t" \
+ "sra %["#TEMP4"], %["#TEMP4"], 16 \n\t" \
+ "sra %["#TEMP12"], %["#TEMP12"], 16 \n\t" \
+ "subu %[temp18], %["#TEMP0"], %["#TEMP8"] \n\t" \
+ "addu %[temp19], %["#TEMP4"], %["#TEMP12"] \n\t" \
+ "addu %["#TEMP0"], %[temp16], %[temp19] \n\t" \
+ "addu %["#TEMP4"], %[temp17], %[temp18] \n\t" \
+ "subu %["#TEMP8"], %[temp17], %[temp18] \n\t" \
+ "subu %["#TEMP12"], %[temp16], %[temp19] \n\t" \
+ "lw %[temp20], 0(%[args]) \n\t" \
+ "sra %["#TEMP0"], %["#TEMP0"], 3 \n\t" \
+ "sra %["#TEMP4"], %["#TEMP4"], 3 \n\t" \
+ "sra %["#TEMP8"], %["#TEMP8"], 3 \n\t" \
+ "sra %["#TEMP12"], %["#TEMP12"], 3 \n\t" \
+ "lbu %[temp16], "#A"(%[temp20]) \n\t" \
+ "lbu %[temp17], "#B"(%[temp20]) \n\t" \
+ "lbu %[temp18], "#C"(%[temp20]) \n\t" \
+ "lbu %[temp19], "#D"(%[temp20]) \n\t" \
+ "addu %["#TEMP0"], %[temp16], %["#TEMP0"] \n\t" \
+ "addu %["#TEMP4"], %[temp17], %["#TEMP4"] \n\t" \
+ "addu %["#TEMP8"], %[temp18], %["#TEMP8"] \n\t" \
+ "addu %["#TEMP12"], %[temp19], %["#TEMP12"] \n\t" \
+ "slt %[temp16], %["#TEMP0"], $zero \n\t" \
+ "slt %[temp17], %["#TEMP4"], $zero \n\t" \
+ "slt %[temp18], %["#TEMP8"], $zero \n\t" \
+ "slt %[temp19], %["#TEMP12"], $zero \n\t" \
+ "movn %["#TEMP0"], $zero, %[temp16] \n\t" \
+ "movn %["#TEMP4"], $zero, %[temp17] \n\t" \
+ "movn %["#TEMP8"], $zero, %[temp18] \n\t" \
+ "movn %["#TEMP12"], $zero, %[temp19] \n\t" \
+ "addiu %[temp20], $zero, 255 \n\t" \
+ "slt %[temp16], %["#TEMP0"], %[temp20] \n\t" \
+ "slt %[temp17], %["#TEMP4"], %[temp20] \n\t" \
+ "slt %[temp18], %["#TEMP8"], %[temp20] \n\t" \
+ "slt %[temp19], %["#TEMP12"], %[temp20] \n\t" \
+ "movz %["#TEMP0"], %[temp20], %[temp16] \n\t" \
+ "movz %["#TEMP4"], %[temp20], %[temp17] \n\t" \
+ "lw %[temp16], 8(%[args]) \n\t" \
+ "movz %["#TEMP8"], %[temp20], %[temp18] \n\t" \
+ "movz %["#TEMP12"], %[temp20], %[temp19] \n\t" \
+ "sb %["#TEMP0"], "#A"(%[temp16]) \n\t" \
+ "sb %["#TEMP4"], "#B"(%[temp16]) \n\t" \
+ "sb %["#TEMP8"], "#C"(%[temp16]) \n\t" \
+ "sb %["#TEMP12"], "#D"(%[temp16]) \n\t"
+
+// Does one or two inverse transforms.
+static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ int temp7, temp8, temp9, temp10, temp11, temp12, temp13;
+ int temp14, temp15, temp16, temp17, temp18, temp19, temp20;
+ const int* args[3] = {(const int*)ref, (const int*)in, (const int*)dst};
+
+ __asm__ volatile(
+ "lw %[temp20], 4(%[args]) \n\t"
+ VERTICAL_PASS(0, 16, 8, 24, temp4, temp0, temp1, temp2, temp3)
+ VERTICAL_PASS(2, 18, 10, 26, temp8, temp4, temp5, temp6, temp7)
+ VERTICAL_PASS(4, 20, 12, 28, temp12, temp8, temp9, temp10, temp11)
+ VERTICAL_PASS(6, 22, 14, 30, temp20, temp12, temp13, temp14, temp15)
+
+ HORIZONTAL_PASS( 0, 1, 2, 3, temp0, temp4, temp8, temp12)
+ HORIZONTAL_PASS(16, 17, 18, 19, temp1, temp5, temp9, temp13)
+ HORIZONTAL_PASS(32, 33, 34, 35, temp2, temp6, temp10, temp14)
+ HORIZONTAL_PASS(48, 49, 50, 51, temp3, temp7, temp11, temp15)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20)
+ : [args]"r"(args), [kC1]"r"(kC1), [kC2]"r"(kC2)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void ITransform(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst, int do_two) {
+ ITransformOne(ref, in, dst);
+ if (do_two) {
+ ITransformOne(ref + 4, in + 16, dst + 4);
+ }
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+// macro for one pass through for loop in QuantizeBlock
+// QUANTDIV macro inlined
+// J - offset in bytes (kZigzag[n] * 2)
+// K - offset in bytes (kZigzag[n] * 4)
+// N - offset in bytes (n * 2)
+#define QUANTIZE_ONE(J, K, N) \
+ "lh %[temp0], "#J"(%[ppin]) \n\t" \
+ "lhu %[temp1], "#J"(%[ppsharpen]) \n\t" \
+ "lw %[temp2], "#K"(%[ppzthresh]) \n\t" \
+ "sra %[sign], %[temp0], 15 \n\t" \
+ "xor %[coeff], %[temp0], %[sign] \n\t" \
+ "subu %[coeff], %[coeff], %[sign] \n\t" \
+ "addu %[coeff], %[coeff], %[temp1] \n\t" \
+ "slt %[temp4], %[temp2], %[coeff] \n\t" \
+ "addiu %[temp5], $zero, 0 \n\t" \
+ "addiu %[level], $zero, 0 \n\t" \
+ "beqz %[temp4], 2f \n\t" \
+ "lhu %[temp1], "#J"(%[ppiq]) \n\t" \
+ "lw %[temp2], "#K"(%[ppbias]) \n\t" \
+ "lhu %[temp3], "#J"(%[ppq]) \n\t" \
+ "mul %[level], %[coeff], %[temp1] \n\t" \
+ "addu %[level], %[level], %[temp2] \n\t" \
+ "sra %[level], %[level], 17 \n\t" \
+ "slt %[temp4], %[max_level], %[level] \n\t" \
+ "movn %[level], %[max_level], %[temp4] \n\t" \
+ "xor %[level], %[level], %[sign] \n\t" \
+ "subu %[level], %[level], %[sign] \n\t" \
+ "mul %[temp5], %[level], %[temp3] \n\t" \
+"2: \n\t" \
+ "sh %[temp5], "#J"(%[ppin]) \n\t" \
+ "sh %[level], "#N"(%[pout]) \n\t"
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ int sign, coeff, level, i;
+ int max_level = MAX_LEVEL;
+
+ int16_t* ppin = &in[0];
+ int16_t* pout = &out[0];
+ const uint16_t* ppsharpen = &mtx->sharpen_[0];
+ const uint32_t* ppzthresh = &mtx->zthresh_[0];
+ const uint16_t* ppq = &mtx->q_[0];
+ const uint16_t* ppiq = &mtx->iq_[0];
+ const uint32_t* ppbias = &mtx->bias_[0];
+
+ __asm__ volatile(
+ QUANTIZE_ONE( 0, 0, 0)
+ QUANTIZE_ONE( 2, 4, 2)
+ QUANTIZE_ONE( 8, 16, 4)
+ QUANTIZE_ONE(16, 32, 6)
+ QUANTIZE_ONE(10, 20, 8)
+ QUANTIZE_ONE( 4, 8, 10)
+ QUANTIZE_ONE( 6, 12, 12)
+ QUANTIZE_ONE(12, 24, 14)
+ QUANTIZE_ONE(18, 36, 16)
+ QUANTIZE_ONE(24, 48, 18)
+ QUANTIZE_ONE(26, 52, 20)
+ QUANTIZE_ONE(20, 40, 22)
+ QUANTIZE_ONE(14, 28, 24)
+ QUANTIZE_ONE(22, 44, 26)
+ QUANTIZE_ONE(28, 56, 28)
+ QUANTIZE_ONE(30, 60, 30)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [sign]"=&r"(sign), [coeff]"=&r"(coeff),
+ [level]"=&r"(level)
+ : [pout]"r"(pout), [ppin]"r"(ppin),
+ [ppiq]"r"(ppiq), [max_level]"r"(max_level),
+ [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh),
+ [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq)
+ : "memory", "hi", "lo"
+ );
+
+ // moved out from macro to increase possibility for earlier breaking
+ for (i = 15; i >= 0; i--) {
+ if (out[i]) return 1;
+ }
+ return 0;
+}
+
+#undef QUANTIZE_ONE
+
+// macro for one horizontal pass in Disto4x4 (TTransform)
+// two calls of function TTransform are merged into single one
+// A..D - offsets in bytes to load from a and b buffers
+// E..H - offsets in bytes to store first results to tmp buffer
+// E1..H1 - offsets in bytes to store second results to tmp buffer
+#define HORIZONTAL_PASS(A, B, C, D, E, F, G, H, E1, F1, G1, H1) \
+ "lbu %[temp0], "#A"(%[a]) \n\t" \
+ "lbu %[temp1], "#B"(%[a]) \n\t" \
+ "lbu %[temp2], "#C"(%[a]) \n\t" \
+ "lbu %[temp3], "#D"(%[a]) \n\t" \
+ "lbu %[temp4], "#A"(%[b]) \n\t" \
+ "lbu %[temp5], "#B"(%[b]) \n\t" \
+ "lbu %[temp6], "#C"(%[b]) \n\t" \
+ "lbu %[temp7], "#D"(%[b]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "addu %[temp2], %[temp1], %[temp3] \n\t" \
+ "subu %[temp1], %[temp1], %[temp3] \n\t" \
+ "addu %[temp3], %[temp4], %[temp6] \n\t" \
+ "subu %[temp4], %[temp4], %[temp6] \n\t" \
+ "addu %[temp6], %[temp5], %[temp7] \n\t" \
+ "subu %[temp5], %[temp5], %[temp7] \n\t" \
+ "addu %[temp7], %[temp8], %[temp2] \n\t" \
+ "subu %[temp2], %[temp8], %[temp2] \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp3], %[temp6] \n\t" \
+ "subu %[temp3], %[temp3], %[temp6] \n\t" \
+ "addu %[temp6], %[temp4], %[temp5] \n\t" \
+ "subu %[temp4], %[temp4], %[temp5] \n\t" \
+ "sw %[temp7], "#E"(%[tmp]) \n\t" \
+ "sw %[temp2], "#H"(%[tmp]) \n\t" \
+ "sw %[temp8], "#F"(%[tmp]) \n\t" \
+ "sw %[temp0], "#G"(%[tmp]) \n\t" \
+ "sw %[temp1], "#E1"(%[tmp]) \n\t" \
+ "sw %[temp3], "#H1"(%[tmp]) \n\t" \
+ "sw %[temp6], "#F1"(%[tmp]) \n\t" \
+ "sw %[temp4], "#G1"(%[tmp]) \n\t"
+
+// macro for one vertical pass in Disto4x4 (TTransform)
+// two calls of function TTransform are merged into single one
+// since only one accu is available in mips32r1 instruction set
+// first is done second call of function TTransform and after
+// that first one.
+// const int sum1 = TTransform(a, w);
+// const int sum2 = TTransform(b, w);
+// return abs(sum2 - sum1) >> 5;
+// (sum2 - sum1) is calculated with madds (sub2) and msubs (sub1)
+// A..D - offsets in bytes to load first results from tmp buffer
+// A1..D1 - offsets in bytes to load second results from tmp buffer
+// E..H - offsets in bytes to load from w buffer
+#define VERTICAL_PASS(A, B, C, D, A1, B1, C1, D1, E, F, G, H) \
+ "lw %[temp0], "#A1"(%[tmp]) \n\t" \
+ "lw %[temp1], "#C1"(%[tmp]) \n\t" \
+ "lw %[temp2], "#B1"(%[tmp]) \n\t" \
+ "lw %[temp3], "#D1"(%[tmp]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp2], %[temp3] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "addu %[temp3], %[temp8], %[temp1] \n\t" \
+ "subu %[temp8], %[temp8], %[temp1] \n\t" \
+ "addu %[temp1], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "sra %[temp4], %[temp3], 31 \n\t" \
+ "sra %[temp5], %[temp1], 31 \n\t" \
+ "sra %[temp6], %[temp0], 31 \n\t" \
+ "sra %[temp7], %[temp8], 31 \n\t" \
+ "xor %[temp3], %[temp3], %[temp4] \n\t" \
+ "xor %[temp1], %[temp1], %[temp5] \n\t" \
+ "xor %[temp0], %[temp0], %[temp6] \n\t" \
+ "xor %[temp8], %[temp8], %[temp7] \n\t" \
+ "subu %[temp3], %[temp3], %[temp4] \n\t" \
+ "subu %[temp1], %[temp1], %[temp5] \n\t" \
+ "subu %[temp0], %[temp0], %[temp6] \n\t" \
+ "subu %[temp8], %[temp8], %[temp7] \n\t" \
+ "lhu %[temp4], "#E"(%[w]) \n\t" \
+ "lhu %[temp5], "#F"(%[w]) \n\t" \
+ "lhu %[temp6], "#G"(%[w]) \n\t" \
+ "lhu %[temp7], "#H"(%[w]) \n\t" \
+ "madd %[temp4], %[temp3] \n\t" \
+ "madd %[temp5], %[temp1] \n\t" \
+ "madd %[temp6], %[temp0] \n\t" \
+ "madd %[temp7], %[temp8] \n\t" \
+ "lw %[temp0], "#A"(%[tmp]) \n\t" \
+ "lw %[temp1], "#C"(%[tmp]) \n\t" \
+ "lw %[temp2], "#B"(%[tmp]) \n\t" \
+ "lw %[temp3], "#D"(%[tmp]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp2], %[temp3] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "addu %[temp3], %[temp8], %[temp1] \n\t" \
+ "subu %[temp1], %[temp8], %[temp1] \n\t" \
+ "addu %[temp8], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "sra %[temp2], %[temp3], 31 \n\t" \
+ "xor %[temp3], %[temp3], %[temp2] \n\t" \
+ "subu %[temp3], %[temp3], %[temp2] \n\t" \
+ "msub %[temp4], %[temp3] \n\t" \
+ "sra %[temp2], %[temp8], 31 \n\t" \
+ "sra %[temp3], %[temp0], 31 \n\t" \
+ "sra %[temp4], %[temp1], 31 \n\t" \
+ "xor %[temp8], %[temp8], %[temp2] \n\t" \
+ "xor %[temp0], %[temp0], %[temp3] \n\t" \
+ "xor %[temp1], %[temp1], %[temp4] \n\t" \
+ "subu %[temp8], %[temp8], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp3] \n\t" \
+ "subu %[temp1], %[temp1], %[temp4] \n\t" \
+ "msub %[temp5], %[temp8] \n\t" \
+ "msub %[temp6], %[temp0] \n\t" \
+ "msub %[temp7], %[temp1] \n\t"
+
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int tmp[32];
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+
+ __asm__ volatile(
+ HORIZONTAL_PASS( 0, 1, 2, 3, 0, 4, 8, 12, 64, 68, 72, 76)
+ HORIZONTAL_PASS(16, 17, 18, 19, 16, 20, 24, 28, 80, 84, 88, 92)
+ HORIZONTAL_PASS(32, 33, 34, 35, 32, 36, 40, 44, 96, 100, 104, 108)
+ HORIZONTAL_PASS(48, 49, 50, 51, 48, 52, 56, 60, 112, 116, 120, 124)
+ "mthi $zero \n\t"
+ "mtlo $zero \n\t"
+ VERTICAL_PASS( 0, 16, 32, 48, 64, 80, 96, 112, 0, 8, 16, 24)
+ VERTICAL_PASS( 4, 20, 36, 52, 68, 84, 100, 116, 2, 10, 18, 26)
+ VERTICAL_PASS( 8, 24, 40, 56, 72, 88, 104, 120, 4, 12, 20, 28)
+ VERTICAL_PASS(12, 28, 44, 60, 76, 92, 108, 124, 6, 14, 22, 30)
+ "mflo %[temp0] \n\t"
+ "sra %[temp1], %[temp0], 31 \n\t"
+ "xor %[temp0], %[temp0], %[temp1] \n\t"
+ "subu %[temp0], %[temp0], %[temp1] \n\t"
+ "sra %[temp0], %[temp0], 5 \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8)
+ : [a]"r"(a), [b]"r"(b), [w]"r"(w), [tmp]"r"(tmp)
+ : "memory", "hi", "lo"
+ );
+
+ return temp0;
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+// macro for one horizontal pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to load from src and ref buffers
+// TEMP0..TEMP3 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS(A, B, C, D, TEMP0, TEMP1, TEMP2, TEMP3) \
+ "lw %["#TEMP1"], 0(%[args]) \n\t" \
+ "lw %["#TEMP2"], 4(%[args]) \n\t" \
+ "lbu %[temp16], "#A"(%["#TEMP1"]) \n\t" \
+ "lbu %[temp17], "#A"(%["#TEMP2"]) \n\t" \
+ "lbu %[temp18], "#B"(%["#TEMP1"]) \n\t" \
+ "lbu %[temp19], "#B"(%["#TEMP2"]) \n\t" \
+ "subu %[temp20], %[temp16], %[temp17] \n\t" \
+ "lbu %[temp16], "#C"(%["#TEMP1"]) \n\t" \
+ "lbu %[temp17], "#C"(%["#TEMP2"]) \n\t" \
+ "subu %["#TEMP0"], %[temp18], %[temp19] \n\t" \
+ "lbu %[temp18], "#D"(%["#TEMP1"]) \n\t" \
+ "lbu %[temp19], "#D"(%["#TEMP2"]) \n\t" \
+ "subu %["#TEMP1"], %[temp16], %[temp17] \n\t" \
+ "subu %["#TEMP2"], %[temp18], %[temp19] \n\t" \
+ "addu %["#TEMP3"], %[temp20], %["#TEMP2"] \n\t" \
+ "subu %["#TEMP2"], %[temp20], %["#TEMP2"] \n\t" \
+ "addu %[temp20], %["#TEMP0"], %["#TEMP1"] \n\t" \
+ "subu %["#TEMP0"], %["#TEMP0"], %["#TEMP1"] \n\t" \
+ "mul %[temp16], %["#TEMP2"], %[c5352] \n\t" \
+ "mul %[temp17], %["#TEMP2"], %[c2217] \n\t" \
+ "mul %[temp18], %["#TEMP0"], %[c5352] \n\t" \
+ "mul %[temp19], %["#TEMP0"], %[c2217] \n\t" \
+ "addu %["#TEMP1"], %["#TEMP3"], %[temp20] \n\t" \
+ "subu %[temp20], %["#TEMP3"], %[temp20] \n\t" \
+ "sll %["#TEMP0"], %["#TEMP1"], 3 \n\t" \
+ "sll %["#TEMP2"], %[temp20], 3 \n\t" \
+ "addiu %[temp16], %[temp16], 1812 \n\t" \
+ "addiu %[temp17], %[temp17], 937 \n\t" \
+ "addu %[temp16], %[temp16], %[temp19] \n\t" \
+ "subu %[temp17], %[temp17], %[temp18] \n\t" \
+ "sra %["#TEMP1"], %[temp16], 9 \n\t" \
+ "sra %["#TEMP3"], %[temp17], 9 \n\t"
+
+// macro for one vertical pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to store to out buffer
+// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
+#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \
+ "addu %[temp16], %["#TEMP0"], %["#TEMP12"] \n\t" \
+ "subu %[temp19], %["#TEMP0"], %["#TEMP12"] \n\t" \
+ "addu %[temp17], %["#TEMP4"], %["#TEMP8"] \n\t" \
+ "subu %[temp18], %["#TEMP4"], %["#TEMP8"] \n\t" \
+ "mul %["#TEMP8"], %[temp19], %[c2217] \n\t" \
+ "mul %["#TEMP12"], %[temp18], %[c2217] \n\t" \
+ "mul %["#TEMP4"], %[temp19], %[c5352] \n\t" \
+ "mul %[temp18], %[temp18], %[c5352] \n\t" \
+ "addiu %[temp16], %[temp16], 7 \n\t" \
+ "addu %["#TEMP0"], %[temp16], %[temp17] \n\t" \
+ "sra %["#TEMP0"], %["#TEMP0"], 4 \n\t" \
+ "addu %["#TEMP12"], %["#TEMP12"], %["#TEMP4"] \n\t" \
+ "subu %["#TEMP4"], %[temp16], %[temp17] \n\t" \
+ "sra %["#TEMP4"], %["#TEMP4"], 4 \n\t" \
+ "addiu %["#TEMP8"], %["#TEMP8"], 30000 \n\t" \
+ "addiu %["#TEMP12"], %["#TEMP12"], 12000 \n\t" \
+ "addiu %["#TEMP8"], %["#TEMP8"], 21000 \n\t" \
+ "subu %["#TEMP8"], %["#TEMP8"], %[temp18] \n\t" \
+ "sra %["#TEMP12"], %["#TEMP12"], 16 \n\t" \
+ "sra %["#TEMP8"], %["#TEMP8"], 16 \n\t" \
+ "addiu %[temp16], %["#TEMP12"], 1 \n\t" \
+ "movn %["#TEMP12"], %[temp16], %[temp19] \n\t" \
+ "sh %["#TEMP0"], "#A"(%[temp20]) \n\t" \
+ "sh %["#TEMP4"], "#C"(%[temp20]) \n\t" \
+ "sh %["#TEMP8"], "#D"(%[temp20]) \n\t" \
+ "sh %["#TEMP12"], "#B"(%[temp20]) \n\t"
+
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16;
+ int temp17, temp18, temp19, temp20;
+ const int c2217 = 2217;
+ const int c5352 = 5352;
+ const int* const args[3] =
+ { (const int*)src, (const int*)ref, (const int*)out };
+
+ __asm__ volatile(
+ HORIZONTAL_PASS( 0, 1, 2, 3, temp0, temp1, temp2, temp3)
+ HORIZONTAL_PASS(16, 17, 18, 19, temp4, temp5, temp6, temp7)
+ HORIZONTAL_PASS(32, 33, 34, 35, temp8, temp9, temp10, temp11)
+ HORIZONTAL_PASS(48, 49, 50, 51, temp12, temp13, temp14, temp15)
+ "lw %[temp20], 8(%[args]) \n\t"
+ VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12)
+ VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13)
+ VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14)
+ VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20)
+ : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352)
+ : "memory", "hi", "lo"
+ );
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+// Forward declaration.
+extern int VP8GetResidualCostMIPS32(int ctx0, const VP8Residual* const res);
+
+int VP8GetResidualCostMIPS32(int ctx0, const VP8Residual* const res) {
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ int p0 = res->prob[n][ctx0][0];
+ const uint16_t* t = res->cost[n][ctx0];
+ int cost;
+ const int const_2 = 2;
+ const int const_255 = 255;
+ const int const_max_level = MAX_VARIABLE_LEVEL;
+ int res_cost;
+ int res_prob;
+ int res_coeffs;
+ int res_last;
+ int v_reg;
+ int b_reg;
+ int ctx_reg;
+ int cost_add, temp_1, temp_2, temp_3;
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+
+ cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+
+ res_cost = (int)res->cost;
+ res_prob = (int)res->prob;
+ res_coeffs = (int)res->coeffs;
+ res_last = (int)res->last;
+
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+
+ "sll %[temp_1], %[n], 1 \n\t"
+ "addu %[res_coeffs], %[res_coeffs], %[temp_1] \n\t"
+ "slt %[temp_2], %[n], %[res_last] \n\t"
+ "bnez %[temp_2], 1f \n\t"
+ " li %[cost_add], 0 \n\t"
+ "b 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lh %[v_reg], 0(%[res_coeffs]) \n\t"
+ "addu %[b_reg], %[n], %[VP8EncBands] \n\t"
+ "move %[temp_1], %[const_max_level] \n\t"
+ "addu %[cost], %[cost], %[cost_add] \n\t"
+ "negu %[temp_2], %[v_reg] \n\t"
+ "slti %[temp_3], %[v_reg], 0 \n\t"
+ "movn %[v_reg], %[temp_2], %[temp_3] \n\t"
+ "lbu %[b_reg], 1(%[b_reg]) \n\t"
+ "li %[cost_add], 0 \n\t"
+
+ "sltiu %[temp_3], %[v_reg], 2 \n\t"
+ "move %[ctx_reg], %[v_reg] \n\t"
+ "movz %[ctx_reg], %[const_2], %[temp_3] \n\t"
+ // cost += VP8LevelCost(t, v);
+ "slt %[temp_3], %[v_reg], %[const_max_level] \n\t"
+ "movn %[temp_1], %[v_reg], %[temp_3] \n\t"
+ "sll %[temp_2], %[v_reg], 1 \n\t"
+ "addu %[temp_2], %[temp_2], %[VP8LevelFixedCosts] \n\t"
+ "lhu %[temp_2], 0(%[temp_2]) \n\t"
+ "sll %[temp_1], %[temp_1], 1 \n\t"
+ "addu %[temp_1], %[temp_1], %[t] \n\t"
+ "lhu %[temp_3], 0(%[temp_1]) \n\t"
+ "addu %[cost], %[cost], %[temp_2] \n\t"
+
+ // t = res->cost[b][ctx];
+ "sll %[temp_1], %[ctx_reg], 7 \n\t"
+ "sll %[temp_2], %[ctx_reg], 3 \n\t"
+ "addu %[cost], %[cost], %[temp_3] \n\t"
+ "addu %[temp_1], %[temp_1], %[temp_2] \n\t"
+ "sll %[temp_2], %[b_reg], 3 \n\t"
+ "sll %[temp_3], %[b_reg], 5 \n\t"
+ "sub %[temp_2], %[temp_3], %[temp_2] \n\t"
+ "sll %[temp_3], %[temp_2], 4 \n\t"
+ "addu %[temp_1], %[temp_1], %[temp_3] \n\t"
+ "addu %[temp_2], %[temp_2], %[res_cost] \n\t"
+ "addiu %[n], %[n], 1 \n\t"
+ "addu %[t], %[temp_1], %[temp_2] \n\t"
+ "slt %[temp_1], %[n], %[res_last] \n\t"
+ "bnez %[temp_1], 1b \n\t"
+ " addiu %[res_coeffs], %[res_coeffs], 2 \n\t"
+ "2: \n\t"
+
+ ".set pop \n\t"
+ : [cost]"+r"(cost), [t]"+r"(t), [n]"+r"(n), [v_reg]"=&r"(v_reg),
+ [ctx_reg]"=&r"(ctx_reg), [b_reg]"=&r"(b_reg), [cost_add]"=&r"(cost_add),
+ [temp_1]"=&r"(temp_1), [temp_2]"=&r"(temp_2), [temp_3]"=&r"(temp_3)
+ : [const_2]"r"(const_2), [const_255]"r"(const_255), [res_last]"r"(res_last),
+ [VP8EntropyCost]"r"(VP8EntropyCost), [VP8EncBands]"r"(VP8EncBands),
+ [const_max_level]"r"(const_max_level), [res_prob]"r"(res_prob),
+ [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_coeffs]"r"(res_coeffs),
+ [res_cost]"r"(res_cost)
+ : "memory"
+ );
+
+ // Last coefficient is always non-zero
+ {
+ const int v = abs(res->coeffs[n]);
+ assert(v != 0);
+ cost += VP8LevelCost(t, v);
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = (v == 1) ? 1 : 2;
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
+#define GET_SSE_INNER(A, B, C, D) \
+ "lbu %[temp0], "#A"(%[a]) \n\t" \
+ "lbu %[temp1], "#A"(%[b]) \n\t" \
+ "lbu %[temp2], "#B"(%[a]) \n\t" \
+ "lbu %[temp3], "#B"(%[b]) \n\t" \
+ "lbu %[temp4], "#C"(%[a]) \n\t" \
+ "lbu %[temp5], "#C"(%[b]) \n\t" \
+ "lbu %[temp6], "#D"(%[a]) \n\t" \
+ "lbu %[temp7], "#D"(%[b]) \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "subu %[temp4], %[temp4], %[temp5] \n\t" \
+ "subu %[temp6], %[temp6], %[temp7] \n\t" \
+ "madd %[temp0], %[temp0] \n\t" \
+ "madd %[temp2], %[temp2] \n\t" \
+ "madd %[temp4], %[temp4] \n\t" \
+ "madd %[temp6], %[temp6] \n\t"
+
+#define GET_SSE(A, B, C, D) \
+ GET_SSE_INNER(A, A + 1, A + 2, A + 3) \
+ GET_SSE_INNER(B, B + 1, B + 2, B + 3) \
+ GET_SSE_INNER(C, C + 1, C + 2, C + 3) \
+ GET_SSE_INNER(D, D + 1, D + 2, D + 3)
+
+#if !defined(WORK_AROUND_GCC)
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE( 0, 4, 8, 12)
+ GET_SSE( 16, 20, 24, 28)
+ GET_SSE( 32, 36, 40, 44)
+ GET_SSE( 48, 52, 56, 60)
+ GET_SSE( 64, 68, 72, 76)
+ GET_SSE( 80, 84, 88, 92)
+ GET_SSE( 96, 100, 104, 108)
+ GET_SSE(112, 116, 120, 124)
+ GET_SSE(128, 132, 136, 140)
+ GET_SSE(144, 148, 152, 156)
+ GET_SSE(160, 164, 168, 172)
+ GET_SSE(176, 180, 184, 188)
+ GET_SSE(192, 196, 200, 204)
+ GET_SSE(208, 212, 216, 220)
+ GET_SSE(224, 228, 232, 236)
+ GET_SSE(240, 244, 248, 252)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi" , "lo"
+ );
+ return count;
+}
+
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE( 0, 4, 8, 12)
+ GET_SSE( 16, 20, 24, 28)
+ GET_SSE( 32, 36, 40, 44)
+ GET_SSE( 48, 52, 56, 60)
+ GET_SSE( 64, 68, 72, 76)
+ GET_SSE( 80, 84, 88, 92)
+ GET_SSE( 96, 100, 104, 108)
+ GET_SSE(112, 116, 120, 124)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi" , "lo"
+ );
+ return count;
+}
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE( 0, 4, 16, 20)
+ GET_SSE(32, 36, 48, 52)
+ GET_SSE(64, 68, 80, 84)
+ GET_SSE(96, 100, 112, 116)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi" , "lo"
+ );
+ return count;
+}
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE(0, 16, 32, 48)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi" , "lo"
+ );
+ return count;
+}
+
+#endif // WORK_AROUND_GCC
+
+#undef GET_SSE_MIPS32
+#undef GET_SSE_MIPS32_INNER
+
+#endif // WEBP_USE_MIPS32
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitMIPS32(void);
+
+void VP8EncDspInitMIPS32(void) {
+#if defined(WEBP_USE_MIPS32)
+ VP8ITransform = ITransform;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+ VP8FTransform = FTransform;
+#if !defined(WORK_AROUND_GCC)
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE4x4 = SSE4x4;
+#endif
+#endif // WEBP_USE_MIPS32
+}
diff --git a/src/3rdparty/libwebp/src/dsp/enc_neon.c b/src/3rdparty/libwebp/src/dsp/enc_neon.c
index 52cca18..5814fac 100644
--- a/src/3rdparty/libwebp/src/dsp/enc_neon.c
+++ b/src/3rdparty/libwebp/src/dsp/enc_neon.c
@@ -15,18 +15,122 @@
#if defined(WEBP_USE_NEON)
+#include <assert.h>
+
+#include "./neon.h"
#include "../enc/vp8enci.h"
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
// Inverse transform.
-// This code is pretty much the same as TransformOneNEON in the decoder, except
+// This code is pretty much the same as TransformOne in the dec_neon.c, except
// for subtraction to *ref. See the comments there for algorithmic explanations.
+
+static const int16_t kC1 = 20091;
+static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+
+// This code works but is *slower* than the inlined-asm version below
+// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to
+// USE_INTRINSICS define.
+// With gcc-4.8, it's a little faster speed than inlined-assembly.
+#if defined(USE_INTRINSICS)
+
+// Treats 'v' as an uint8x8_t and zero extends to an int16x8_t.
+static WEBP_INLINE int16x8_t ConvertU8ToS16(uint32x2_t v) {
+ return vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(v)));
+}
+
+// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result
+// to the corresponding rows of 'dst'.
+static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
+ const int16x8_t dst01,
+ const int16x8_t dst23) {
+ // Unsigned saturate to 8b.
+ const uint8x8_t dst01_u8 = vqmovun_s16(dst01);
+ const uint8x8_t dst23_u8 = vqmovun_s16(dst23);
+
+ // Store the results.
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1);
+}
+
+static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
+ const uint8_t* const ref, uint8_t* const dst) {
+ uint32x2_t dst01 = vdup_n_u32(0);
+ uint32x2_t dst23 = vdup_n_u32(0);
+
+ // Load the source pixels.
+ dst01 = vld1_lane_u32((uint32_t*)(ref + 0 * BPS), dst01, 0);
+ dst23 = vld1_lane_u32((uint32_t*)(ref + 2 * BPS), dst23, 0);
+ dst01 = vld1_lane_u32((uint32_t*)(ref + 1 * BPS), dst01, 1);
+ dst23 = vld1_lane_u32((uint32_t*)(ref + 3 * BPS), dst23, 1);
+
+ {
+ // Convert to 16b.
+ const int16x8_t dst01_s16 = ConvertU8ToS16(dst01);
+ const int16x8_t dst23_s16 = ConvertU8ToS16(dst23);
+
+ // Descale with rounding.
+ const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3);
+ const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3);
+ // Add the inverse transform.
+ SaturateAndStore4x4(dst, out01, out23);
+ }
+}
+
+static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
+ int16x8x2_t* const out) {
+ // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1
+ // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3
+ const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ...
+ // b0 d0 b1 d1 b2 d2 ...
+ *out = vzipq_s16(tmp0.val[0], tmp0.val[1]);
+}
+
+static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
+ // {rows} = in0 | in4
+ // in8 | in12
+ // B1 = in4 | in12
+ const int16x8_t B1 =
+ vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1]));
+ // C0 = kC1 * in4 | kC1 * in12
+ // C1 = kC2 * in4 | kC2 * in12
+ const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1);
+ const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2);
+ const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 + in8
+ const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 - in8
+ // c = kC2 * in4 - kC1 * in12
+ // d = kC1 * in4 + kC2 * in12
+ const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0));
+ const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1));
+ const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b
+ const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c
+ const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c
+ const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c
+ const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp));
+ Transpose8x2(E0, E1, rows);
+}
+
+static void ITransformOne(const uint8_t* ref,
+ const int16_t* in, uint8_t* dst) {
+ int16x8x2_t rows;
+ INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8));
+ TransformPass(&rows);
+ TransformPass(&rows);
+ Add4x4(rows.val[0], rows.val[1], ref, dst);
+}
+
+#else
+
static void ITransformOne(const uint8_t* ref,
const int16_t* in, uint8_t* dst) {
const int kBPS = BPS;
- const int16_t kC1C2[] = { 20091, 17734, 0, 0 }; // kC1 / (kC2 >> 1) / 0 / 0
+ const int16_t kC1C2[] = { kC1, kC2, 0, 0 };
__asm__ volatile (
"vld1.16 {q1, q2}, [%[in]] \n"
@@ -137,6 +241,8 @@ static void ITransformOne(const uint8_t* ref,
);
}
+#endif // USE_INTRINSICS
+
static void ITransform(const uint8_t* ref,
const int16_t* in, uint8_t* dst, int do_two) {
ITransformOne(ref, in, dst);
@@ -145,76 +251,102 @@ static void ITransform(const uint8_t* ref,
}
}
-// Same code as dec_neon.c
-static void ITransformWHT(const int16_t* in, int16_t* out) {
- const int kStep = 32; // The store is only incrementing the pointer as if we
- // had stored a single byte.
- __asm__ volatile (
- // part 1
- // load data into q0, q1
- "vld1.16 {q0, q1}, [%[in]] \n"
-
- "vaddl.s16 q2, d0, d3 \n" // a0 = in[0] + in[12]
- "vaddl.s16 q3, d1, d2 \n" // a1 = in[4] + in[8]
- "vsubl.s16 q4, d1, d2 \n" // a2 = in[4] - in[8]
- "vsubl.s16 q5, d0, d3 \n" // a3 = in[0] - in[12]
-
- "vadd.s32 q0, q2, q3 \n" // tmp[0] = a0 + a1
- "vsub.s32 q2, q2, q3 \n" // tmp[8] = a0 - a1
- "vadd.s32 q1, q5, q4 \n" // tmp[4] = a3 + a2
- "vsub.s32 q3, q5, q4 \n" // tmp[12] = a3 - a2
-
- // Transpose
- // q0 = tmp[0, 4, 8, 12], q1 = tmp[2, 6, 10, 14]
- // q2 = tmp[1, 5, 9, 13], q3 = tmp[3, 7, 11, 15]
- "vswp d1, d4 \n" // vtrn.64 q0, q2
- "vswp d3, d6 \n" // vtrn.64 q1, q3
- "vtrn.32 q0, q1 \n"
- "vtrn.32 q2, q3 \n"
-
- "vmov.s32 q4, #3 \n" // dc = 3
- "vadd.s32 q0, q0, q4 \n" // dc = tmp[0] + 3
- "vadd.s32 q6, q0, q3 \n" // a0 = dc + tmp[3]
- "vadd.s32 q7, q1, q2 \n" // a1 = tmp[1] + tmp[2]
- "vsub.s32 q8, q1, q2 \n" // a2 = tmp[1] - tmp[2]
- "vsub.s32 q9, q0, q3 \n" // a3 = dc - tmp[3]
-
- "vadd.s32 q0, q6, q7 \n"
- "vshrn.s32 d0, q0, #3 \n" // (a0 + a1) >> 3
- "vadd.s32 q1, q9, q8 \n"
- "vshrn.s32 d1, q1, #3 \n" // (a3 + a2) >> 3
- "vsub.s32 q2, q6, q7 \n"
- "vshrn.s32 d2, q2, #3 \n" // (a0 - a1) >> 3
- "vsub.s32 q3, q9, q8 \n"
- "vshrn.s32 d3, q3, #3 \n" // (a3 - a2) >> 3
-
- // set the results to output
- "vst1.16 d0[0], [%[out]], %[kStep] \n"
- "vst1.16 d1[0], [%[out]], %[kStep] \n"
- "vst1.16 d2[0], [%[out]], %[kStep] \n"
- "vst1.16 d3[0], [%[out]], %[kStep] \n"
- "vst1.16 d0[1], [%[out]], %[kStep] \n"
- "vst1.16 d1[1], [%[out]], %[kStep] \n"
- "vst1.16 d2[1], [%[out]], %[kStep] \n"
- "vst1.16 d3[1], [%[out]], %[kStep] \n"
- "vst1.16 d0[2], [%[out]], %[kStep] \n"
- "vst1.16 d1[2], [%[out]], %[kStep] \n"
- "vst1.16 d2[2], [%[out]], %[kStep] \n"
- "vst1.16 d3[2], [%[out]], %[kStep] \n"
- "vst1.16 d0[3], [%[out]], %[kStep] \n"
- "vst1.16 d1[3], [%[out]], %[kStep] \n"
- "vst1.16 d2[3], [%[out]], %[kStep] \n"
- "vst1.16 d3[3], [%[out]], %[kStep] \n"
-
- : [out] "+r"(out) // modified registers
- : [in] "r"(in), [kStep] "r"(kStep) // constants
- : "memory", "q0", "q1", "q2", "q3", "q4",
- "q5", "q6", "q7", "q8", "q9" // clobbered
- );
+// Load all 4x4 pixels into a single uint8x16_t variable.
+static uint8x16_t Load4x4(const uint8_t* src) {
+ uint32x4_t out = vdupq_n_u32(0);
+ out = vld1q_lane_u32((const uint32_t*)(src + 0 * BPS), out, 0);
+ out = vld1q_lane_u32((const uint32_t*)(src + 1 * BPS), out, 1);
+ out = vld1q_lane_u32((const uint32_t*)(src + 2 * BPS), out, 2);
+ out = vld1q_lane_u32((const uint32_t*)(src + 3 * BPS), out, 3);
+ return vreinterpretq_u8_u32(out);
}
// Forward transform.
+#if defined(USE_INTRINSICS)
+
+static WEBP_INLINE void Transpose4x4_S16(const int16x4_t A, const int16x4_t B,
+ const int16x4_t C, const int16x4_t D,
+ int16x8_t* const out01,
+ int16x8_t* const out32) {
+ const int16x4x2_t AB = vtrn_s16(A, B);
+ const int16x4x2_t CD = vtrn_s16(C, D);
+ const int32x2x2_t tmp02 = vtrn_s32(vreinterpret_s32_s16(AB.val[0]),
+ vreinterpret_s32_s16(CD.val[0]));
+ const int32x2x2_t tmp13 = vtrn_s32(vreinterpret_s32_s16(AB.val[1]),
+ vreinterpret_s32_s16(CD.val[1]));
+ *out01 = vreinterpretq_s16_s64(
+ vcombine_s64(vreinterpret_s64_s32(tmp02.val[0]),
+ vreinterpret_s64_s32(tmp13.val[0])));
+ *out32 = vreinterpretq_s16_s64(
+ vcombine_s64(vreinterpret_s64_s32(tmp13.val[1]),
+ vreinterpret_s64_s32(tmp02.val[1])));
+}
+
+static WEBP_INLINE int16x8_t DiffU8ToS16(const uint8x8_t a,
+ const uint8x8_t b) {
+ return vreinterpretq_s16_u16(vsubl_u8(a, b));
+}
+
+static void FTransform(const uint8_t* src, const uint8_t* ref,
+ int16_t* out) {
+ int16x8_t d0d1, d3d2; // working 4x4 int16 variables
+ {
+ const uint8x16_t S0 = Load4x4(src);
+ const uint8x16_t R0 = Load4x4(ref);
+ const int16x8_t D0D1 = DiffU8ToS16(vget_low_u8(S0), vget_low_u8(R0));
+ const int16x8_t D2D3 = DiffU8ToS16(vget_high_u8(S0), vget_high_u8(R0));
+ const int16x4_t D0 = vget_low_s16(D0D1);
+ const int16x4_t D1 = vget_high_s16(D0D1);
+ const int16x4_t D2 = vget_low_s16(D2D3);
+ const int16x4_t D3 = vget_high_s16(D2D3);
+ Transpose4x4_S16(D0, D1, D2, D3, &d0d1, &d3d2);
+ }
+ { // 1rst pass
+ const int32x4_t kCst937 = vdupq_n_s32(937);
+ const int32x4_t kCst1812 = vdupq_n_s32(1812);
+ const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1)
+ const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2)
+ const int16x8_t a0a1_2 = vshlq_n_s16(a0a1, 3);
+ const int16x4_t tmp0 = vadd_s16(vget_low_s16(a0a1_2),
+ vget_high_s16(a0a1_2));
+ const int16x4_t tmp2 = vsub_s16(vget_low_s16(a0a1_2),
+ vget_high_s16(a0a1_2));
+ const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217);
+ const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217);
+ const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352);
+ const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352);
+ const int16x4_t tmp1 = vshrn_n_s32(vaddq_s32(a2_p_a3, kCst1812), 9);
+ const int16x4_t tmp3 = vshrn_n_s32(vaddq_s32(a3_m_a2, kCst937), 9);
+ Transpose4x4_S16(tmp0, tmp1, tmp2, tmp3, &d0d1, &d3d2);
+ }
+ { // 2nd pass
+ // the (1<<16) addition is for the replacement: a3!=0 <-> 1-(a3==0)
+ const int32x4_t kCst12000 = vdupq_n_s32(12000 + (1 << 16));
+ const int32x4_t kCst51000 = vdupq_n_s32(51000);
+ const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1)
+ const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2)
+ const int16x4_t a0_k7 = vadd_s16(vget_low_s16(a0a1), vdup_n_s16(7));
+ const int16x4_t out0 = vshr_n_s16(vadd_s16(a0_k7, vget_high_s16(a0a1)), 4);
+ const int16x4_t out2 = vshr_n_s16(vsub_s16(a0_k7, vget_high_s16(a0a1)), 4);
+ const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217);
+ const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217);
+ const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352);
+ const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352);
+ const int16x4_t tmp1 = vaddhn_s32(a2_p_a3, kCst12000);
+ const int16x4_t out3 = vaddhn_s32(a3_m_a2, kCst51000);
+ const int16x4_t a3_eq_0 =
+ vreinterpret_s16_u16(vceq_s16(vget_low_s16(a3a2), vdup_n_s16(0)));
+ const int16x4_t out1 = vadd_s16(tmp1, a3_eq_0);
+ vst1_s16(out + 0, out0);
+ vst1_s16(out + 4, out1);
+ vst1_s16(out + 8, out2);
+ vst1_s16(out + 12, out3);
+ }
+}
+
+#else
+
// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm
static const int16_t kCoeff16[] = {
5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217
@@ -339,69 +471,76 @@ static void FTransform(const uint8_t* src, const uint8_t* ref,
);
}
-static void FTransformWHT(const int16_t* in, int16_t* out) {
- const int kStep = 32;
- __asm__ volatile (
- // d0 = in[0 * 16] , d1 = in[1 * 16]
- // d2 = in[2 * 16] , d3 = in[3 * 16]
- "vld1.16 d0[0], [%[in]], %[kStep] \n"
- "vld1.16 d1[0], [%[in]], %[kStep] \n"
- "vld1.16 d2[0], [%[in]], %[kStep] \n"
- "vld1.16 d3[0], [%[in]], %[kStep] \n"
- "vld1.16 d0[1], [%[in]], %[kStep] \n"
- "vld1.16 d1[1], [%[in]], %[kStep] \n"
- "vld1.16 d2[1], [%[in]], %[kStep] \n"
- "vld1.16 d3[1], [%[in]], %[kStep] \n"
- "vld1.16 d0[2], [%[in]], %[kStep] \n"
- "vld1.16 d1[2], [%[in]], %[kStep] \n"
- "vld1.16 d2[2], [%[in]], %[kStep] \n"
- "vld1.16 d3[2], [%[in]], %[kStep] \n"
- "vld1.16 d0[3], [%[in]], %[kStep] \n"
- "vld1.16 d1[3], [%[in]], %[kStep] \n"
- "vld1.16 d2[3], [%[in]], %[kStep] \n"
- "vld1.16 d3[3], [%[in]], %[kStep] \n"
-
- "vaddl.s16 q2, d0, d2 \n" // a0=(in[0*16]+in[2*16])
- "vaddl.s16 q3, d1, d3 \n" // a1=(in[1*16]+in[3*16])
- "vsubl.s16 q4, d1, d3 \n" // a2=(in[1*16]-in[3*16])
- "vsubl.s16 q5, d0, d2 \n" // a3=(in[0*16]-in[2*16])
-
- "vqadd.s32 q6, q2, q3 \n" // a0 + a1
- "vqadd.s32 q7, q5, q4 \n" // a3 + a2
- "vqsub.s32 q8, q5, q4 \n" // a3 - a2
- "vqsub.s32 q9, q2, q3 \n" // a0 - a1
-
- // Transpose
- // q6 = tmp[0, 1, 2, 3] ; q7 = tmp[ 4, 5, 6, 7]
- // q8 = tmp[8, 9, 10, 11] ; q9 = tmp[12, 13, 14, 15]
- "vswp d13, d16 \n" // vtrn.64 q0, q2
- "vswp d15, d18 \n" // vtrn.64 q1, q3
- "vtrn.32 q6, q7 \n"
- "vtrn.32 q8, q9 \n"
-
- "vqadd.s32 q0, q6, q8 \n" // a0 = tmp[0] + tmp[8]
- "vqadd.s32 q1, q7, q9 \n" // a1 = tmp[4] + tmp[12]
- "vqsub.s32 q2, q7, q9 \n" // a2 = tmp[4] - tmp[12]
- "vqsub.s32 q3, q6, q8 \n" // a3 = tmp[0] - tmp[8]
-
- "vqadd.s32 q4, q0, q1 \n" // b0 = a0 + a1
- "vqadd.s32 q5, q3, q2 \n" // b1 = a3 + a2
- "vqsub.s32 q6, q3, q2 \n" // b2 = a3 - a2
- "vqsub.s32 q7, q0, q1 \n" // b3 = a0 - a1
-
- "vshrn.s32 d18, q4, #1 \n" // b0 >> 1
- "vshrn.s32 d19, q5, #1 \n" // b1 >> 1
- "vshrn.s32 d20, q6, #1 \n" // b2 >> 1
- "vshrn.s32 d21, q7, #1 \n" // b3 >> 1
-
- "vst1.16 {q9, q10}, [%[out]] \n"
-
- : [in] "+r"(in)
- : [kStep] "r"(kStep), [out] "r"(out)
- : "memory", "q0", "q1", "q2", "q3", "q4", "q5",
- "q6", "q7", "q8", "q9", "q10" // clobbered
- ) ;
+#endif
+
+#define LOAD_LANE_16b(VALUE, LANE) do { \
+ (VALUE) = vld1_lane_s16(src, (VALUE), (LANE)); \
+ src += stride; \
+} while (0)
+
+static void FTransformWHT(const int16_t* src, int16_t* out) {
+ const int stride = 16;
+ const int16x4_t zero = vdup_n_s16(0);
+ int32x4x4_t tmp0;
+ int16x4x4_t in;
+ INIT_VECTOR4(in, zero, zero, zero, zero);
+ LOAD_LANE_16b(in.val[0], 0);
+ LOAD_LANE_16b(in.val[1], 0);
+ LOAD_LANE_16b(in.val[2], 0);
+ LOAD_LANE_16b(in.val[3], 0);
+ LOAD_LANE_16b(in.val[0], 1);
+ LOAD_LANE_16b(in.val[1], 1);
+ LOAD_LANE_16b(in.val[2], 1);
+ LOAD_LANE_16b(in.val[3], 1);
+ LOAD_LANE_16b(in.val[0], 2);
+ LOAD_LANE_16b(in.val[1], 2);
+ LOAD_LANE_16b(in.val[2], 2);
+ LOAD_LANE_16b(in.val[3], 2);
+ LOAD_LANE_16b(in.val[0], 3);
+ LOAD_LANE_16b(in.val[1], 3);
+ LOAD_LANE_16b(in.val[2], 3);
+ LOAD_LANE_16b(in.val[3], 3);
+
+ {
+ // a0 = in[0 * 16] + in[2 * 16]
+ // a1 = in[1 * 16] + in[3 * 16]
+ // a2 = in[1 * 16] - in[3 * 16]
+ // a3 = in[0 * 16] - in[2 * 16]
+ const int32x4_t a0 = vaddl_s16(in.val[0], in.val[2]);
+ const int32x4_t a1 = vaddl_s16(in.val[1], in.val[3]);
+ const int32x4_t a2 = vsubl_s16(in.val[1], in.val[3]);
+ const int32x4_t a3 = vsubl_s16(in.val[0], in.val[2]);
+ tmp0.val[0] = vaddq_s32(a0, a1);
+ tmp0.val[1] = vaddq_s32(a3, a2);
+ tmp0.val[2] = vsubq_s32(a3, a2);
+ tmp0.val[3] = vsubq_s32(a0, a1);
+ }
+ {
+ const int32x4x4_t tmp1 = Transpose4x4(tmp0);
+ // a0 = tmp[0 + i] + tmp[ 8 + i]
+ // a1 = tmp[4 + i] + tmp[12 + i]
+ // a2 = tmp[4 + i] - tmp[12 + i]
+ // a3 = tmp[0 + i] - tmp[ 8 + i]
+ const int32x4_t a0 = vaddq_s32(tmp1.val[0], tmp1.val[2]);
+ const int32x4_t a1 = vaddq_s32(tmp1.val[1], tmp1.val[3]);
+ const int32x4_t a2 = vsubq_s32(tmp1.val[1], tmp1.val[3]);
+ const int32x4_t a3 = vsubq_s32(tmp1.val[0], tmp1.val[2]);
+ const int32x4_t b0 = vhaddq_s32(a0, a1); // (a0 + a1) >> 1
+ const int32x4_t b1 = vhaddq_s32(a3, a2); // (a3 + a2) >> 1
+ const int32x4_t b2 = vhsubq_s32(a3, a2); // (a3 - a2) >> 1
+ const int32x4_t b3 = vhsubq_s32(a0, a1); // (a0 - a1) >> 1
+ const int16x4_t out0 = vmovn_s32(b0);
+ const int16x4_t out1 = vmovn_s32(b1);
+ const int16x4_t out2 = vmovn_s32(b2);
+ const int16x4_t out3 = vmovn_s32(b3);
+
+ vst1_s16(out + 0, out0);
+ vst1_s16(out + 4, out1);
+ vst1_s16(out + 8, out2);
+ vst1_s16(out + 12, out3);
+ }
}
+#undef LOAD_LANE_16b
//------------------------------------------------------------------------------
// Texture distortion
@@ -409,9 +548,136 @@ static void FTransformWHT(const int16_t* in, int16_t* out) {
// We try to match the spectral content (weighted) between source and
// reconstructed samples.
+// This code works but is *slower* than the inlined-asm version below
+// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to
+// USE_INTRINSICS define.
+// With gcc-4.8, it's only slightly slower than the inlined.
+#if defined(USE_INTRINSICS)
+
+// Zero extend an uint16x4_t 'v' to an int32x4_t.
+static WEBP_INLINE int32x4_t ConvertU16ToS32(uint16x4_t v) {
+ return vreinterpretq_s32_u32(vmovl_u16(v));
+}
+
+// Does a regular 4x4 transpose followed by an adjustment of the upper columns
+// in the inner rows to restore the source order of differences,
+// i.e., a0 - a1 | a3 - a2.
+static WEBP_INLINE int32x4x4_t DistoTranspose4x4(const int32x4x4_t rows) {
+ int32x4x4_t out = Transpose4x4(rows);
+ // restore source order in the columns containing differences.
+ const int32x2_t r1h = vget_high_s32(out.val[1]);
+ const int32x2_t r2h = vget_high_s32(out.val[2]);
+ out.val[1] = vcombine_s32(vget_low_s32(out.val[1]), r2h);
+ out.val[2] = vcombine_s32(vget_low_s32(out.val[2]), r1h);
+ return out;
+}
+
+static WEBP_INLINE int32x4x4_t DistoHorizontalPass(const uint8x8_t r0r1,
+ const uint8x8_t r2r3) {
+ // a0 = in[0] + in[2] | a1 = in[1] + in[3]
+ const uint16x8_t a0a1 = vaddl_u8(r0r1, r2r3);
+ // a3 = in[0] - in[2] | a2 = in[1] - in[3]
+ const uint16x8_t a3a2 = vsubl_u8(r0r1, r2r3);
+ const int32x4_t tmp0 = vpaddlq_s16(vreinterpretq_s16_u16(a0a1)); // a0 + a1
+ const int32x4_t tmp1 = vpaddlq_s16(vreinterpretq_s16_u16(a3a2)); // a3 + a2
+ // no pairwise subtraction; reorder to perform tmp[2]/tmp[3] calculations.
+ // a0a0 a3a3 a0a0 a3a3 a0a0 a3a3 a0a0 a3a3
+ // a1a1 a2a2 a1a1 a2a2 a1a1 a2a2 a1a1 a2a2
+ const int16x8x2_t transpose =
+ vtrnq_s16(vreinterpretq_s16_u16(a0a1), vreinterpretq_s16_u16(a3a2));
+ // tmp[3] = a0 - a1 | tmp[2] = a3 - a2
+ const int32x4_t tmp32_1 = vsubl_s16(vget_low_s16(transpose.val[0]),
+ vget_low_s16(transpose.val[1]));
+ const int32x4_t tmp32_2 = vsubl_s16(vget_high_s16(transpose.val[0]),
+ vget_high_s16(transpose.val[1]));
+ // [0]: tmp[3] [1]: tmp[2]
+ const int32x4x2_t split = vtrnq_s32(tmp32_1, tmp32_2);
+ const int32x4x4_t res = { { tmp0, tmp1, split.val[1], split.val[0] } };
+ return res;
+}
+
+static WEBP_INLINE int32x4x4_t DistoVerticalPass(const int32x4x4_t rows) {
+ // a0 = tmp[0 + i] + tmp[8 + i];
+ const int32x4_t a0 = vaddq_s32(rows.val[0], rows.val[1]);
+ // a1 = tmp[4 + i] + tmp[12+ i];
+ const int32x4_t a1 = vaddq_s32(rows.val[2], rows.val[3]);
+ // a2 = tmp[4 + i] - tmp[12+ i];
+ const int32x4_t a2 = vsubq_s32(rows.val[2], rows.val[3]);
+ // a3 = tmp[0 + i] - tmp[8 + i];
+ const int32x4_t a3 = vsubq_s32(rows.val[0], rows.val[1]);
+ const int32x4_t b0 = vqabsq_s32(vaddq_s32(a0, a1)); // abs(a0 + a1)
+ const int32x4_t b1 = vqabsq_s32(vaddq_s32(a3, a2)); // abs(a3 + a2)
+ const int32x4_t b2 = vabdq_s32(a3, a2); // abs(a3 - a2)
+ const int32x4_t b3 = vabdq_s32(a0, a1); // abs(a0 - a1)
+ const int32x4x4_t res = { { b0, b1, b2, b3 } };
+ return res;
+}
+
+// Calculate the weighted sum of the rows in 'b'.
+static WEBP_INLINE int64x1_t DistoSum(const int32x4x4_t b,
+ const int32x4_t w0, const int32x4_t w1,
+ const int32x4_t w2, const int32x4_t w3) {
+ const int32x4_t s0 = vmulq_s32(w0, b.val[0]);
+ const int32x4_t s1 = vmlaq_s32(s0, w1, b.val[1]);
+ const int32x4_t s2 = vmlaq_s32(s1, w2, b.val[2]);
+ const int32x4_t s3 = vmlaq_s32(s2, w3, b.val[3]);
+ const int64x2_t sum1 = vpaddlq_s32(s3);
+ const int64x1_t sum2 = vadd_s64(vget_low_s64(sum1), vget_high_s64(sum1));
+ return sum2;
+}
+
+#define LOAD_LANE_32b(src, VALUE, LANE) \
+ (VALUE) = vld1q_lane_u32((const uint32_t*)(src), (VALUE), (LANE))
+
+// Hadamard transform
+// Returns the weighted sum of the absolute value of transformed coefficients.
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ uint32x4_t d0d1 = { 0, 0, 0, 0 };
+ uint32x4_t d2d3 = { 0, 0, 0, 0 };
+ LOAD_LANE_32b(a + 0 * BPS, d0d1, 0); // a00 a01 a02 a03
+ LOAD_LANE_32b(a + 1 * BPS, d0d1, 1); // a10 a11 a12 a13
+ LOAD_LANE_32b(b + 0 * BPS, d0d1, 2); // b00 b01 b02 b03
+ LOAD_LANE_32b(b + 1 * BPS, d0d1, 3); // b10 b11 b12 b13
+ LOAD_LANE_32b(a + 2 * BPS, d2d3, 0); // a20 a21 a22 a23
+ LOAD_LANE_32b(a + 3 * BPS, d2d3, 1); // a30 a31 a32 a33
+ LOAD_LANE_32b(b + 2 * BPS, d2d3, 2); // b20 b21 b22 b23
+ LOAD_LANE_32b(b + 3 * BPS, d2d3, 3); // b30 b31 b32 b33
+
+ {
+ // a00 a01 a20 a21 a10 a11 a30 a31 b00 b01 b20 b21 b10 b11 b30 b31
+ // a02 a03 a22 a23 a12 a13 a32 a33 b02 b03 b22 b23 b12 b13 b32 b33
+ const uint16x8x2_t tmp =
+ vtrnq_u16(vreinterpretq_u16_u32(d0d1), vreinterpretq_u16_u32(d2d3));
+ const uint8x16_t d0d1u8 = vreinterpretq_u8_u16(tmp.val[0]);
+ const uint8x16_t d2d3u8 = vreinterpretq_u8_u16(tmp.val[1]);
+ const int32x4x4_t hpass_a = DistoHorizontalPass(vget_low_u8(d0d1u8),
+ vget_low_u8(d2d3u8));
+ const int32x4x4_t hpass_b = DistoHorizontalPass(vget_high_u8(d0d1u8),
+ vget_high_u8(d2d3u8));
+ const int32x4x4_t tmp_a = DistoTranspose4x4(hpass_a);
+ const int32x4x4_t tmp_b = DistoTranspose4x4(hpass_b);
+ const int32x4x4_t vpass_a = DistoVerticalPass(tmp_a);
+ const int32x4x4_t vpass_b = DistoVerticalPass(tmp_b);
+ const int32x4_t w0 = ConvertU16ToS32(vld1_u16(w + 0));
+ const int32x4_t w1 = ConvertU16ToS32(vld1_u16(w + 4));
+ const int32x4_t w2 = ConvertU16ToS32(vld1_u16(w + 8));
+ const int32x4_t w3 = ConvertU16ToS32(vld1_u16(w + 12));
+ const int64x1_t sum1 = DistoSum(vpass_a, w0, w1, w2, w3);
+ const int64x1_t sum2 = DistoSum(vpass_b, w0, w1, w2, w3);
+ const int32x2_t diff = vabd_s32(vreinterpret_s32_s64(sum1),
+ vreinterpret_s32_s64(sum2));
+ const int32x2_t res = vshr_n_s32(diff, 5);
+ return vget_lane_s32(res, 0);
+ }
+}
+
+#undef LOAD_LANE_32b
+
+#else
+
// Hadamard transform
// Returns the weighted sum of the absolute value of transformed coefficients.
-// This uses a TTransform helper function in C
static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
const int kBPS = BPS;
@@ -598,6 +864,8 @@ static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
return sum;
}
+#endif // USE_INTRINSICS
+
static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
int D = 0;
@@ -610,6 +878,179 @@ static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
return D;
}
+//------------------------------------------------------------------------------
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ const uint16x8_t max_coeff_thresh = vdupq_n_u16(MAX_COEFF_THRESH);
+ int j;
+ for (j = start_block; j < end_block; ++j) {
+ int16_t out[16];
+ FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+ {
+ int k;
+ const int16x8_t a0 = vld1q_s16(out + 0);
+ const int16x8_t b0 = vld1q_s16(out + 8);
+ const uint16x8_t a1 = vreinterpretq_u16_s16(vabsq_s16(a0));
+ const uint16x8_t b1 = vreinterpretq_u16_s16(vabsq_s16(b0));
+ const uint16x8_t a2 = vshrq_n_u16(a1, 3);
+ const uint16x8_t b2 = vshrq_n_u16(b1, 3);
+ const uint16x8_t a3 = vminq_u16(a2, max_coeff_thresh);
+ const uint16x8_t b3 = vminq_u16(b2, max_coeff_thresh);
+ vst1q_s16(out + 0, vreinterpretq_s16_u16(a3));
+ vst1q_s16(out + 8, vreinterpretq_s16_u16(b3));
+ // Convert coefficients to bin.
+ for (k = 0; k < 16; ++k) {
+ histo->distribution[out[k]]++;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE void AccumulateSSE16(const uint8_t* const a,
+ const uint8_t* const b,
+ uint32x4_t* const sum) {
+ const uint8x16_t a0 = vld1q_u8(a);
+ const uint8x16_t b0 = vld1q_u8(b);
+ const uint8x16_t abs_diff = vabdq_u8(a0, b0);
+ uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff));
+ prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff));
+ *sum = vpadalq_u16(*sum, prod); // pair-wise add and accumulate
+}
+
+// Horizontal sum of all four uint32_t values in 'sum'.
+static int SumToInt(uint32x4_t sum) {
+ const uint64x2_t sum2 = vpaddlq_u32(sum);
+ const uint64_t sum3 = vgetq_lane_u64(sum2, 0) + vgetq_lane_u64(sum2, 1);
+ return (int)sum3;
+}
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 16; ++y) {
+ AccumulateSSE16(a + y * BPS, b + y * BPS, &sum);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 8; ++y) {
+ AccumulateSSE16(a + y * BPS, b + y * BPS, &sum);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 8; ++y) {
+ const uint8x8_t a0 = vld1_u8(a + y * BPS);
+ const uint8x8_t b0 = vld1_u8(b + y * BPS);
+ const uint8x8_t abs_diff = vabd_u8(a0, b0);
+ const uint16x8_t prod = vmull_u8(abs_diff, abs_diff);
+ sum = vpadalq_u16(sum, prod);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ const uint8x16_t a0 = Load4x4(a);
+ const uint8x16_t b0 = Load4x4(b);
+ const uint8x16_t abs_diff = vabdq_u8(a0, b0);
+ uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff));
+ prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff));
+ return SumToInt(vpaddlq_u16(prod));
+}
+
+//------------------------------------------------------------------------------
+
+// Compilation with gcc-4.6.x is problematic for now.
+#if !defined(WORK_AROUND_GCC)
+
+static int16x8_t Quantize(int16_t* const in,
+ const VP8Matrix* const mtx, int offset) {
+ const uint16x8_t sharp = vld1q_u16(&mtx->sharpen_[offset]);
+ const uint16x8_t q = vld1q_u16(&mtx->q_[offset]);
+ const uint16x8_t iq = vld1q_u16(&mtx->iq_[offset]);
+ const uint32x4_t bias0 = vld1q_u32(&mtx->bias_[offset + 0]);
+ const uint32x4_t bias1 = vld1q_u32(&mtx->bias_[offset + 4]);
+
+ const int16x8_t a = vld1q_s16(in + offset); // in
+ const uint16x8_t b = vreinterpretq_u16_s16(vabsq_s16(a)); // coeff = abs(in)
+ const int16x8_t sign = vshrq_n_s16(a, 15); // sign
+ const uint16x8_t c = vaddq_u16(b, sharp); // + sharpen
+ const uint32x4_t m0 = vmull_u16(vget_low_u16(c), vget_low_u16(iq));
+ const uint32x4_t m1 = vmull_u16(vget_high_u16(c), vget_high_u16(iq));
+ const uint32x4_t m2 = vhaddq_u32(m0, bias0);
+ const uint32x4_t m3 = vhaddq_u32(m1, bias1); // (coeff * iQ + bias) >> 1
+ const uint16x8_t c0 = vcombine_u16(vshrn_n_u32(m2, 16),
+ vshrn_n_u32(m3, 16)); // QFIX=17 = 16+1
+ const uint16x8_t c1 = vminq_u16(c0, vdupq_n_u16(MAX_LEVEL));
+ const int16x8_t c2 = veorq_s16(vreinterpretq_s16_u16(c1), sign);
+ const int16x8_t c3 = vsubq_s16(c2, sign); // restore sign
+ const int16x8_t c4 = vmulq_s16(c3, vreinterpretq_s16_u16(q));
+ vst1q_s16(in + offset, c4);
+ assert(QFIX == 17); // this function can't work as is if QFIX != 16+1
+ return c3;
+}
+
+static const uint8_t kShuffles[4][8] = {
+ { 0, 1, 2, 3, 8, 9, 16, 17 },
+ { 10, 11, 4, 5, 6, 7, 12, 13 },
+ { 18, 19, 24, 25, 26, 27, 20, 21 },
+ { 14, 15, 22, 23, 28, 29, 30, 31 }
+};
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ const int16x8_t out0 = Quantize(in, mtx, 0);
+ const int16x8_t out1 = Quantize(in, mtx, 8);
+ uint8x8x4_t shuffles;
+ // vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
+ // non-standard versions there.
+#if defined(__APPLE__) && defined(__aarch64__) && \
+ defined(__apple_build_version__) && (__apple_build_version__< 6020037)
+ uint8x16x2_t all_out;
+ INIT_VECTOR2(all_out, vreinterpretq_u8_s16(out0), vreinterpretq_u8_s16(out1));
+ INIT_VECTOR4(shuffles,
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[0])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[1])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[2])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[3])));
+#else
+ uint8x8x4_t all_out;
+ INIT_VECTOR4(all_out,
+ vreinterpret_u8_s16(vget_low_s16(out0)),
+ vreinterpret_u8_s16(vget_high_s16(out0)),
+ vreinterpret_u8_s16(vget_low_s16(out1)),
+ vreinterpret_u8_s16(vget_high_s16(out1)));
+ INIT_VECTOR4(shuffles,
+ vtbl4_u8(all_out, vld1_u8(kShuffles[0])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[1])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[2])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[3])));
+#endif
+ // Zigzag reordering
+ vst1_u8((uint8_t*)(out + 0), shuffles.val[0]);
+ vst1_u8((uint8_t*)(out + 4), shuffles.val[1]);
+ vst1_u8((uint8_t*)(out + 8), shuffles.val[2]);
+ vst1_u8((uint8_t*)(out + 12), shuffles.val[3]);
+ // test zeros
+ if (*(uint64_t*)(out + 0) != 0) return 1;
+ if (*(uint64_t*)(out + 4) != 0) return 1;
+ if (*(uint64_t*)(out + 8) != 0) return 1;
+ if (*(uint64_t*)(out + 12) != 0) return 1;
+ return 0;
+}
+
+#endif // !WORK_AROUND_GCC
+
#endif // WEBP_USE_NEON
//------------------------------------------------------------------------------
@@ -622,11 +1063,17 @@ void VP8EncDspInitNEON(void) {
VP8ITransform = ITransform;
VP8FTransform = FTransform;
- VP8ITransformWHT = ITransformWHT;
VP8FTransformWHT = FTransformWHT;
VP8TDisto4x4 = Disto4x4;
VP8TDisto16x16 = Disto16x16;
+ VP8CollectHistogram = CollectHistogram;
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE4x4 = SSE4x4;
+#if !defined(WORK_AROUND_GCC)
+ VP8EncQuantizeBlock = QuantizeBlock;
+#endif
#endif // WEBP_USE_NEON
}
-
diff --git a/src/3rdparty/libwebp/src/dsp/enc_sse2.c b/src/3rdparty/libwebp/src/dsp/enc_sse2.c
index 540a3cb..9958d9f 100644
--- a/src/3rdparty/libwebp/src/dsp/enc_sse2.c
+++ b/src/3rdparty/libwebp/src/dsp/enc_sse2.c
@@ -17,7 +17,9 @@
#include <stdlib.h> // for abs()
#include <emmintrin.h>
+#include "../enc/cost.h"
#include "../enc/vp8enci.h"
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Quite useful macro for debugging. Left here for convenience.
@@ -52,9 +54,9 @@ static void PrintReg(const __m128i r, const char* const name, int size) {
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
-static void CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
- int start_block, int end_block,
- VP8Histogram* const histo) {
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
int j;
for (j = start_block; j < end_block; ++j) {
@@ -98,8 +100,8 @@ static void CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
// Transforms (Paragraph 14.4)
// Does one or two inverse transforms.
-static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
- int do_two) {
+static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -318,8 +320,7 @@ static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
}
}
-static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
- int16_t* out) {
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i seven = _mm_set1_epi16(7);
const __m128i k937 = _mm_set1_epi32(937);
@@ -444,14 +445,14 @@ static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
// -> f1 = f1 + 1 - (a3 == 0)
const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
- _mm_storel_epi64((__m128i*)&out[ 0], d0);
- _mm_storel_epi64((__m128i*)&out[ 4], g1);
- _mm_storel_epi64((__m128i*)&out[ 8], d2);
- _mm_storel_epi64((__m128i*)&out[12], f3);
+ const __m128i d0_g1 = _mm_unpacklo_epi64(d0, g1);
+ const __m128i d2_f3 = _mm_unpacklo_epi64(d2, f3);
+ _mm_storeu_si128((__m128i*)&out[0], d0_g1);
+ _mm_storeu_si128((__m128i*)&out[8], d2_f3);
}
}
-static void FTransformWHTSSE2(const int16_t* in, int16_t* out) {
+static void FTransformWHT(const int16_t* in, int16_t* out) {
int32_t tmp[16];
int i;
for (i = 0; i < 4; ++i, in += 64) {
@@ -487,8 +488,8 @@ static void FTransformWHTSSE2(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------
// Metric
-static int SSE_Nx4SSE2(const uint8_t* a, const uint8_t* b,
- int num_quads, int do_16) {
+static int SSE_Nx4(const uint8_t* a, const uint8_t* b,
+ int num_quads, int do_16) {
const __m128i zero = _mm_setzero_si128();
__m128i sum1 = zero;
__m128i sum2 = zero;
@@ -565,19 +566,19 @@ static int SSE_Nx4SSE2(const uint8_t* a, const uint8_t* b,
}
}
-static int SSE16x16SSE2(const uint8_t* a, const uint8_t* b) {
- return SSE_Nx4SSE2(a, b, 4, 1);
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ return SSE_Nx4(a, b, 4, 1);
}
-static int SSE16x8SSE2(const uint8_t* a, const uint8_t* b) {
- return SSE_Nx4SSE2(a, b, 2, 1);
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ return SSE_Nx4(a, b, 2, 1);
}
-static int SSE8x8SSE2(const uint8_t* a, const uint8_t* b) {
- return SSE_Nx4SSE2(a, b, 2, 0);
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ return SSE_Nx4(a, b, 2, 0);
}
-static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
const __m128i zero = _mm_setzero_si128();
// Load values. Note that we read 8 pixels instead of 4,
@@ -634,8 +635,8 @@ static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
// Hadamard transform
// Returns the difference between the weighted sum of the absolute value of
// transformed coefficients.
-static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
- const uint16_t* const w) {
+static int TTransform(const uint8_t* inA, const uint8_t* inB,
+ const uint16_t* const w) {
int32_t sum[4];
__m128i tmp_0, tmp_1, tmp_2, tmp_3;
const __m128i zero = _mm_setzero_si128();
@@ -782,19 +783,19 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
return sum[0] + sum[1] + sum[2] + sum[3];
}
-static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b,
- const uint16_t* const w) {
- const int diff_sum = TTransformSSE2(a, b, w);
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ const int diff_sum = TTransform(a, b, w);
return abs(diff_sum) >> 5;
}
-static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
- const uint16_t* const w) {
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
int D = 0;
int x, y;
for (y = 0; y < 16 * BPS; y += 4 * BPS) {
for (x = 0; x < 16; x += 4) {
- D += Disto4x4SSE2(a + x + y, b + x + y, w);
+ D += Disto4x4(a + x + y, b + x + y, w);
}
}
return D;
@@ -804,9 +805,9 @@ static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
// Quantization
//
-// Simple quantization
-static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
- int n, const VP8Matrix* const mtx) {
+static WEBP_INLINE int DoQuantizeBlock(int16_t in[16], int16_t out[16],
+ const uint16_t* const sharpen,
+ const VP8Matrix* const mtx) {
const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
const __m128i zero = _mm_setzero_si128();
__m128i coeff0, coeff8;
@@ -818,18 +819,14 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
// we can use _mm_load_si128 instead of _mm_loadu_si128.
__m128i in0 = _mm_loadu_si128((__m128i*)&in[0]);
__m128i in8 = _mm_loadu_si128((__m128i*)&in[8]);
- const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[0]);
- const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[8]);
const __m128i iq0 = _mm_loadu_si128((__m128i*)&mtx->iq_[0]);
const __m128i iq8 = _mm_loadu_si128((__m128i*)&mtx->iq_[8]);
- const __m128i bias0 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]);
- const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]);
const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]);
- // sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative)
- const __m128i sign0 = _mm_srai_epi16(in0, 15);
- const __m128i sign8 = _mm_srai_epi16(in8, 15);
+ // extract sign(in) (0x0000 if positive, 0xffff if negative)
+ const __m128i sign0 = _mm_cmpgt_epi16(zero, in0);
+ const __m128i sign8 = _mm_cmpgt_epi16(zero, in8);
// coeff = abs(in) = (in ^ sign) - sign
coeff0 = _mm_xor_si128(in0, sign0);
@@ -838,32 +835,35 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
coeff8 = _mm_sub_epi16(coeff8, sign8);
// coeff = abs(in) + sharpen
- coeff0 = _mm_add_epi16(coeff0, sharpen0);
- coeff8 = _mm_add_epi16(coeff8, sharpen8);
+ if (sharpen != NULL) {
+ const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&sharpen[0]);
+ const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&sharpen[8]);
+ coeff0 = _mm_add_epi16(coeff0, sharpen0);
+ coeff8 = _mm_add_epi16(coeff8, sharpen8);
+ }
- // out = (coeff * iQ + B) >> QFIX;
+ // out = (coeff * iQ + B) >> QFIX
{
// doing calculations with 32b precision (QFIX=17)
// out = (coeff * iQ)
- __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
- __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
- __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
- __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
+ const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
+ const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
+ const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
+ const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
__m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H);
__m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H);
- // expand bias from 16b to 32b
- __m128i bias_00 = _mm_unpacklo_epi16(bias0, zero);
- __m128i bias_04 = _mm_unpackhi_epi16(bias0, zero);
- __m128i bias_08 = _mm_unpacklo_epi16(bias8, zero);
- __m128i bias_12 = _mm_unpackhi_epi16(bias8, zero);
// out = (coeff * iQ + B)
+ const __m128i bias_00 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]);
+ const __m128i bias_04 = _mm_loadu_si128((__m128i*)&mtx->bias_[4]);
+ const __m128i bias_08 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
+ const __m128i bias_12 = _mm_loadu_si128((__m128i*)&mtx->bias_[12]);
out_00 = _mm_add_epi32(out_00, bias_00);
out_04 = _mm_add_epi32(out_04, bias_04);
out_08 = _mm_add_epi32(out_08, bias_08);
out_12 = _mm_add_epi32(out_12, bias_12);
- // out = (coeff * iQ + B) >> QFIX;
+ // out = QUANTDIV(coeff, iQ, B, QFIX)
out_00 = _mm_srai_epi32(out_00, QFIX);
out_04 = _mm_srai_epi32(out_04, QFIX);
out_08 = _mm_srai_epi32(out_08, QFIX);
@@ -916,19 +916,44 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
}
// detect if all 'out' values are zeroes or not
- {
- int32_t tmp[4];
- _mm_storeu_si128((__m128i*)tmp, packed_out);
- if (n) {
- tmp[0] &= ~0xff;
- }
- return (tmp[3] || tmp[2] || tmp[1] || tmp[0]);
- }
+ return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff);
}
-static int QuantizeBlockWHTSSE2(int16_t in[16], int16_t out[16],
- const VP8Matrix* const mtx) {
- return QuantizeBlockSSE2(in, out, 0, mtx);
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, &mtx->sharpen_[0], mtx);
+}
+
+static int QuantizeBlockWHT(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, NULL, mtx);
+}
+
+// Forward declaration.
+void VP8SetResidualCoeffsSSE2(const int16_t* const coeffs,
+ VP8Residual* const res);
+
+void VP8SetResidualCoeffsSSE2(const int16_t* const coeffs,
+ VP8Residual* const res) {
+ const __m128i c0 = _mm_loadu_si128((const __m128i*)coeffs);
+ const __m128i c1 = _mm_loadu_si128((const __m128i*)(coeffs + 8));
+ // Use SSE to compare 8 values with a single instruction.
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i m0 = _mm_cmpeq_epi16(c0, zero);
+ const __m128i m1 = _mm_cmpeq_epi16(c1, zero);
+ // Get the comparison results as a bitmask, consisting of two times 16 bits:
+ // two identical bits for each result. Concatenate both bitmasks to get a
+ // single 32 bit value. Negate the mask to get the position of entries that
+ // are not equal to zero. We don't need to mask out least significant bits
+ // according to res->first, since coeffs[0] is 0 if res->first > 0
+ const uint32_t mask =
+ ~(((uint32_t)_mm_movemask_epi8(m1) << 16) | _mm_movemask_epi8(m0));
+ // The position of the most significant non-zero bit indicates the position of
+ // the last non-zero value. Divide the result by two because __movemask_epi8
+ // operates on 8 bit values instead of 16 bit values.
+ assert(res->first == 0 || coeffs[0] == 0);
+ res->last = mask ? (BitsLog2Floor(mask) >> 1) : -1;
+ res->coeffs = coeffs;
}
#endif // WEBP_USE_SSE2
@@ -940,18 +965,18 @@ extern void VP8EncDspInitSSE2(void);
void VP8EncDspInitSSE2(void) {
#if defined(WEBP_USE_SSE2)
- VP8CollectHistogram = CollectHistogramSSE2;
- VP8EncQuantizeBlock = QuantizeBlockSSE2;
- VP8EncQuantizeBlockWHT = QuantizeBlockWHTSSE2;
- VP8ITransform = ITransformSSE2;
- VP8FTransform = FTransformSSE2;
- VP8FTransformWHT = FTransformWHTSSE2;
- VP8SSE16x16 = SSE16x16SSE2;
- VP8SSE16x8 = SSE16x8SSE2;
- VP8SSE8x8 = SSE8x8SSE2;
- VP8SSE4x4 = SSE4x4SSE2;
- VP8TDisto4x4 = Disto4x4SSE2;
- VP8TDisto16x16 = Disto16x16SSE2;
+ VP8CollectHistogram = CollectHistogram;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantizeBlockWHT = QuantizeBlockWHT;
+ VP8ITransform = ITransform;
+ VP8FTransform = FTransform;
+ VP8FTransformWHT = FTransformWHT;
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE4x4 = SSE4x4;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
#endif // WEBP_USE_SSE2
}
diff --git a/src/3rdparty/libwebp/src/dsp/lossless.c b/src/3rdparty/libwebp/src/dsp/lossless.c
index bab76d2..ee334bc 100644
--- a/src/3rdparty/libwebp/src/dsp/lossless.c
+++ b/src/3rdparty/libwebp/src/dsp/lossless.c
@@ -15,21 +15,16 @@
#include "./dsp.h"
-#if defined(WEBP_USE_SSE2)
-#include <emmintrin.h>
-#endif
-
#include <math.h>
#include <stdlib.h>
-#include "./lossless.h"
#include "../dec/vp8li.h"
+#include "../utils/endian_inl.h"
+#include "./lossless.h"
#include "./yuv.h"
#define MAX_DIFF_COST (1e30f)
// lookup table for small values of log2(int)
-#define APPROX_LOG_MAX 4096
-#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
0.0000000000000000f, 0.0000000000000000f,
1.0000000000000000f, 1.5849625007211560f,
@@ -331,30 +326,59 @@ const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = {
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126
};
-float VP8LFastSLog2Slow(int v) {
+// The threshold till approximate version of log_2 can be used.
+// Practically, we can get rid of the call to log() as the two values match to
+// very high degree (the ratio of these two is 0.99999x).
+// Keeping a high threshold for now.
+#define APPROX_LOG_WITH_CORRECTION_MAX 65536
+#define APPROX_LOG_MAX 4096
+#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
+static float FastSLog2Slow(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
- if (v < APPROX_LOG_MAX) {
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
int log_cnt = 0;
+ uint32_t y = 1;
+ int correction = 0;
const float v_f = (float)v;
- while (v >= LOG_LOOKUP_IDX_MAX) {
+ const uint32_t orig_v = v;
+ do {
++log_cnt;
v = v >> 1;
- }
- return v_f * (kLog2Table[v] + log_cnt);
+ y = y << 1;
+ } while (v >= LOG_LOOKUP_IDX_MAX);
+ // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
+ // Xf = floor(Xf) * (1 + (v % y) / v)
+ // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
+ // The correction factor: log(1 + d) ~ d; for very small d values, so
+ // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
+ // LOG_2_RECIPROCAL ~ 23/16
+ correction = (23 * (orig_v & (y - 1))) >> 4;
+ return v_f * (kLog2Table[v] + log_cnt) + correction;
} else {
return (float)(LOG_2_RECIPROCAL * v * log((double)v));
}
}
-float VP8LFastLog2Slow(int v) {
+static float FastLog2Slow(uint32_t v) {
assert(v >= LOG_LOOKUP_IDX_MAX);
- if (v < APPROX_LOG_MAX) {
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
int log_cnt = 0;
- while (v >= LOG_LOOKUP_IDX_MAX) {
+ uint32_t y = 1;
+ const uint32_t orig_v = v;
+ double log_2;
+ do {
++log_cnt;
v = v >> 1;
+ y = y << 1;
+ } while (v >= LOG_LOOKUP_IDX_MAX);
+ log_2 = kLog2Table[v] + log_cnt;
+ if (orig_v >= APPROX_LOG_MAX) {
+ // Since the division is still expensive, add this correction factor only
+ // for large values of 'v'.
+ const int correction = (23 * (orig_v & (y - 1))) >> 4;
+ log_2 += (double)correction / orig_v;
}
- return kLog2Table[v] + log_cnt;
+ return (float)log_2;
} else {
return (float)(LOG_2_RECIPROCAL * log((double)v));
}
@@ -363,6 +387,9 @@ float VP8LFastLog2Slow(int v) {
//------------------------------------------------------------------------------
// Image transforms.
+// Mostly used to reduce code size + readability
+static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
+
// In-place sum of each component with mod 256.
static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
@@ -406,7 +433,7 @@ static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
(c1 >> 8) & 0xff,
(c2 >> 8) & 0xff);
const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);
- return (a << 24) | (r << 16) | (g << 8) | b;
+ return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
}
static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
@@ -420,15 +447,24 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);
const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);
const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);
- return (a << 24) | (r << 16) | (g << 8) | b;
+ return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
}
-static WEBP_INLINE int Sub3(int a, int b, int c) {
+// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined.
+#if defined(__arm__) && LOCAL_GCC_VERSION == 0x409
+# define LOCAL_INLINE __attribute__ ((noinline))
+#else
+# define LOCAL_INLINE WEBP_INLINE
+#endif
+
+static LOCAL_INLINE int Sub3(int a, int b, int c) {
const int pb = b - c;
const int pa = a - c;
return abs(pb) - abs(pa);
}
+#undef LOCAL_INLINE
+
static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
const int pa_minus_pb =
Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +
@@ -489,21 +525,19 @@ static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
return pred;
}
static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = VP8LSelect(top[0], left, top[-1]);
+ const uint32_t pred = Select(top[0], left, top[-1]);
return pred;
}
static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = VP8LClampedAddSubtractFull(left, top[0], top[-1]);
+ const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
return pred;
}
static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
- const uint32_t pred = VP8LClampedAddSubtractHalf(left, top[0], top[-1]);
+ const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
return pred;
}
-// TODO(vikasa): Export the predictor array, to allow SSE2 variants.
-typedef uint32_t (*PredictorFunc)(uint32_t left, const uint32_t* const top);
-static const PredictorFunc kPredictors[16] = {
+static const VP8LPredictorFunc kPredictorsC[16] = {
Predictor0, Predictor1, Predictor2, Predictor3,
Predictor4, Predictor5, Predictor6, Predictor7,
Predictor8, Predictor9, Predictor10, Predictor11,
@@ -511,10 +545,9 @@ static const PredictorFunc kPredictors[16] = {
Predictor0, Predictor0 // <- padding security sentinels
};
-// TODO(vikasa): Replace 256 etc with defines.
-static float PredictionCostSpatial(const int* counts,
- int weight_0, double exp_val) {
- const int significant_symbols = 16;
+static float PredictionCostSpatial(const int counts[256], int weight_0,
+ double exp_val) {
+ const int significant_symbols = 256 >> 4;
const double exp_decay_factor = 0.6;
double bits = weight_0 * counts[0];
int i;
@@ -526,19 +559,19 @@ static float PredictionCostSpatial(const int* counts,
}
// Compute the combined Shanon's entropy for distribution {X} and {X+Y}
-static float CombinedShannonEntropy(const int* const X,
- const int* const Y, int n) {
+static float CombinedShannonEntropy(const int X[256], const int Y[256]) {
int i;
double retval = 0.;
int sumX = 0, sumXY = 0;
- for (i = 0; i < n; ++i) {
+ for (i = 0; i < 256; ++i) {
const int x = X[i];
- const int xy = X[i] + Y[i];
+ const int xy = x + Y[i];
if (x != 0) {
sumX += x;
retval -= VP8LFastSLog2(x);
- }
- if (xy != 0) {
+ sumXY += xy;
+ retval -= VP8LFastSLog2(xy);
+ } else if (xy != 0) {
sumXY += xy;
retval -= VP8LFastSLog2(xy);
}
@@ -547,50 +580,53 @@ static float CombinedShannonEntropy(const int* const X,
return (float)retval;
}
-static float PredictionCostSpatialHistogram(int accumulated[4][256],
- int tile[4][256]) {
+static float PredictionCostSpatialHistogram(const int accumulated[4][256],
+ const int tile[4][256]) {
int i;
double retval = 0;
for (i = 0; i < 4; ++i) {
const double kExpValue = 0.94;
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
- retval += CombinedShannonEntropy(tile[i], accumulated[i], 256);
+ retval += CombinedShannonEntropy(tile[i], accumulated[i]);
}
return (float)retval;
}
+static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) {
+ ++histo_argb[0][argb >> 24];
+ ++histo_argb[1][(argb >> 16) & 0xff];
+ ++histo_argb[2][(argb >> 8) & 0xff];
+ ++histo_argb[3][argb & 0xff];
+}
+
static int GetBestPredictorForTile(int width, int height,
int tile_x, int tile_y, int bits,
- int accumulated[4][256],
+ const int accumulated[4][256],
const uint32_t* const argb_scratch) {
const int kNumPredModes = 14;
const int col_start = tile_x << bits;
const int row_start = tile_y << bits;
const int tile_size = 1 << bits;
- const int ymax = (tile_size <= height - row_start) ?
- tile_size : height - row_start;
- const int xmax = (tile_size <= width - col_start) ?
- tile_size : width - col_start;
- int histo[4][256];
+ const int max_y = GetMin(tile_size, height - row_start);
+ const int max_x = GetMin(tile_size, width - col_start);
float best_diff = MAX_DIFF_COST;
int best_mode = 0;
-
int mode;
for (mode = 0; mode < kNumPredModes; ++mode) {
const uint32_t* current_row = argb_scratch;
- const PredictorFunc pred_func = kPredictors[mode];
+ const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
float cur_diff;
int y;
- memset(&histo[0][0], 0, sizeof(histo));
- for (y = 0; y < ymax; ++y) {
+ int histo_argb[4][256];
+ memset(histo_argb, 0, sizeof(histo_argb));
+ for (y = 0; y < max_y; ++y) {
int x;
const int row = row_start + y;
const uint32_t* const upper_row = current_row;
current_row = upper_row + width;
- for (x = 0; x < xmax; ++x) {
+ for (x = 0; x < max_x; ++x) {
const int col = col_start + x;
uint32_t predict;
- uint32_t predict_diff;
if (row == 0) {
predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
} else if (col == 0) {
@@ -598,14 +634,11 @@ static int GetBestPredictorForTile(int width, int height,
} else {
predict = pred_func(current_row[col - 1], upper_row + col);
}
- predict_diff = VP8LSubPixels(current_row[col], predict);
- ++histo[0][predict_diff >> 24];
- ++histo[1][((predict_diff >> 16) & 0xff)];
- ++histo[2][((predict_diff >> 8) & 0xff)];
- ++histo[3][(predict_diff & 0xff)];
+ UpdateHisto(histo_argb, VP8LSubPixels(current_row[col], predict));
}
}
- cur_diff = PredictionCostSpatialHistogram(accumulated, histo);
+ cur_diff = PredictionCostSpatialHistogram(
+ accumulated, (const int (*)[256])histo_argb);
if (cur_diff < best_diff) {
best_diff = cur_diff;
best_mode = mode;
@@ -622,20 +655,18 @@ static void CopyTileWithPrediction(int width, int height,
const int col_start = tile_x << bits;
const int row_start = tile_y << bits;
const int tile_size = 1 << bits;
- const int ymax = (tile_size <= height - row_start) ?
- tile_size : height - row_start;
- const int xmax = (tile_size <= width - col_start) ?
- tile_size : width - col_start;
- const PredictorFunc pred_func = kPredictors[mode];
+ const int max_y = GetMin(tile_size, height - row_start);
+ const int max_x = GetMin(tile_size, width - col_start);
+ const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
const uint32_t* current_row = argb_scratch;
int y;
- for (y = 0; y < ymax; ++y) {
+ for (y = 0; y < max_y; ++y) {
int x;
const int row = row_start + y;
const uint32_t* const upper_row = current_row;
current_row = upper_row + width;
- for (x = 0; x < xmax; ++x) {
+ for (x = 0; x < max_x; ++x) {
const int col = col_start + x;
const int pix = row * width + col;
uint32_t predict;
@@ -681,7 +712,8 @@ void VP8LResidualImage(int width, int height, int bits,
if (all_x_max > width) {
all_x_max = width;
}
- pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo,
+ pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits,
+ (const int (*)[256])histo,
argb_scratch);
image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
@@ -695,11 +727,7 @@ void VP8LResidualImage(int width, int height, int bits,
}
ix = all_y * width + tile_x_offset;
for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- const uint32_t a = argb[ix];
- ++histo[0][a >> 24];
- ++histo[1][((a >> 16) & 0xff)];
- ++histo[2][((a >> 8) & 0xff)];
- ++histo[3][(a & 0xff)];
+ UpdateHisto(histo, argb[ix]);
}
}
}
@@ -724,29 +752,36 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
{
int y = y_start;
- const int mask = (1 << transform->bits_) - 1;
+ const int tile_width = 1 << transform->bits_;
+ const int mask = tile_width - 1;
+ const int safe_width = width & ~mask;
const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
const uint32_t* pred_mode_base =
transform->data_ + (y >> transform->bits_) * tiles_per_row;
while (y < y_end) {
- int x;
const uint32_t pred2 = Predictor2(data[-1], data - width);
const uint32_t* pred_mode_src = pred_mode_base;
- PredictorFunc pred_func;
-
+ VP8LPredictorFunc pred_func;
+ int x = 1;
+ int t = 1;
// First pixel follows the T (mode=2) mode.
AddPixelsEq(data, pred2);
-
// .. the rest:
- pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
- for (x = 1; x < width; ++x) {
- uint32_t pred;
- if ((x & mask) == 0) { // start of tile. Read predictor function.
- pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ while (x < safe_width) {
+ pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ for (; t < tile_width; ++t, ++x) {
+ const uint32_t pred = pred_func(data[x - 1], data + x - width);
+ AddPixelsEq(data + x, pred);
+ }
+ t = 0;
+ }
+ if (x < width) {
+ pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ for (; x < width; ++x) {
+ const uint32_t pred = pred_func(data[x - 1], data + x - width);
+ AddPixelsEq(data + x, pred);
}
- pred = pred_func(data[x - 1], data + x - width);
- AddPixelsEq(data + x, pred);
}
data += width;
++y;
@@ -757,9 +792,9 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
}
}
-static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) {
- int i = 0;
- for (; i < num_pixs; ++i) {
+void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
const uint32_t argb = argb_data[i];
const uint32_t green = (argb >> 8) & 0xff;
const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
@@ -770,26 +805,19 @@ static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) {
// Add green to blue and red channels (i.e. perform the inverse transform of
// 'subtract green').
-static void AddGreenToBlueAndRed(uint32_t* data, const uint32_t* data_end) {
- while (data < data_end) {
- const uint32_t argb = *data;
+void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
const uint32_t green = ((argb >> 8) & 0xff);
uint32_t red_blue = (argb & 0x00ff00ffu);
red_blue += (green << 16) | green;
red_blue &= 0x00ff00ffu;
- *data++ = (argb & 0xff00ff00u) | red_blue;
+ data[i] = (argb & 0xff00ff00u) | red_blue;
}
}
-typedef struct {
- // Note: the members are uint8_t, so that any negative values are
- // automatically converted to "mod 256" values.
- uint8_t green_to_red_;
- uint8_t green_to_blue_;
- uint8_t red_to_blue_;
-} Multipliers;
-
-static WEBP_INLINE void MultipliersClear(Multipliers* m) {
+static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) {
m->green_to_red_ = 0;
m->green_to_blue_ = 0;
m->red_to_blue_ = 0;
@@ -801,40 +829,54 @@ static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
}
static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
- Multipliers* const m) {
+ VP8LMultipliers* const m) {
m->green_to_red_ = (color_code >> 0) & 0xff;
m->green_to_blue_ = (color_code >> 8) & 0xff;
m->red_to_blue_ = (color_code >> 16) & 0xff;
}
-static WEBP_INLINE uint32_t MultipliersToColorCode(Multipliers* const m) {
+static WEBP_INLINE uint32_t MultipliersToColorCode(
+ const VP8LMultipliers* const m) {
return 0xff000000u |
((uint32_t)(m->red_to_blue_) << 16) |
((uint32_t)(m->green_to_blue_) << 8) |
m->green_to_red_;
}
-static WEBP_INLINE uint32_t TransformColor(const Multipliers* const m,
- uint32_t argb, int inverse) {
- const uint32_t green = argb >> 8;
- const uint32_t red = argb >> 16;
- uint32_t new_red = red;
- uint32_t new_blue = argb;
+void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
+ int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint32_t new_red = red;
+ uint32_t new_blue = argb;
+ new_red -= ColorTransformDelta(m->green_to_red_, green);
+ new_red &= 0xff;
+ new_blue -= ColorTransformDelta(m->green_to_blue_, green);
+ new_blue -= ColorTransformDelta(m->red_to_blue_, red);
+ new_blue &= 0xff;
+ data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
+ }
+}
- if (inverse) {
+void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, uint32_t* data,
+ int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint32_t new_red = red;
+ uint32_t new_blue = argb;
new_red += ColorTransformDelta(m->green_to_red_, green);
new_red &= 0xff;
new_blue += ColorTransformDelta(m->green_to_blue_, green);
new_blue += ColorTransformDelta(m->red_to_blue_, new_red);
new_blue &= 0xff;
- } else {
- new_red -= ColorTransformDelta(m->green_to_red_, green);
- new_red &= 0xff;
- new_blue -= ColorTransformDelta(m->green_to_blue_, green);
- new_blue -= ColorTransformDelta(m->red_to_blue_, red);
- new_blue &= 0xff;
+ data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
}
- return (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
}
static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
@@ -856,225 +898,251 @@ static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue,
return (new_blue & 0xff);
}
-static WEBP_INLINE int SkipRepeatedPixels(const uint32_t* const argb,
- int ix, int xsize) {
- const uint32_t v = argb[ix];
- if (ix >= xsize + 3) {
- if (v == argb[ix - xsize] &&
- argb[ix - 1] == argb[ix - xsize - 1] &&
- argb[ix - 2] == argb[ix - xsize - 2] &&
- argb[ix - 3] == argb[ix - xsize - 3]) {
- return 1;
- }
- return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
- } else if (ix >= 3) {
- return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
- }
- return 0;
-}
-
static float PredictionCostCrossColor(const int accumulated[256],
const int counts[256]) {
// Favor low entropy, locally and globally.
// Favor small absolute values for PredictionCostSpatial
static const double kExpValue = 2.4;
- return CombinedShannonEntropy(counts, accumulated, 256) +
+ return CombinedShannonEntropy(counts, accumulated) +
PredictionCostSpatial(counts, 3, kExpValue);
}
-static Multipliers GetBestColorTransformForTile(
- int tile_x, int tile_y, int bits,
- Multipliers prevX,
- Multipliers prevY,
- int step, int xsize, int ysize,
- int* accumulated_red_histo,
- int* accumulated_blue_histo,
- const uint32_t* const argb) {
- float best_diff = MAX_DIFF_COST;
+static float GetPredictionCostCrossColorRed(
+ int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
+ int xsize, VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
+ const int accumulated_red_histo[256], const uint32_t* const argb) {
+ int all_y;
+ int histo[256] = { 0 };
float cur_diff;
- const int halfstep = step / 2;
- const int max_tile_size = 1 << bits;
- const int tile_y_offset = tile_y * max_tile_size;
- const int tile_x_offset = tile_x * max_tile_size;
- int green_to_red;
- int green_to_blue;
- int red_to_blue;
- int all_x_max = tile_x_offset + max_tile_size;
- int all_y_max = tile_y_offset + max_tile_size;
- Multipliers best_tx;
- MultipliersClear(&best_tx);
- if (all_x_max > xsize) {
- all_x_max = xsize;
+ for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
+ int ix = all_y * xsize + tile_x_offset;
+ int all_x;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ ++histo[TransformColorRed(green_to_red, argb[ix])]; // red.
+ }
}
- if (all_y_max > ysize) {
- all_y_max = ysize;
+ cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
+ if ((uint8_t)green_to_red == prev_x.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
}
-
- for (green_to_red = -64; green_to_red <= 64; green_to_red += halfstep) {
- int histo[256] = { 0 };
- int all_y;
-
- for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
- int ix = all_y * xsize + tile_x_offset;
- int all_x;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- if (SkipRepeatedPixels(argb, ix, xsize)) {
- continue;
- }
- ++histo[TransformColorRed(green_to_red, argb[ix])]; // red.
- }
- }
- cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]);
- if ((uint8_t)green_to_red == prevX.green_to_red_) {
- cur_diff -= 3; // favor keeping the areas locally similar
+ if ((uint8_t)green_to_red == prev_y.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (green_to_red == 0) {
+ cur_diff -= 3;
+ }
+ return cur_diff;
+}
+
+static void GetBestGreenToRed(
+ int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
+ int xsize, VP8LMultipliers prev_x, VP8LMultipliers prev_y,
+ const int accumulated_red_histo[256], const uint32_t* const argb,
+ VP8LMultipliers* const best_tx) {
+ int min_green_to_red = -64;
+ int max_green_to_red = 64;
+ int green_to_red = 0;
+ int eval_min = 1;
+ int eval_max = 1;
+ float cur_diff_min = MAX_DIFF_COST;
+ float cur_diff_max = MAX_DIFF_COST;
+ // Do a binary search to find the optimal green_to_red color transform.
+ while (max_green_to_red - min_green_to_red > 2) {
+ if (eval_min) {
+ cur_diff_min = GetPredictionCostCrossColorRed(
+ tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
+ prev_x, prev_y, min_green_to_red, accumulated_red_histo, argb);
+ eval_min = 0;
}
- if ((uint8_t)green_to_red == prevY.green_to_red_) {
- cur_diff -= 3; // favor keeping the areas locally similar
+ if (eval_max) {
+ cur_diff_max = GetPredictionCostCrossColorRed(
+ tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
+ prev_x, prev_y, max_green_to_red, accumulated_red_histo, argb);
+ eval_max = 0;
}
- if (green_to_red == 0) {
- cur_diff -= 3;
+ if (cur_diff_min < cur_diff_max) {
+ green_to_red = min_green_to_red;
+ max_green_to_red = (max_green_to_red + min_green_to_red) / 2;
+ eval_max = 1;
+ } else {
+ green_to_red = max_green_to_red;
+ min_green_to_red = (max_green_to_red + min_green_to_red) / 2;
+ eval_min = 1;
}
- if (cur_diff < best_diff) {
- best_diff = cur_diff;
- best_tx.green_to_red_ = green_to_red;
+ }
+ best_tx->green_to_red_ = green_to_red;
+}
+
+static float GetPredictionCostCrossColorBlue(
+ int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
+ int xsize, VP8LMultipliers prev_x, VP8LMultipliers prev_y,
+ int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256],
+ const uint32_t* const argb) {
+ int all_y;
+ int histo[256] = { 0 };
+ float cur_diff;
+ for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
+ int all_x;
+ int ix = all_y * xsize + tile_x_offset;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ ++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[ix])];
}
}
- best_diff = MAX_DIFF_COST;
- for (green_to_blue = -32; green_to_blue <= 32; green_to_blue += step) {
- for (red_to_blue = -32; red_to_blue <= 32; red_to_blue += step) {
- int all_y;
- int histo[256] = { 0 };
- for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
- int all_x;
- int ix = all_y * xsize + tile_x_offset;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- if (SkipRepeatedPixels(argb, ix, xsize)) {
- continue;
- }
- ++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[ix])];
- }
- }
- cur_diff =
- PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]);
- if ((uint8_t)green_to_blue == prevX.green_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if ((uint8_t)green_to_blue == prevY.green_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if ((uint8_t)red_to_blue == prevX.red_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if ((uint8_t)red_to_blue == prevY.red_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (green_to_blue == 0) {
- cur_diff -= 3;
- }
- if (red_to_blue == 0) {
- cur_diff -= 3;
- }
+ cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
+ if ((uint8_t)green_to_blue == prev_x.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)green_to_blue == prev_y.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)red_to_blue == prev_x.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)red_to_blue == prev_y.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (green_to_blue == 0) {
+ cur_diff -= 3;
+ }
+ if (red_to_blue == 0) {
+ cur_diff -= 3;
+ }
+ return cur_diff;
+}
+
+static void GetBestGreenRedToBlue(
+ int tile_x_offset, int tile_y_offset, int all_x_max, int all_y_max,
+ int xsize, VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality,
+ const int accumulated_blue_histo[256], const uint32_t* const argb,
+ VP8LMultipliers* const best_tx) {
+ float best_diff = MAX_DIFF_COST;
+ float cur_diff;
+ const int step = (quality < 25) ? 32 : (quality > 50) ? 8 : 16;
+ const int min_green_to_blue = -32;
+ const int max_green_to_blue = 32;
+ const int min_red_to_blue = -32;
+ const int max_red_to_blue = 32;
+ const int num_iters =
+ (1 + (max_green_to_blue - min_green_to_blue) / step) *
+ (1 + (max_red_to_blue - min_red_to_blue) / step);
+ // Number of tries to get optimal green_to_blue & red_to_blue color transforms
+ // after finding a local minima.
+ const int max_tries_after_min = 4 + (num_iters >> 2);
+ int num_tries_after_min = 0;
+ int green_to_blue;
+ for (green_to_blue = min_green_to_blue;
+ green_to_blue <= max_green_to_blue &&
+ num_tries_after_min < max_tries_after_min;
+ green_to_blue += step) {
+ int red_to_blue;
+ for (red_to_blue = min_red_to_blue;
+ red_to_blue <= max_red_to_blue &&
+ num_tries_after_min < max_tries_after_min;
+ red_to_blue += step) {
+ cur_diff = GetPredictionCostCrossColorBlue(
+ tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize, prev_x,
+ prev_y, green_to_blue, red_to_blue, accumulated_blue_histo, argb);
if (cur_diff < best_diff) {
best_diff = cur_diff;
- best_tx.green_to_blue_ = green_to_blue;
- best_tx.red_to_blue_ = red_to_blue;
+ best_tx->green_to_blue_ = green_to_blue;
+ best_tx->red_to_blue_ = red_to_blue;
+ num_tries_after_min = 0;
+ } else {
+ ++num_tries_after_min;
}
}
}
+}
+
+static VP8LMultipliers GetBestColorTransformForTile(
+ int tile_x, int tile_y, int bits,
+ VP8LMultipliers prev_x,
+ VP8LMultipliers prev_y,
+ int quality, int xsize, int ysize,
+ const int accumulated_red_histo[256],
+ const int accumulated_blue_histo[256],
+ const uint32_t* const argb) {
+ const int max_tile_size = 1 << bits;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int tile_x_offset = tile_x * max_tile_size;
+ const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize);
+ const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize);
+ VP8LMultipliers best_tx;
+ MultipliersClear(&best_tx);
+
+ GetBestGreenToRed(tile_x_offset, tile_y_offset, all_x_max, all_y_max, xsize,
+ prev_x, prev_y, accumulated_red_histo, argb, &best_tx);
+ GetBestGreenRedToBlue(tile_x_offset, tile_y_offset, all_x_max, all_y_max,
+ xsize, prev_x, prev_y, quality, accumulated_blue_histo,
+ argb, &best_tx);
return best_tx;
}
static void CopyTileWithColorTransform(int xsize, int ysize,
- int tile_x, int tile_y, int bits,
- Multipliers color_transform,
- uint32_t* const argb) {
- int y;
- int xscan = 1 << bits;
- int yscan = 1 << bits;
- tile_x <<= bits;
- tile_y <<= bits;
- if (xscan > xsize - tile_x) {
- xscan = xsize - tile_x;
- }
- if (yscan > ysize - tile_y) {
- yscan = ysize - tile_y;
- }
- yscan += tile_y;
- for (y = tile_y; y < yscan; ++y) {
- int ix = y * xsize + tile_x;
- const int end_ix = ix + xscan;
- for (; ix < end_ix; ++ix) {
- argb[ix] = TransformColor(&color_transform, argb[ix], 0);
- }
+ int tile_x, int tile_y,
+ int max_tile_size,
+ VP8LMultipliers color_transform,
+ uint32_t* argb) {
+ const int xscan = GetMin(max_tile_size, xsize - tile_x);
+ int yscan = GetMin(max_tile_size, ysize - tile_y);
+ argb += tile_y * xsize + tile_x;
+ while (yscan-- > 0) {
+ VP8LTransformColor(&color_transform, argb, xscan);
+ argb += xsize;
}
}
-void VP8LColorSpaceTransform(int width, int height, int bits, int step,
+void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image) {
const int max_tile_size = 1 << bits;
- int tile_xsize = VP8LSubSampleSize(width, bits);
- int tile_ysize = VP8LSubSampleSize(height, bits);
+ const int tile_xsize = VP8LSubSampleSize(width, bits);
+ const int tile_ysize = VP8LSubSampleSize(height, bits);
int accumulated_red_histo[256] = { 0 };
int accumulated_blue_histo[256] = { 0 };
- int tile_y;
- int tile_x;
- Multipliers prevX;
- Multipliers prevY;
- MultipliersClear(&prevY);
- MultipliersClear(&prevX);
+ int tile_x, tile_y;
+ VP8LMultipliers prev_x, prev_y;
+ MultipliersClear(&prev_y);
+ MultipliersClear(&prev_x);
for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
- Multipliers color_transform;
- int all_x_max;
int y;
- const int tile_y_offset = tile_y * max_tile_size;
const int tile_x_offset = tile_x * max_tile_size;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int all_x_max = GetMin(tile_x_offset + max_tile_size, width);
+ const int all_y_max = GetMin(tile_y_offset + max_tile_size, height);
+ const int offset = tile_y * tile_xsize + tile_x;
if (tile_y != 0) {
- ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
- ColorCodeToMultipliers(image[(tile_y - 1) * tile_xsize + tile_x],
- &prevY);
- } else if (tile_x != 0) {
- ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
+ ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y);
}
- color_transform =
- GetBestColorTransformForTile(tile_x, tile_y, bits,
- prevX, prevY,
- step, width, height,
- &accumulated_red_histo[0],
- &accumulated_blue_histo[0],
- argb);
- image[tile_y * tile_xsize + tile_x] =
- MultipliersToColorCode(&color_transform);
- CopyTileWithColorTransform(width, height, tile_x, tile_y, bits,
- color_transform, argb);
+ prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits,
+ prev_x, prev_y,
+ quality, width, height,
+ accumulated_red_histo,
+ accumulated_blue_histo,
+ argb);
+ image[offset] = MultipliersToColorCode(&prev_x);
+ CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
+ max_tile_size, prev_x, argb);
// Gather accumulated histogram data.
- all_x_max = tile_x_offset + max_tile_size;
- if (all_x_max > width) {
- all_x_max = width;
- }
- for (y = 0; y < max_tile_size; ++y) {
- int ix;
- int all_x;
- int all_y = tile_y_offset + y;
- if (all_y >= height) {
- break;
- }
- ix = all_y * width + tile_x_offset;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ for (y = tile_y_offset; y < all_y_max; ++y) {
+ int ix = y * width + tile_x_offset;
+ const int ix_end = ix + all_x_max - tile_x_offset;
+ for (; ix < ix_end; ++ix) {
+ const uint32_t pix = argb[ix];
if (ix >= 2 &&
- argb[ix] == argb[ix - 2] &&
- argb[ix] == argb[ix - 1]) {
+ pix == argb[ix - 2] &&
+ pix == argb[ix - 1]) {
continue; // repeated pixels are handled by backward references
}
if (ix >= width + 2 &&
argb[ix - 2] == argb[ix - width - 2] &&
argb[ix - 1] == argb[ix - width - 1] &&
- argb[ix] == argb[ix - width]) {
+ pix == argb[ix - width]) {
continue; // repeated pixels are handled by backward references
}
- ++accumulated_red_histo[(argb[ix] >> 16) & 0xff];
- ++accumulated_blue_histo[argb[ix] & 0xff];
+ ++accumulated_red_histo[(pix >> 16) & 0xff];
+ ++accumulated_blue_histo[(pix >> 0) & 0xff];
}
}
}
@@ -1085,7 +1153,10 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int step,
static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
int y_start, int y_end, uint32_t* data) {
const int width = transform->xsize_;
- const int mask = (1 << transform->bits_) - 1;
+ const int tile_width = 1 << transform->bits_;
+ const int mask = tile_width - 1;
+ const int safe_width = width & ~mask;
+ const int remaining_width = width - safe_width;
const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
int y = y_start;
const uint32_t* pred_row =
@@ -1093,16 +1164,21 @@ static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
while (y < y_end) {
const uint32_t* pred = pred_row;
- Multipliers m = { 0, 0, 0 };
- int x;
-
- for (x = 0; x < width; ++x) {
- if ((x & mask) == 0) ColorCodeToMultipliers(*pred++, &m);
- data[x] = TransformColor(&m, data[x], 1);
+ VP8LMultipliers m = { 0, 0, 0 };
+ const uint32_t* const data_safe_end = data + safe_width;
+ const uint32_t* const data_end = data + width;
+ while (data < data_safe_end) {
+ ColorCodeToMultipliers(*pred++, &m);
+ VP8LTransformColorInverse(&m, data, tile_width);
+ data += tile_width;
+ }
+ if (data < data_end) { // Left-overs using C-version.
+ ColorCodeToMultipliers(*pred++, &m);
+ VP8LTransformColorInverse(&m, data, remaining_width);
+ data += remaining_width;
}
- data += width;
++y;
- if ((y & mask) == 0) pred_row += tiles_per_row;;
+ if ((y & mask) == 0) pred_row += tiles_per_row;
}
}
@@ -1173,7 +1249,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
assert(row_end <= transform->ysize_);
switch (transform->type_) {
case SUBTRACT_GREEN:
- VP8LAddGreenToBlueAndRed(out, out + (row_end - row_start) * width);
+ VP8LAddGreenToBlueAndRed(out, (row_end - row_start) * width);
break;
case PREDICTOR_TRANSFORM:
PredictorInverseTransform(transform, row_start, row_end, out);
@@ -1218,8 +1294,8 @@ static int is_big_endian(void) {
return (tmp.b[0] != 1);
}
-static void ConvertBGRAToRGB(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGB_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1229,8 +1305,8 @@ static void ConvertBGRAToRGB(const uint32_t* src,
}
}
-static void ConvertBGRAToRGBA(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGBA_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1241,8 +1317,8 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
}
}
-static void ConvertBGRAToRGBA4444(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1258,8 +1334,8 @@ static void ConvertBGRAToRGBA4444(const uint32_t* src,
}
}
-static void ConvertBGRAToRGB565(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1275,8 +1351,8 @@ static void ConvertBGRAToRGB565(const uint32_t* src,
}
}
-static void ConvertBGRAToBGR(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToBGR_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1291,29 +1367,18 @@ static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
if (is_big_endian() == swap_on_big_endian) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
- uint32_t argb = *src++;
+ const uint32_t argb = *src++;
-#if !defined(__BIG_ENDIAN__)
+#if !defined(WORDS_BIGENDIAN)
#if !defined(WEBP_REFERENCE_IMPLEMENTATION)
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ volatile("bswap %0" : "=r"(argb) : "0"(argb));
- *(uint32_t*)dst = argb;
-#elif defined(_MSC_VER)
- argb = _byteswap_ulong(argb);
- *(uint32_t*)dst = argb;
-#else
- dst[0] = (argb >> 24) & 0xff;
- dst[1] = (argb >> 16) & 0xff;
- dst[2] = (argb >> 8) & 0xff;
- dst[3] = (argb >> 0) & 0xff;
-#endif
+ *(uint32_t*)dst = BSwap32(argb);
#else // WEBP_REFERENCE_IMPLEMENTATION
dst[0] = (argb >> 24) & 0xff;
dst[1] = (argb >> 16) & 0xff;
dst[2] = (argb >> 8) & 0xff;
dst[3] = (argb >> 0) & 0xff;
#endif
-#else // __BIG_ENDIAN__
+#else // WORDS_BIGENDIAN
dst[0] = (argb >> 0) & 0xff;
dst[1] = (argb >> 8) & 0xff;
dst[2] = (argb >> 16) & 0xff;
@@ -1330,17 +1395,17 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {
switch (out_colorspace) {
case MODE_RGB:
- ConvertBGRAToRGB(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGB(in_data, num_pixels, rgba);
break;
case MODE_RGBA:
- ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);
break;
case MODE_rgbA:
- ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);
WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
break;
case MODE_BGR:
- ConvertBGRAToBGR(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToBGR(in_data, num_pixels, rgba);
break;
case MODE_BGRA:
CopyOrSwap(in_data, num_pixels, rgba, 1);
@@ -1357,20 +1422,21 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);
break;
case MODE_RGBA_4444:
- ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
break;
case MODE_rgbA_4444:
- ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);
break;
case MODE_RGB_565:
- ConvertBGRAToRGB565(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGB565(in_data, num_pixels, rgba);
break;
default:
assert(0); // Code flow should not reach here.
}
}
+//------------------------------------------------------------------------------
// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel.
void VP8LBundleColorMap(const uint8_t* const row, int width,
int xbits, uint32_t* const dst) {
@@ -1394,129 +1460,166 @@ void VP8LBundleColorMap(const uint8_t* const row, int width,
//------------------------------------------------------------------------------
-// TODO(vikasa): Move the SSE2 functions to lossless_dsp.c (new file), once
-// color-space conversion methods (ConvertFromBGRA) are also updated for SSE2.
-#if defined(WEBP_USE_SSE2)
-static WEBP_INLINE uint32_t ClampedAddSubtractFullSSE2(uint32_t c0, uint32_t c1,
- uint32_t c2) {
- const __m128i zero = _mm_setzero_si128();
- const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
- const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
- const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
- const __m128i V1 = _mm_add_epi16(C0, C1);
- const __m128i V2 = _mm_sub_epi16(V1, C2);
- const __m128i b = _mm_packus_epi16(V2, V2);
- const uint32_t output = _mm_cvtsi128_si32(b);
- return output;
-}
-
-static WEBP_INLINE uint32_t ClampedAddSubtractHalfSSE2(uint32_t c0, uint32_t c1,
- uint32_t c2) {
- const uint32_t ave = Average2(c0, c1);
- const __m128i zero = _mm_setzero_si128();
- const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(ave), zero);
- const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
- const __m128i A1 = _mm_sub_epi16(A0, B0);
- const __m128i BgtA = _mm_cmpgt_epi16(B0, A0);
- const __m128i A2 = _mm_sub_epi16(A1, BgtA);
- const __m128i A3 = _mm_srai_epi16(A2, 1);
- const __m128i A4 = _mm_add_epi16(A0, A3);
- const __m128i A5 = _mm_packus_epi16(A4, A4);
- const uint32_t output = _mm_cvtsi128_si32(A5);
- return output;
-}
-
-static WEBP_INLINE uint32_t SelectSSE2(uint32_t a, uint32_t b, uint32_t c) {
- int pa_minus_pb;
- const __m128i zero = _mm_setzero_si128();
- const __m128i A0 = _mm_cvtsi32_si128(a);
- const __m128i B0 = _mm_cvtsi32_si128(b);
- const __m128i C0 = _mm_cvtsi32_si128(c);
- const __m128i AC0 = _mm_subs_epu8(A0, C0);
- const __m128i CA0 = _mm_subs_epu8(C0, A0);
- const __m128i BC0 = _mm_subs_epu8(B0, C0);
- const __m128i CB0 = _mm_subs_epu8(C0, B0);
- const __m128i AC = _mm_or_si128(AC0, CA0);
- const __m128i BC = _mm_or_si128(BC0, CB0);
- const __m128i pa = _mm_unpacklo_epi8(AC, zero); // |a - c|
- const __m128i pb = _mm_unpacklo_epi8(BC, zero); // |b - c|
- const __m128i diff = _mm_sub_epi16(pb, pa);
- {
- int16_t out[8];
- _mm_storeu_si128((__m128i*)out, diff);
- pa_minus_pb = out[0] + out[1] + out[2] + out[3];
- }
- return (pa_minus_pb <= 0) ? a : b;
+static double ExtraCost(const uint32_t* population, int length) {
+ int i;
+ double cost = 0.;
+ for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
+ return cost;
}
-static void SubtractGreenFromBlueAndRedSSE2(uint32_t* argb_data, int num_pixs) {
- int i = 0;
- const __m128i mask = _mm_set1_epi32(0x0000ff00);
- for (; i + 4 < num_pixs; i += 4) {
- const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
- const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|...
- const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|...
- const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|...
- const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g);
- const __m128i out = _mm_sub_epi8(in, in_0g0g);
- _mm_storeu_si128((__m128i*)&argb_data[i], out);
+static double ExtraCostCombined(const uint32_t* X, const uint32_t* Y,
+ int length) {
+ int i;
+ double cost = 0.;
+ for (i = 2; i < length - 2; ++i) {
+ const int xy = X[i + 2] + Y[i + 2];
+ cost += (i >> 1) * xy;
}
- // fallthrough and finish off with plain-C
- for (; i < num_pixs; ++i) {
- const uint32_t argb = argb_data[i];
- const uint32_t green = (argb >> 8) & 0xff;
- const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
- const uint32_t new_b = ((argb & 0xff) - green) & 0xff;
- argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b;
+ return cost;
+}
+
+// Returns the various RLE counts
+static VP8LStreaks HuffmanCostCount(const uint32_t* population, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ ++streak;
+ if (population[i] == population[i + 1]) {
+ continue;
+ }
+ stats.counts[population[i] != 0] += (streak > 3);
+ stats.streaks[population[i] != 0][(streak > 3)] += streak;
+ streak = 0;
}
+ ++streak;
+ stats.counts[population[i] != 0] += (streak > 3);
+ stats.streaks[population[i] != 0][(streak > 3)] += streak;
+ return stats;
}
-static void AddGreenToBlueAndRedSSE2(uint32_t* data, const uint32_t* data_end) {
- const __m128i mask = _mm_set1_epi32(0x0000ff00);
- for (; data + 4 < data_end; data += 4) {
- const __m128i in = _mm_loadu_si128((__m128i*)data);
- const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|...
- const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|...
- const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|...
- const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g);
- const __m128i out = _mm_add_epi8(in, in_0g0g);
- _mm_storeu_si128((__m128i*)data, out);
+static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X,
+ const uint32_t* Y, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ const int xy = X[i] + Y[i];
+ const int xy_next = X[i + 1] + Y[i + 1];
+ ++streak;
+ if (xy == xy_next) {
+ continue;
+ }
+ stats.counts[xy != 0] += (streak > 3);
+ stats.streaks[xy != 0][(streak > 3)] += streak;
+ streak = 0;
}
- // fallthrough and finish off with plain-C
- while (data < data_end) {
- const uint32_t argb = *data;
- const uint32_t green = ((argb >> 8) & 0xff);
- uint32_t red_blue = (argb & 0x00ff00ffu);
- red_blue += (green << 16) | green;
- red_blue &= 0x00ff00ffu;
- *data++ = (argb & 0xff00ff00u) | red_blue;
+ {
+ const int xy = X[i] + Y[i];
+ ++streak;
+ stats.counts[xy != 0] += (streak > 3);
+ stats.streaks[xy != 0][(streak > 3)] += streak;
}
+ return stats;
}
-extern void VP8LDspInitSSE2(void);
+//------------------------------------------------------------------------------
-void VP8LDspInitSSE2(void) {
- VP8LClampedAddSubtractFull = ClampedAddSubtractFullSSE2;
- VP8LClampedAddSubtractHalf = ClampedAddSubtractHalfSSE2;
- VP8LSelect = SelectSSE2;
- VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRedSSE2;
- VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRedSSE2;
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ int i;
+ const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+ if (b != out) {
+ for (i = 0; i < literal_size; ++i) {
+ out->literal_[i] = a->literal_[i] + b->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] = a->distance_[i] + b->distance_[i];
+ }
+ for (i = 0; i < NUM_LITERAL_CODES; ++i) {
+ out->red_[i] = a->red_[i] + b->red_[i];
+ out->blue_[i] = a->blue_[i] + b->blue_[i];
+ out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
+ }
+ } else {
+ for (i = 0; i < literal_size; ++i) {
+ out->literal_[i] += a->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] += a->distance_[i];
+ }
+ for (i = 0; i < NUM_LITERAL_CODES; ++i) {
+ out->red_[i] += a->red_[i];
+ out->blue_[i] += a->blue_[i];
+ out->alpha_[i] += a->alpha_[i];
+ }
+ }
}
-#endif
+
//------------------------------------------------------------------------------
-VP8LPredClampedAddSubFunc VP8LClampedAddSubtractFull;
-VP8LPredClampedAddSubFunc VP8LClampedAddSubtractHalf;
-VP8LPredSelectFunc VP8LSelect;
-VP8LSubtractGreenFromBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
-VP8LAddGreenToBlueAndRedFunc VP8LAddGreenToBlueAndRed;
+VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
+VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
+VP8LPredictorFunc VP8LPredictors[16];
+
+VP8LTransformColorFunc VP8LTransformColor;
+VP8LTransformColorFunc VP8LTransformColorInverse;
+
+VP8LConvertFunc VP8LConvertBGRAToRGB;
+VP8LConvertFunc VP8LConvertBGRAToRGBA;
+VP8LConvertFunc VP8LConvertBGRAToRGBA4444;
+VP8LConvertFunc VP8LConvertBGRAToRGB565;
+VP8LConvertFunc VP8LConvertBGRAToBGR;
+
+VP8LFastLog2SlowFunc VP8LFastLog2Slow;
+VP8LFastLog2SlowFunc VP8LFastSLog2Slow;
+
+VP8LCostFunc VP8LExtraCost;
+VP8LCostCombinedFunc VP8LExtraCostCombined;
+
+VP8LCostCountFunc VP8LHuffmanCostCount;
+VP8LCostCombinedCountFunc VP8LHuffmanCostCombinedCount;
+
+VP8LHistogramAddFunc VP8LHistogramAdd;
+
+extern void VP8LDspInitSSE2(void);
+extern void VP8LDspInitNEON(void);
+extern void VP8LDspInitMIPS32(void);
+
+static volatile VP8CPUInfo lossless_last_cpuinfo_used =
+ (VP8CPUInfo)&lossless_last_cpuinfo_used;
void VP8LDspInit(void) {
- VP8LClampedAddSubtractFull = ClampedAddSubtractFull;
- VP8LClampedAddSubtractHalf = ClampedAddSubtractHalf;
- VP8LSelect = Select;
- VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
- VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+ if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ memcpy(VP8LPredictors, kPredictorsC, sizeof(VP8LPredictors));
+
+ VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C;
+ VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
+
+ VP8LTransformColor = VP8LTransformColor_C;
+ VP8LTransformColorInverse = VP8LTransformColorInverse_C;
+
+ VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
+ VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
+ VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
+ VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
+ VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
+
+ VP8LFastLog2Slow = FastLog2Slow;
+ VP8LFastSLog2Slow = FastSLog2Slow;
+
+ VP8LExtraCost = ExtraCost;
+ VP8LExtraCostCombined = ExtraCostCombined;
+
+ VP8LHuffmanCostCount = HuffmanCostCount;
+ VP8LHuffmanCostCombinedCount = HuffmanCostCombinedCount;
+
+ VP8LHistogramAdd = HistogramAdd;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
@@ -1525,8 +1628,18 @@ void VP8LDspInit(void) {
VP8LDspInitSSE2();
}
#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ VP8LDspInitNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8LDspInitMIPS32();
+ }
+#endif
}
+ lossless_last_cpuinfo_used = VP8GetCPUInfo;
}
//------------------------------------------------------------------------------
-
diff --git a/src/3rdparty/libwebp/src/dsp/lossless.h b/src/3rdparty/libwebp/src/dsp/lossless.h
index 0f1d442..8c7551c 100644
--- a/src/3rdparty/libwebp/src/dsp/lossless.h
+++ b/src/3rdparty/libwebp/src/dsp/lossless.h
@@ -18,26 +18,58 @@
#include "../webp/types.h"
#include "../webp/decode.h"
+#include "../enc/histogram.h"
+#include "../utils/utils.h"
+
#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
-//
+// Signatures and generic function-pointers
+
+typedef uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top);
+extern VP8LPredictorFunc VP8LPredictors[16];
-typedef uint32_t (*VP8LPredClampedAddSubFunc)(uint32_t c0, uint32_t c1,
- uint32_t c2);
-typedef uint32_t (*VP8LPredSelectFunc)(uint32_t c0, uint32_t c1, uint32_t c2);
-typedef void (*VP8LSubtractGreenFromBlueAndRedFunc)(uint32_t* argb_data,
- int num_pixs);
-typedef void (*VP8LAddGreenToBlueAndRedFunc)(uint32_t* data_start,
- const uint32_t* data_end);
+typedef void (*VP8LProcessBlueAndRedFunc)(uint32_t* argb_data, int num_pixels);
+extern VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
+extern VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
-extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractFull;
-extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractHalf;
-extern VP8LPredSelectFunc VP8LSelect;
-extern VP8LSubtractGreenFromBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
-extern VP8LAddGreenToBlueAndRedFunc VP8LAddGreenToBlueAndRed;
+typedef struct {
+ // Note: the members are uint8_t, so that any negative values are
+ // automatically converted to "mod 256" values.
+ uint8_t green_to_red_;
+ uint8_t green_to_blue_;
+ uint8_t red_to_blue_;
+} VP8LMultipliers;
+typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels);
+extern VP8LTransformColorFunc VP8LTransformColor;
+extern VP8LTransformColorFunc VP8LTransformColorInverse;
+
+typedef void (*VP8LConvertFunc)(const uint32_t* src, int num_pixels,
+ uint8_t* dst);
+extern VP8LConvertFunc VP8LConvertBGRAToRGB;
+extern VP8LConvertFunc VP8LConvertBGRAToRGBA;
+extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444;
+extern VP8LConvertFunc VP8LConvertBGRAToRGB565;
+extern VP8LConvertFunc VP8LConvertBGRAToBGR;
+
+// Expose some C-only fallback functions
+void VP8LTransformColor_C(const VP8LMultipliers* const m,
+ uint32_t* data, int num_pixels);
+void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
+ uint32_t* data, int num_pixels);
+
+void VP8LConvertBGRAToRGB_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGBA_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToBGR_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels);
+void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels);
// Must be called before calling any of the above methods.
void VP8LDspInit(void);
@@ -66,7 +98,7 @@ void VP8LResidualImage(int width, int height, int bits,
uint32_t* const argb, uint32_t* const argb_scratch,
uint32_t* const image);
-void VP8LColorSpaceTransform(int width, int height, int bits, int step,
+void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
uint32_t* const argb, uint32_t* image);
//------------------------------------------------------------------------------
@@ -85,57 +117,54 @@ static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size,
return (size + (1 << sampling_bits) - 1) >> sampling_bits;
}
+// -----------------------------------------------------------------------------
// Faster logarithm for integers. Small values use a look-up table.
#define LOG_LOOKUP_IDX_MAX 256
extern const float kLog2Table[LOG_LOOKUP_IDX_MAX];
extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX];
-float VP8LFastLog2Slow(int v);
-float VP8LFastSLog2Slow(int v);
-static WEBP_INLINE float VP8LFastLog2(int v) {
+typedef float (*VP8LFastLog2SlowFunc)(uint32_t v);
+
+extern VP8LFastLog2SlowFunc VP8LFastLog2Slow;
+extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow;
+
+static WEBP_INLINE float VP8LFastLog2(uint32_t v) {
return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v);
}
// Fast calculation of v * log2(v) for integer input.
-static WEBP_INLINE float VP8LFastSLog2(int v) {
+static WEBP_INLINE float VP8LFastSLog2(uint32_t v) {
return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v);
}
// -----------------------------------------------------------------------------
-// PrefixEncode()
+// Huffman-cost related functions.
-// use GNU builtins where available.
-#if defined(__GNUC__) && \
- ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- return 31 ^ __builtin_clz(n);
-}
-#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
- (defined(_M_X64) || defined(_M_IX86))
-#include <intrin.h>
-#pragma intrinsic(_BitScanReverse)
-
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- unsigned long first_set_bit;
- _BitScanReverse(&first_set_bit, n);
- return first_set_bit;
-}
-#else
-// Returns (int)floor(log2(n)). n must be > 0.
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- int log = 0;
- uint32_t value = n;
- int i;
-
- for (i = 4; i >= 0; --i) {
- const int shift = (1 << i);
- const uint32_t x = value >> shift;
- if (x != 0) {
- value = x;
- log += shift;
- }
- }
- return log;
-}
-#endif
+typedef double (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
+
+extern VP8LCostFunc VP8LExtraCost;
+extern VP8LCostCombinedFunc VP8LExtraCostCombined;
+
+typedef struct { // small struct to hold counters
+ int counts[2]; // index: 0=zero steak, 1=non-zero streak
+ int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3]
+} VP8LStreaks;
+
+typedef VP8LStreaks (*VP8LCostCountFunc)(const uint32_t* population,
+ int length);
+typedef VP8LStreaks (*VP8LCostCombinedCountFunc)(const uint32_t* X,
+ const uint32_t* Y, int length);
+
+extern VP8LCostCountFunc VP8LHuffmanCostCount;
+extern VP8LCostCombinedCountFunc VP8LHuffmanCostCombinedCount;
+
+typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out);
+extern VP8LHistogramAddFunc VP8LHistogramAdd;
+
+// -----------------------------------------------------------------------------
+// PrefixEncode()
static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
const int log_floor = BitsLog2Floor(n);
diff --git a/src/3rdparty/libwebp/src/dsp/lossless_mips32.c b/src/3rdparty/libwebp/src/dsp/lossless_mips32.c
new file mode 100644
index 0000000..1308580
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/lossless_mips32.c
@@ -0,0 +1,416 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of lossless functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+#include "./lossless.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define APPROX_LOG_WITH_CORRECTION_MAX 65536
+#define APPROX_LOG_MAX 4096
+#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
+
+static float FastSLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ uint32_t log_cnt, y, correction;
+ const int c24 = 24;
+ const float v_f = (float)v;
+ uint32_t temp;
+
+ // Xf = 256 = 2^8
+ // log_cnt is index of leading one in upper 24 bits
+ __asm__ volatile(
+ "clz %[log_cnt], %[v] \n\t"
+ "addiu %[y], $zero, 1 \n\t"
+ "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
+ "sllv %[y], %[y], %[log_cnt] \n\t"
+ "srlv %[temp], %[v], %[log_cnt] \n\t"
+ : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
+ [temp]"=r"(temp)
+ : [c24]"r"(c24), [v]"r"(v)
+ );
+
+ // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
+ // Xf = floor(Xf) * (1 + (v % y) / v)
+ // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
+ // The correction factor: log(1 + d) ~ d; for very small d values, so
+ // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
+ // LOG_2_RECIPROCAL ~ 23/16
+
+ // (v % y) = (v % 2^log_cnt) = v & (2^log_cnt - 1)
+ correction = (23 * (v & (y - 1))) >> 4;
+ return v_f * (kLog2Table[temp] + log_cnt) + correction;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * v * log((double)v));
+ }
+}
+
+static float FastLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ uint32_t log_cnt, y;
+ const int c24 = 24;
+ double log_2;
+ uint32_t temp;
+
+ __asm__ volatile(
+ "clz %[log_cnt], %[v] \n\t"
+ "addiu %[y], $zero, 1 \n\t"
+ "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
+ "sllv %[y], %[y], %[log_cnt] \n\t"
+ "srlv %[temp], %[v], %[log_cnt] \n\t"
+ : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
+ [temp]"=r"(temp)
+ : [c24]"r"(c24), [v]"r"(v)
+ );
+
+ log_2 = kLog2Table[temp] + log_cnt;
+ if (v >= APPROX_LOG_MAX) {
+ // Since the division is still expensive, add this correction factor only
+ // for large values of 'v'.
+
+ const uint32_t correction = (23 * (v & (y - 1))) >> 4;
+ log_2 += (double)correction / v;
+ }
+ return (float)log_2;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * log((double)v));
+ }
+}
+
+// C version of this function:
+// int i = 0;
+// int64_t cost = 0;
+// const uint32_t* pop = &population[4];
+// const uint32_t* LoopEnd = &population[length];
+// while (pop != LoopEnd) {
+// ++i;
+// cost += i * *pop;
+// cost += i * *(pop + 1);
+// pop += 2;
+// }
+// return (double)cost;
+static double ExtraCost(const uint32_t* const population, int length) {
+ int i, temp0, temp1;
+ const uint32_t* pop = &population[4];
+ const uint32_t* const LoopEnd = &population[length];
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+ "xor %[i], %[i], %[i] \n\t"
+ "beq %[pop], %[LoopEnd], 2f \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[pop]) \n\t"
+ "lw %[temp1], 4(%[pop]) \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "addiu %[pop], %[pop], 8 \n\t"
+ "madd %[i], %[temp0] \n\t"
+ "madd %[i], %[temp1] \n\t"
+ "bne %[pop], %[LoopEnd], 1b \n\t"
+ "2: \n\t"
+ "mfhi %[temp0] \n\t"
+ "mflo %[temp1] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [i]"=&r"(i), [pop]"+r"(pop)
+ : [LoopEnd]"r"(LoopEnd)
+ : "memory", "hi", "lo"
+ );
+
+ return (double)((int64_t)temp0 << 32 | temp1);
+}
+
+// C version of this function:
+// int i = 0;
+// int64_t cost = 0;
+// const uint32_t* pX = &X[4];
+// const uint32_t* pY = &Y[4];
+// const uint32_t* LoopEnd = &X[length];
+// while (pX != LoopEnd) {
+// const uint32_t xy0 = *pX + *pY;
+// const uint32_t xy1 = *(pX + 1) + *(pY + 1);
+// ++i;
+// cost += i * xy0;
+// cost += i * xy1;
+// pX += 2;
+// pY += 2;
+// }
+// return (double)cost;
+static double ExtraCostCombined(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
+ int i, temp0, temp1, temp2, temp3;
+ const uint32_t* pX = &X[4];
+ const uint32_t* pY = &Y[4];
+ const uint32_t* const LoopEnd = &X[length];
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+ "xor %[i], %[i], %[i] \n\t"
+ "beq %[pX], %[LoopEnd], 2f \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[pX]) \n\t"
+ "lw %[temp1], 0(%[pY]) \n\t"
+ "lw %[temp2], 4(%[pX]) \n\t"
+ "lw %[temp3], 4(%[pY]) \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addiu %[pX], %[pX], 8 \n\t"
+ "addiu %[pY], %[pY], 8 \n\t"
+ "madd %[i], %[temp0] \n\t"
+ "madd %[i], %[temp2] \n\t"
+ "bne %[pX], %[LoopEnd], 1b \n\t"
+ "2: \n\t"
+ "mfhi %[temp0] \n\t"
+ "mflo %[temp1] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY)
+ : [LoopEnd]"r"(LoopEnd)
+ : "memory", "hi", "lo"
+ );
+
+ return (double)((int64_t)temp0 << 32 | temp1);
+}
+
+#define HUFFMAN_COST_PASS \
+ __asm__ volatile( \
+ "sll %[temp1], %[temp0], 3 \n\t" \
+ "addiu %[temp3], %[streak], -3 \n\t" \
+ "addu %[temp2], %[pstreaks], %[temp1] \n\t" \
+ "blez %[temp3], 1f \n\t" \
+ "srl %[temp1], %[temp1], 1 \n\t" \
+ "addu %[temp3], %[pcnts], %[temp1] \n\t" \
+ "lw %[temp0], 4(%[temp2]) \n\t" \
+ "lw %[temp1], 0(%[temp3]) \n\t" \
+ "addu %[temp0], %[temp0], %[streak] \n\t" \
+ "addiu %[temp1], %[temp1], 1 \n\t" \
+ "sw %[temp0], 4(%[temp2]) \n\t" \
+ "sw %[temp1], 0(%[temp3]) \n\t" \
+ "b 2f \n\t" \
+ "1: \n\t" \
+ "lw %[temp0], 0(%[temp2]) \n\t" \
+ "addu %[temp0], %[temp0], %[streak] \n\t" \
+ "sw %[temp0], 0(%[temp2]) \n\t" \
+ "2: \n\t" \
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
+ [temp3]"=&r"(temp3), [temp0]"+r"(temp0) \
+ : [pstreaks]"r"(pstreaks), [pcnts]"r"(pcnts), \
+ [streak]"r"(streak) \
+ : "memory" \
+ );
+
+// Returns the various RLE counts
+static VP8LStreaks HuffmanCostCount(const uint32_t* population, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ int* const pstreaks = &stats.streaks[0][0];
+ int* const pcnts = &stats.counts[0];
+ int temp0, temp1, temp2, temp3;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ ++streak;
+ if (population[i] == population[i + 1]) {
+ continue;
+ }
+ temp0 = (population[i] != 0);
+ HUFFMAN_COST_PASS
+ streak = 0;
+ }
+ ++streak;
+ temp0 = (population[i] != 0);
+ HUFFMAN_COST_PASS
+
+ return stats;
+}
+
+static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X,
+ const uint32_t* Y, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ int* const pstreaks = &stats.streaks[0][0];
+ int* const pcnts = &stats.counts[0];
+ int temp0, temp1, temp2, temp3;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ const uint32_t xy = X[i] + Y[i];
+ const uint32_t xy_next = X[i + 1] + Y[i + 1];
+ ++streak;
+ if (xy == xy_next) {
+ continue;
+ }
+ temp0 = (xy != 0);
+ HUFFMAN_COST_PASS
+ streak = 0;
+ }
+ {
+ const uint32_t xy = X[i] + Y[i];
+ ++streak;
+ temp0 = (xy != 0);
+ HUFFMAN_COST_PASS
+ }
+
+ return stats;
+}
+
+#define ASM_START \
+ __asm__ volatile( \
+ ".set push \n\t" \
+ ".set at \n\t" \
+ ".set macro \n\t" \
+ "1: \n\t"
+
+// P2 = P0 + P1
+// A..D - offsets
+// E - temp variable to tell macro
+// if pointer should be incremented
+// literal_ and successive histograms could be unaligned
+// so we must use ulw and usw
+#define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \
+ "ulw %[temp0], "#A"(%["#P0"]) \n\t" \
+ "ulw %[temp1], "#B"(%["#P0"]) \n\t" \
+ "ulw %[temp2], "#C"(%["#P0"]) \n\t" \
+ "ulw %[temp3], "#D"(%["#P0"]) \n\t" \
+ "ulw %[temp4], "#A"(%["#P1"]) \n\t" \
+ "ulw %[temp5], "#B"(%["#P1"]) \n\t" \
+ "ulw %[temp6], "#C"(%["#P1"]) \n\t" \
+ "ulw %[temp7], "#D"(%["#P1"]) \n\t" \
+ "addu %[temp4], %[temp4], %[temp0] \n\t" \
+ "addu %[temp5], %[temp5], %[temp1] \n\t" \
+ "addu %[temp6], %[temp6], %[temp2] \n\t" \
+ "addu %[temp7], %[temp7], %[temp3] \n\t" \
+ "addiu %["#P0"], %["#P0"], 16 \n\t" \
+ ".if "#E" == 1 \n\t" \
+ "addiu %["#P1"], %["#P1"], 16 \n\t" \
+ ".endif \n\t" \
+ "usw %[temp4], "#A"(%["#P2"]) \n\t" \
+ "usw %[temp5], "#B"(%["#P2"]) \n\t" \
+ "usw %[temp6], "#C"(%["#P2"]) \n\t" \
+ "usw %[temp7], "#D"(%["#P2"]) \n\t" \
+ "addiu %["#P2"], %["#P2"], 16 \n\t" \
+ "bne %["#P0"], %[LoopEnd], 1b \n\t" \
+ ".set pop \n\t" \
+
+#define ASM_END_COMMON_0 \
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), \
+ [pa]"+r"(pa), [pout]"+r"(pout)
+
+#define ASM_END_COMMON_1 \
+ : [LoopEnd]"r"(LoopEnd) \
+ : "memory", "at" \
+ );
+
+#define ASM_END_0 \
+ ASM_END_COMMON_0 \
+ , [pb]"+r"(pb) \
+ ASM_END_COMMON_1
+
+#define ASM_END_1 \
+ ASM_END_COMMON_0 \
+ ASM_END_COMMON_1
+
+#define ADD_VECTOR(A, B, OUT, SIZE, EXTRA_SIZE) do { \
+ const uint32_t* pa = (const uint32_t*)(A); \
+ const uint32_t* pb = (const uint32_t*)(B); \
+ uint32_t* pout = (uint32_t*)(OUT); \
+ const uint32_t* const LoopEnd = pa + (SIZE); \
+ assert((SIZE) % 4 == 0); \
+ ASM_START \
+ ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) \
+ ASM_END_0 \
+ if ((EXTRA_SIZE) > 0) { \
+ const int last = (EXTRA_SIZE); \
+ int i; \
+ for (i = 0; i < last; ++i) pout[i] = pa[i] + pb[i]; \
+ } \
+} while (0)
+
+#define ADD_VECTOR_EQ(A, OUT, SIZE, EXTRA_SIZE) do { \
+ const uint32_t* pa = (const uint32_t*)(A); \
+ uint32_t* pout = (uint32_t*)(OUT); \
+ const uint32_t* const LoopEnd = pa + (SIZE); \
+ assert((SIZE) % 4 == 0); \
+ ASM_START \
+ ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) \
+ ASM_END_1 \
+ if ((EXTRA_SIZE) > 0) { \
+ const int last = (EXTRA_SIZE); \
+ int i; \
+ for (i = 0; i < last; ++i) pout[i] += pa[i]; \
+ } \
+} while (0)
+
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ const int extra_cache_size = VP8LHistogramNumCodes(a->palette_code_bits_)
+ - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+
+ if (b != out) {
+ ADD_VECTOR(a->literal_, b->literal_, out->literal_,
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
+ ADD_VECTOR(a->distance_, b->distance_, out->distance_,
+ NUM_DISTANCE_CODES, 0);
+ ADD_VECTOR(a->red_, b->red_, out->red_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
+ } else {
+ ADD_VECTOR_EQ(a->literal_, out->literal_,
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
+ ADD_VECTOR_EQ(a->distance_, out->distance_, NUM_DISTANCE_CODES, 0);
+ ADD_VECTOR_EQ(a->red_, out->red_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR_EQ(a->blue_, out->blue_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR_EQ(a->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
+ }
+}
+
+#undef ADD_VECTOR_EQ
+#undef ADD_VECTOR
+#undef ASM_END_1
+#undef ASM_END_0
+#undef ASM_END_COMMON_1
+#undef ASM_END_COMMON_0
+#undef ADD_TO_OUT
+#undef ASM_START
+
+#endif // WEBP_USE_MIPS32
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LDspInitMIPS32(void);
+
+void VP8LDspInitMIPS32(void) {
+#if defined(WEBP_USE_MIPS32)
+ VP8LFastSLog2Slow = FastSLog2Slow;
+ VP8LFastLog2Slow = FastLog2Slow;
+ VP8LExtraCost = ExtraCost;
+ VP8LExtraCostCombined = ExtraCostCombined;
+ VP8LHuffmanCostCount = HuffmanCostCount;
+ VP8LHuffmanCostCombinedCount = HuffmanCostCombinedCount;
+ VP8LHistogramAdd = HistogramAdd;
+#endif // WEBP_USE_MIPS32
+}
diff --git a/src/3rdparty/libwebp/src/dsp/lossless_neon.c b/src/3rdparty/libwebp/src/dsp/lossless_neon.c
new file mode 100644
index 0000000..8c82b19
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/lossless_neon.c
@@ -0,0 +1,357 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON variant of methods for lossless decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <arm_neon.h>
+
+#include "./lossless.h"
+#include "./neon.h"
+
+//------------------------------------------------------------------------------
+// Colorspace conversion functions
+
+#if !defined(WORK_AROUND_GCC)
+// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for
+// gcc-4.8.x at least.
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ // swap B and R. (VSWP d0,d2 has no intrinsics equivalent!)
+ const uint8x16_t tmp = pixel.val[0];
+ pixel.val[0] = pixel.val[2];
+ pixel.val[2] = tmp;
+ vst4q_u8(dst, pixel);
+ dst += 64;
+ }
+ VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ const uint8x16x3_t tmp = { { pixel.val[0], pixel.val[1], pixel.val[2] } };
+ vst3q_u8(dst, tmp);
+ dst += 48;
+ }
+ VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs
+}
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ const uint8x16x3_t tmp = { { pixel.val[2], pixel.val[1], pixel.val[0] } };
+ vst3q_u8(dst, tmp);
+ dst += 48;
+ }
+ VP8LConvertBGRAToRGB_C(src, num_pixels & 15, dst); // left-overs
+}
+
+#else // WORK_AROUND_GCC
+
+// gcc-4.6.0 fallback
+
+static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 };
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~1);
+ const uint8x8_t shuffle = vld1_u8(kRGBAShuffle);
+ for (; src < end; src += 2) {
+ const uint8x8_t pixels = vld1_u8((uint8_t*)src);
+ vst1_u8(dst, vtbl1_u8(pixels, shuffle));
+ dst += 8;
+ }
+ VP8LConvertBGRAToRGBA_C(src, num_pixels & 1, dst); // left-overs
+}
+
+static const uint8_t kBGRShuffle[3][8] = {
+ { 0, 1, 2, 4, 5, 6, 8, 9 },
+ { 10, 12, 13, 14, 16, 17, 18, 20 },
+ { 21, 22, 24, 25, 26, 28, 29, 30 }
+};
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~7);
+ const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]);
+ const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]);
+ const uint8x8_t shuffle2 = vld1_u8(kBGRShuffle[2]);
+ for (; src < end; src += 8) {
+ uint8x8x4_t pixels;
+ INIT_VECTOR4(pixels,
+ vld1_u8((const uint8_t*)(src + 0)),
+ vld1_u8((const uint8_t*)(src + 2)),
+ vld1_u8((const uint8_t*)(src + 4)),
+ vld1_u8((const uint8_t*)(src + 6)));
+ vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0));
+ vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1));
+ vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2));
+ dst += 8 * 3;
+ }
+ VP8LConvertBGRAToBGR_C(src, num_pixels & 7, dst); // left-overs
+}
+
+static const uint8_t kRGBShuffle[3][8] = {
+ { 2, 1, 0, 6, 5, 4, 10, 9 },
+ { 8, 14, 13, 12, 18, 17, 16, 22 },
+ { 21, 20, 26, 25, 24, 30, 29, 28 }
+};
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~7);
+ const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]);
+ const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]);
+ const uint8x8_t shuffle2 = vld1_u8(kRGBShuffle[2]);
+ for (; src < end; src += 8) {
+ uint8x8x4_t pixels;
+ INIT_VECTOR4(pixels,
+ vld1_u8((const uint8_t*)(src + 0)),
+ vld1_u8((const uint8_t*)(src + 2)),
+ vld1_u8((const uint8_t*)(src + 4)),
+ vld1_u8((const uint8_t*)(src + 6)));
+ vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0));
+ vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1));
+ vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2));
+ dst += 8 * 3;
+ }
+ VP8LConvertBGRAToRGB_C(src, num_pixels & 7, dst); // left-overs
+}
+
+#endif // !WORK_AROUND_GCC
+
+//------------------------------------------------------------------------------
+
+#ifdef USE_INTRINSICS
+
+static WEBP_INLINE uint32_t Average2(const uint32_t* const a,
+ const uint32_t* const b) {
+ const uint8x8_t a0 = vreinterpret_u8_u64(vcreate_u64(*a));
+ const uint8x8_t b0 = vreinterpret_u8_u64(vcreate_u64(*b));
+ const uint8x8_t avg = vhadd_u8(a0, b0);
+ return vget_lane_u32(vreinterpret_u32_u8(avg), 0);
+}
+
+static WEBP_INLINE uint32_t Average3(const uint32_t* const a,
+ const uint32_t* const b,
+ const uint32_t* const c) {
+ const uint8x8_t a0 = vreinterpret_u8_u64(vcreate_u64(*a));
+ const uint8x8_t b0 = vreinterpret_u8_u64(vcreate_u64(*b));
+ const uint8x8_t c0 = vreinterpret_u8_u64(vcreate_u64(*c));
+ const uint8x8_t avg1 = vhadd_u8(a0, c0);
+ const uint8x8_t avg2 = vhadd_u8(avg1, b0);
+ return vget_lane_u32(vreinterpret_u32_u8(avg2), 0);
+}
+
+static WEBP_INLINE uint32_t Average4(const uint32_t* const a,
+ const uint32_t* const b,
+ const uint32_t* const c,
+ const uint32_t* const d) {
+ const uint8x8_t a0 = vreinterpret_u8_u64(vcreate_u64(*a));
+ const uint8x8_t b0 = vreinterpret_u8_u64(vcreate_u64(*b));
+ const uint8x8_t c0 = vreinterpret_u8_u64(vcreate_u64(*c));
+ const uint8x8_t d0 = vreinterpret_u8_u64(vcreate_u64(*d));
+ const uint8x8_t avg1 = vhadd_u8(a0, b0);
+ const uint8x8_t avg2 = vhadd_u8(c0, d0);
+ const uint8x8_t avg3 = vhadd_u8(avg1, avg2);
+ return vget_lane_u32(vreinterpret_u32_u8(avg3), 0);
+}
+
+static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+ return Average3(&left, top + 0, top + 1);
+}
+
+static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+ return Average2(&left, top - 1);
+}
+
+static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+ return Average2(&left, top + 0);
+}
+
+static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return Average2(top - 1, top + 0);
+}
+
+static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return Average2(top + 0, top + 1);
+}
+
+static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+ return Average4(&left, top - 1, top + 0, top + 1);
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE uint32_t Select(const uint32_t* const c0,
+ const uint32_t* const c1,
+ const uint32_t* const c2) {
+ const uint8x8_t p0 = vreinterpret_u8_u64(vcreate_u64(*c0));
+ const uint8x8_t p1 = vreinterpret_u8_u64(vcreate_u64(*c1));
+ const uint8x8_t p2 = vreinterpret_u8_u64(vcreate_u64(*c2));
+ const uint8x8_t bc = vabd_u8(p1, p2); // |b-c|
+ const uint8x8_t ac = vabd_u8(p0, p2); // |a-c|
+ const int16x4_t sum_bc = vreinterpret_s16_u16(vpaddl_u8(bc));
+ const int16x4_t sum_ac = vreinterpret_s16_u16(vpaddl_u8(ac));
+ const int32x2_t diff = vpaddl_s16(vsub_s16(sum_bc, sum_ac));
+ const int32_t pa_minus_pb = vget_lane_s32(diff, 0);
+ return (pa_minus_pb <= 0) ? *c0 : *c1;
+}
+
+static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+ return Select(top + 0, &left, top - 1);
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFull(const uint32_t* const c0,
+ const uint32_t* const c1,
+ const uint32_t* const c2) {
+ const uint8x8_t p0 = vreinterpret_u8_u64(vcreate_u64(*c0));
+ const uint8x8_t p1 = vreinterpret_u8_u64(vcreate_u64(*c1));
+ const uint8x8_t p2 = vreinterpret_u8_u64(vcreate_u64(*c2));
+ const uint16x8_t sum0 = vaddl_u8(p0, p1); // add and widen
+ const uint16x8_t sum1 = vqsubq_u16(sum0, vmovl_u8(p2)); // widen and subtract
+ const uint8x8_t out = vqmovn_u16(sum1); // narrow and clamp
+ return vget_lane_u32(vreinterpret_u32_u8(out), 0);
+}
+
+static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+ return ClampedAddSubtractFull(&left, top + 0, top - 1);
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf(const uint32_t* const c0,
+ const uint32_t* const c1,
+ const uint32_t* const c2) {
+ const uint8x8_t p0 = vreinterpret_u8_u64(vcreate_u64(*c0));
+ const uint8x8_t p1 = vreinterpret_u8_u64(vcreate_u64(*c1));
+ const uint8x8_t p2 = vreinterpret_u8_u64(vcreate_u64(*c2));
+ const uint8x8_t avg = vhadd_u8(p0, p1); // Average(c0,c1)
+ const uint8x8_t ab = vshr_n_u8(vqsub_u8(avg, p2), 1); // (a-b)>>1 saturated
+ const uint8x8_t ba = vshr_n_u8(vqsub_u8(p2, avg), 1); // (b-a)>>1 saturated
+ const uint8x8_t out = vqsub_u8(vqadd_u8(avg, ab), ba);
+ return vget_lane_u32(vreinterpret_u32_u8(out), 0);
+}
+
+static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+ return ClampedAddSubtractHalf(&left, top + 0, top - 1);
+}
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
+// non-standard versions there.
+#if defined(__APPLE__) && defined(__aarch64__) && \
+ defined(__apple_build_version__) && (__apple_build_version__< 6020037)
+#define USE_VTBLQ
+#endif
+
+#ifdef USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[16] = {
+ 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
+};
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x16_t shuffle) {
+ return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
+ vtbl1q_u8(argb, vget_high_u8(shuffle)));
+}
+#else // !USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x8_t shuffle) {
+ return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
+ vtbl1_u8(vget_high_u8(argb), shuffle));
+}
+#endif // USE_VTBLQ
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const uint32_t* const end = argb_data + (num_pixels & ~3);
+#ifdef USE_VTBLQ
+ const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
+#else
+ const uint8x8_t shuffle = vld1_u8(kGreenShuffle);
+#endif
+ for (; argb_data < end; argb_data += 4) {
+ const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data);
+ const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
+ vst1q_u8((uint8_t*)argb_data, vsubq_u8(argb, greens));
+ }
+ // fallthrough and finish off with plain-C
+ VP8LSubtractGreenFromBlueAndRed_C(argb_data, num_pixels & 3);
+}
+
+static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const uint32_t* const end = argb_data + (num_pixels & ~3);
+#ifdef USE_VTBLQ
+ const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
+#else
+ const uint8x8_t shuffle = vld1_u8(kGreenShuffle);
+#endif
+ for (; argb_data < end; argb_data += 4) {
+ const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data);
+ const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
+ vst1q_u8((uint8_t*)argb_data, vaddq_u8(argb, greens));
+ }
+ // fallthrough and finish off with plain-C
+ VP8LAddGreenToBlueAndRed_C(argb_data, num_pixels & 3);
+}
+
+#undef USE_VTBLQ
+
+#endif // USE_INTRINSICS
+
+#endif // WEBP_USE_NEON
+
+//------------------------------------------------------------------------------
+
+extern void VP8LDspInitNEON(void);
+
+void VP8LDspInitNEON(void) {
+#if defined(WEBP_USE_NEON)
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
+
+#ifdef USE_INTRINSICS
+ VP8LPredictors[5] = Predictor5;
+ VP8LPredictors[6] = Predictor6;
+ VP8LPredictors[7] = Predictor7;
+ VP8LPredictors[8] = Predictor8;
+ VP8LPredictors[9] = Predictor9;
+ VP8LPredictors[10] = Predictor10;
+ VP8LPredictors[11] = Predictor11;
+ VP8LPredictors[12] = Predictor12;
+ VP8LPredictors[13] = Predictor13;
+
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+#endif
+
+#endif // WEBP_USE_NEON
+}
+
+//------------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/dsp/lossless_sse2.c b/src/3rdparty/libwebp/src/dsp/lossless_sse2.c
new file mode 100644
index 0000000..7130909
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/lossless_sse2.c
@@ -0,0 +1,535 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 variant of methods for lossless decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#include <assert.h>
+
+#if defined(WEBP_USE_SSE2)
+#include <emmintrin.h>
+#include "./lossless.h"
+
+//------------------------------------------------------------------------------
+// Predictor Transform
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
+ const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i V1 = _mm_add_epi16(C0, C1);
+ const __m128i V2 = _mm_sub_epi16(V1, C2);
+ const __m128i b = _mm_packus_epi16(V2, V2);
+ const uint32_t output = _mm_cvtsi128_si32(b);
+ return output;
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
+ const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i avg = _mm_add_epi16(C1, C0);
+ const __m128i A0 = _mm_srli_epi16(avg, 1);
+ const __m128i A1 = _mm_sub_epi16(A0, B0);
+ const __m128i BgtA = _mm_cmpgt_epi16(B0, A0);
+ const __m128i A2 = _mm_sub_epi16(A1, BgtA);
+ const __m128i A3 = _mm_srai_epi16(A2, 1);
+ const __m128i A4 = _mm_add_epi16(A0, A3);
+ const __m128i A5 = _mm_packus_epi16(A4, A4);
+ const uint32_t output = _mm_cvtsi128_si32(A5);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
+ int pa_minus_pb;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A0 = _mm_cvtsi32_si128(a);
+ const __m128i B0 = _mm_cvtsi32_si128(b);
+ const __m128i C0 = _mm_cvtsi32_si128(c);
+ const __m128i AC0 = _mm_subs_epu8(A0, C0);
+ const __m128i CA0 = _mm_subs_epu8(C0, A0);
+ const __m128i BC0 = _mm_subs_epu8(B0, C0);
+ const __m128i CB0 = _mm_subs_epu8(C0, B0);
+ const __m128i AC = _mm_or_si128(AC0, CA0);
+ const __m128i BC = _mm_or_si128(BC0, CB0);
+ const __m128i pa = _mm_unpacklo_epi8(AC, zero); // |a - c|
+ const __m128i pb = _mm_unpacklo_epi8(BC, zero); // |b - c|
+ const __m128i diff = _mm_sub_epi16(pb, pa);
+ {
+ int16_t out[8];
+ _mm_storeu_si128((__m128i*)out, diff);
+ pa_minus_pb = out[0] + out[1] + out[2] + out[3];
+ }
+ return (pa_minus_pb <= 0) ? a : b;
+}
+
+static WEBP_INLINE __m128i Average2_128i(uint32_t a0, uint32_t a1) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i sum = _mm_add_epi16(A1, A0);
+ const __m128i avg = _mm_srli_epi16(sum, 1);
+ return avg;
+}
+
+static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
+ const __m128i avg = Average2_128i(a0, a1);
+ const __m128i A2 = _mm_packus_epi16(avg, avg);
+ const uint32_t output = _mm_cvtsi128_si32(A2);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i avg1 = Average2_128i(a0, a2);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i sum = _mm_add_epi16(avg1, A1);
+ const __m128i avg2 = _mm_srli_epi16(sum, 1);
+ const __m128i A2 = _mm_packus_epi16(avg2, avg2);
+ const uint32_t output = _mm_cvtsi128_si32(A2);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
+ uint32_t a2, uint32_t a3) {
+ const __m128i avg1 = Average2_128i(a0, a1);
+ const __m128i avg2 = Average2_128i(a2, a3);
+ const __m128i sum = _mm_add_epi16(avg2, avg1);
+ const __m128i avg3 = _mm_srli_epi16(sum, 1);
+ const __m128i A0 = _mm_packus_epi16(avg3, avg3);
+ const uint32_t output = _mm_cvtsi128_si32(A0);
+ return output;
+}
+
+static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average3(left, top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[0]);
+ return pred;
+}
+static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[-1], top[0]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[0], top[1]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Select(top[0], left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
+ return pred;
+}
+static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
+ return pred;
+}
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const __m128i mask = _mm_set1_epi32(0x0000ff00);
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
+ const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|...
+ const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|...
+ const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|...
+ const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g);
+ const __m128i out = _mm_sub_epi8(in, in_0g0g);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i);
+}
+
+static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const __m128i mask = _mm_set1_epi32(0x0000ff00);
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
+ const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|...
+ const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|...
+ const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|...
+ const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g);
+ const __m128i out = _mm_add_epi8(in, in_0g0g);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LAddGreenToBlueAndRed_C(argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Color Transform
+
+static WEBP_INLINE __m128i ColorTransformDelta(__m128i color_pred,
+ __m128i color) {
+ // We simulate signed 8-bit multiplication as:
+ // * Left shift the two (8-bit) numbers by 8 bits,
+ // * Perform a 16-bit signed multiplication and retain the higher 16-bits.
+ const __m128i color_pred_shifted = _mm_slli_epi32(color_pred, 8);
+ const __m128i color_shifted = _mm_slli_epi32(color, 8);
+ // Note: This performs multiplication on 8 packed 16-bit numbers, 4 of which
+ // happen to be zeroes.
+ const __m128i signed_mult =
+ _mm_mulhi_epi16(color_pred_shifted, color_shifted);
+ return _mm_srli_epi32(signed_mult, 5);
+}
+
+static WEBP_INLINE void TransformColor(const VP8LMultipliers* const m,
+ uint32_t* argb_data,
+ int num_pixels) {
+ const __m128i g_to_r = _mm_set1_epi32(m->green_to_red_); // multipliers
+ const __m128i g_to_b = _mm_set1_epi32(m->green_to_blue_);
+ const __m128i r_to_b = _mm_set1_epi32(m->red_to_blue_);
+
+ int i;
+
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
+ const __m128i alpha_green_mask = _mm_set1_epi32(0xff00ff00); // masks
+ const __m128i red_mask = _mm_set1_epi32(0x00ff0000);
+ const __m128i green_mask = _mm_set1_epi32(0x0000ff00);
+ const __m128i lower_8bit_mask = _mm_set1_epi32(0x000000ff);
+ const __m128i ag = _mm_and_si128(in, alpha_green_mask); // alpha, green
+ const __m128i r = _mm_srli_epi32(_mm_and_si128(in, red_mask), 16);
+ const __m128i g = _mm_srli_epi32(_mm_and_si128(in, green_mask), 8);
+ const __m128i b = in;
+
+ const __m128i r_delta = ColorTransformDelta(g_to_r, g); // red
+ const __m128i r_new =
+ _mm_and_si128(_mm_sub_epi32(r, r_delta), lower_8bit_mask);
+ const __m128i r_new_shifted = _mm_slli_epi32(r_new, 16);
+
+ const __m128i b_delta_1 = ColorTransformDelta(g_to_b, g); // blue
+ const __m128i b_delta_2 = ColorTransformDelta(r_to_b, r);
+ const __m128i b_delta = _mm_add_epi32(b_delta_1, b_delta_2);
+ const __m128i b_new =
+ _mm_and_si128(_mm_sub_epi32(b, b_delta), lower_8bit_mask);
+
+ const __m128i out = _mm_or_si128(_mm_or_si128(ag, r_new_shifted), b_new);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+
+ // Fall-back to C-version for left-overs.
+ VP8LTransformColor_C(m, argb_data + i, num_pixels - i);
+}
+
+static WEBP_INLINE void TransformColorInverse(const VP8LMultipliers* const m,
+ uint32_t* argb_data,
+ int num_pixels) {
+ const __m128i g_to_r = _mm_set1_epi32(m->green_to_red_); // multipliers
+ const __m128i g_to_b = _mm_set1_epi32(m->green_to_blue_);
+ const __m128i r_to_b = _mm_set1_epi32(m->red_to_blue_);
+
+ int i;
+
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
+ const __m128i alpha_green_mask = _mm_set1_epi32(0xff00ff00); // masks
+ const __m128i red_mask = _mm_set1_epi32(0x00ff0000);
+ const __m128i green_mask = _mm_set1_epi32(0x0000ff00);
+ const __m128i lower_8bit_mask = _mm_set1_epi32(0x000000ff);
+ const __m128i ag = _mm_and_si128(in, alpha_green_mask); // alpha, green
+ const __m128i r = _mm_srli_epi32(_mm_and_si128(in, red_mask), 16);
+ const __m128i g = _mm_srli_epi32(_mm_and_si128(in, green_mask), 8);
+ const __m128i b = in;
+
+ const __m128i r_delta = ColorTransformDelta(g_to_r, g); // red
+ const __m128i r_new =
+ _mm_and_si128(_mm_add_epi32(r, r_delta), lower_8bit_mask);
+ const __m128i r_new_shifted = _mm_slli_epi32(r_new, 16);
+
+ const __m128i b_delta_1 = ColorTransformDelta(g_to_b, g); // blue
+ const __m128i b_delta_2 = ColorTransformDelta(r_to_b, r_new);
+ const __m128i b_delta = _mm_add_epi32(b_delta_1, b_delta_2);
+ const __m128i b_new =
+ _mm_and_si128(_mm_add_epi32(b, b_delta), lower_8bit_mask);
+
+ const __m128i out = _mm_or_si128(_mm_or_si128(ag, r_new_shifted), b_new);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+
+ // Fall-back to C-version for left-overs.
+ VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Color-space conversion functions
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i rg0 = _mm_unpacklo_epi8(rb0, ga0); // r0g0r1g1 ... r6g6r7g7
+ const __m128i ba0 = _mm_unpackhi_epi8(rb0, ga0); // b0a0b1a1 ... b6a6b7a7
+ const __m128i rgba0 = _mm_unpacklo_epi16(rg0, ba0); // rgba0|rgba1...
+ const __m128i rgba4 = _mm_unpackhi_epi16(rg0, ba0); // rgba4|rgba5...
+ _mm_storeu_si128(out++, rgba0);
+ _mm_storeu_si128(out++, rgba4);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToRGBA4444(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
+ const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i ga1 = _mm_srli_epi16(ga0, 4); // g0-|g1-|...|a6-|a7-
+ const __m128i rb1 = _mm_and_si128(rb0, mask_0xf0); // -r0|-r1|...|-b6|-a7
+ const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7-
+ const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7
+ const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0
+#ifdef WEBP_SWAP_16BIT_CSP
+ const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7
+#else
+ const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7
+#endif
+ _mm_storeu_si128(out++, rgba);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToRGB565(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
+ const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
+ const __m128i mask_0x07 = _mm_set1_epi8(0x07);
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i rb1 = _mm_and_si128(rb0, mask_0xf8); // -r0..-r7|-b0..-b7
+ const __m128i g_lo1 = _mm_srli_epi16(ga0, 5);
+ const __m128i g_lo2 = _mm_and_si128(g_lo1, mask_0x07); // g0-...g7-|xx (3b)
+ const __m128i g_hi1 = _mm_slli_epi16(ga0, 3);
+ const __m128i g_hi2 = _mm_and_si128(g_hi1, mask_0xe0); // -g0...-g7|xx (3b)
+ const __m128i b0 = _mm_srli_si128(rb1, 8); // -b0...-b7|0
+ const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx
+ const __m128i b1 = _mm_srli_epi16(b0, 3);
+ const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx
+#ifdef WEBP_SWAP_16BIT_CSP
+ const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7
+#else
+ const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7
+#endif
+ _mm_storeu_si128(out++, rgba);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
+ const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
+ const __m128i* in = (const __m128i*)src;
+ const uint8_t* const end = dst + num_pixels * 3;
+ // the last storel_epi64 below writes 8 bytes starting at offset 18
+ while (dst + 26 <= end) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i a0l = _mm_and_si128(bgra0, mask_l); // bgr0|0|bgr0|0
+ const __m128i a4l = _mm_and_si128(bgra4, mask_l); // bgr0|0|bgr0|0
+ const __m128i a0h = _mm_and_si128(bgra0, mask_h); // 0|bgr0|0|bgr0
+ const __m128i a4h = _mm_and_si128(bgra4, mask_h); // 0|bgr0|0|bgr0
+ const __m128i b0h = _mm_srli_epi64(a0h, 8); // 000b|gr00|000b|gr00
+ const __m128i b4h = _mm_srli_epi64(a4h, 8); // 000b|gr00|000b|gr00
+ const __m128i c0 = _mm_or_si128(a0l, b0h); // rgbrgb00|rgbrgb00
+ const __m128i c4 = _mm_or_si128(a4l, b4h); // rgbrgb00|rgbrgb00
+ const __m128i c2 = _mm_srli_si128(c0, 8);
+ const __m128i c6 = _mm_srli_si128(c4, 8);
+ _mm_storel_epi64((__m128i*)(dst + 0), c0);
+ _mm_storel_epi64((__m128i*)(dst + 6), c2);
+ _mm_storel_epi64((__m128i*)(dst + 12), c4);
+ _mm_storel_epi64((__m128i*)(dst + 18), c6);
+ dst += 24;
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst);
+}
+
+//------------------------------------------------------------------------------
+
+#define LINE_SIZE 16 // 8 or 16
+static void AddVector(const uint32_t* a, const uint32_t* b, uint32_t* out,
+ int size) {
+ int i;
+ assert(size % LINE_SIZE == 0);
+ for (i = 0; i < size; i += LINE_SIZE) {
+ const __m128i a0 = _mm_loadu_si128((__m128i*)&a[i + 0]);
+ const __m128i a1 = _mm_loadu_si128((__m128i*)&a[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i a2 = _mm_loadu_si128((__m128i*)&a[i + 8]);
+ const __m128i a3 = _mm_loadu_si128((__m128i*)&a[i + 12]);
+#endif
+ const __m128i b0 = _mm_loadu_si128((__m128i*)&b[i + 0]);
+ const __m128i b1 = _mm_loadu_si128((__m128i*)&b[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i b2 = _mm_loadu_si128((__m128i*)&b[i + 8]);
+ const __m128i b3 = _mm_loadu_si128((__m128i*)&b[i + 12]);
+#endif
+ _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0));
+ _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1));
+#if (LINE_SIZE == 16)
+ _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2));
+ _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
+#endif
+ }
+}
+
+static void AddVectorEq(const uint32_t* a, uint32_t* out, int size) {
+ int i;
+ assert(size % LINE_SIZE == 0);
+ for (i = 0; i < size; i += LINE_SIZE) {
+ const __m128i a0 = _mm_loadu_si128((__m128i*)&a[i + 0]);
+ const __m128i a1 = _mm_loadu_si128((__m128i*)&a[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i a2 = _mm_loadu_si128((__m128i*)&a[i + 8]);
+ const __m128i a3 = _mm_loadu_si128((__m128i*)&a[i + 12]);
+#endif
+ const __m128i b0 = _mm_loadu_si128((__m128i*)&out[i + 0]);
+ const __m128i b1 = _mm_loadu_si128((__m128i*)&out[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i b2 = _mm_loadu_si128((__m128i*)&out[i + 8]);
+ const __m128i b3 = _mm_loadu_si128((__m128i*)&out[i + 12]);
+#endif
+ _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0));
+ _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1));
+#if (LINE_SIZE == 16)
+ _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2));
+ _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
+#endif
+ }
+}
+#undef LINE_SIZE
+
+// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
+// that's ok since the histogram values are less than 1<<28 (max picture size).
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ int i;
+ const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+ if (b != out) {
+ AddVector(a->literal_, b->literal_, out->literal_, NUM_LITERAL_CODES);
+ AddVector(a->red_, b->red_, out->red_, NUM_LITERAL_CODES);
+ AddVector(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES);
+ AddVector(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES);
+ } else {
+ AddVectorEq(a->literal_, out->literal_, NUM_LITERAL_CODES);
+ AddVectorEq(a->red_, out->red_, NUM_LITERAL_CODES);
+ AddVectorEq(a->blue_, out->blue_, NUM_LITERAL_CODES);
+ AddVectorEq(a->alpha_, out->alpha_, NUM_LITERAL_CODES);
+ }
+ for (i = NUM_LITERAL_CODES; i < literal_size; ++i) {
+ out->literal_[i] = a->literal_[i] + b->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] = a->distance_[i] + b->distance_[i];
+ }
+}
+
+#endif // WEBP_USE_SSE2
+
+//------------------------------------------------------------------------------
+
+extern void VP8LDspInitSSE2(void);
+
+void VP8LDspInitSSE2(void) {
+#if defined(WEBP_USE_SSE2)
+ VP8LPredictors[5] = Predictor5;
+ VP8LPredictors[6] = Predictor6;
+ VP8LPredictors[7] = Predictor7;
+ VP8LPredictors[8] = Predictor8;
+ VP8LPredictors[9] = Predictor9;
+ VP8LPredictors[10] = Predictor10;
+ VP8LPredictors[11] = Predictor11;
+ VP8LPredictors[12] = Predictor12;
+ VP8LPredictors[13] = Predictor13;
+
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+
+ VP8LTransformColor = TransformColor;
+ VP8LTransformColorInverse = TransformColorInverse;
+
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
+ VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
+ VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+
+ VP8LHistogramAdd = HistogramAdd;
+#endif // WEBP_USE_SSE2
+}
+
+//------------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/dsp/neon.h b/src/3rdparty/libwebp/src/dsp/neon.h
new file mode 100644
index 0000000..7e06eae
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/neon.h
@@ -0,0 +1,82 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON common code.
+
+#ifndef WEBP_DSP_NEON_H_
+#define WEBP_DSP_NEON_H_
+
+#include <arm_neon.h>
+
+#include "./dsp.h"
+
+// Right now, some intrinsics functions seem slower, so we disable them
+// everywhere except aarch64 where the inline assembly is incompatible.
+#if defined(__aarch64__)
+#define USE_INTRINSICS // use intrinsics when possible
+#endif
+
+#define INIT_VECTOR2(v, a, b) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+} while (0)
+
+#define INIT_VECTOR3(v, a, b, c) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+ v.val[2] = c; \
+} while (0)
+
+#define INIT_VECTOR4(v, a, b, c, d) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+ v.val[2] = c; \
+ v.val[3] = d; \
+} while (0)
+
+// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
+// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
+// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
+#if !(LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
+#define WORK_AROUND_GCC
+#endif
+
+static WEBP_INLINE int32x4x4_t Transpose4x4(const int32x4x4_t rows) {
+ uint64x2x2_t row01, row23;
+
+ row01.val[0] = vreinterpretq_u64_s32(rows.val[0]);
+ row01.val[1] = vreinterpretq_u64_s32(rows.val[1]);
+ row23.val[0] = vreinterpretq_u64_s32(rows.val[2]);
+ row23.val[1] = vreinterpretq_u64_s32(rows.val[3]);
+ // Transpose 64-bit values (there's no vswp equivalent)
+ {
+ const uint64x1_t row0h = vget_high_u64(row01.val[0]);
+ const uint64x1_t row2l = vget_low_u64(row23.val[0]);
+ const uint64x1_t row1h = vget_high_u64(row01.val[1]);
+ const uint64x1_t row3l = vget_low_u64(row23.val[1]);
+ row01.val[0] = vcombine_u64(vget_low_u64(row01.val[0]), row2l);
+ row23.val[0] = vcombine_u64(row0h, vget_high_u64(row23.val[0]));
+ row01.val[1] = vcombine_u64(vget_low_u64(row01.val[1]), row3l);
+ row23.val[1] = vcombine_u64(row1h, vget_high_u64(row23.val[1]));
+ }
+ {
+ const int32x4x2_t out01 = vtrnq_s32(vreinterpretq_s32_u64(row01.val[0]),
+ vreinterpretq_s32_u64(row01.val[1]));
+ const int32x4x2_t out23 = vtrnq_s32(vreinterpretq_s32_u64(row23.val[0]),
+ vreinterpretq_s32_u64(row23.val[1]));
+ int32x4x4_t out;
+ out.val[0] = out01.val[0];
+ out.val[1] = out01.val[1];
+ out.val[2] = out23.val[0];
+ out.val[3] = out23.val[1];
+ return out;
+ }
+}
+
+#endif // WEBP_DSP_NEON_H_
diff --git a/src/3rdparty/libwebp/src/dsp/upsampling.c b/src/3rdparty/libwebp/src/dsp/upsampling.c
index 978e3ce..53c68d5 100644
--- a/src/3rdparty/libwebp/src/dsp/upsampling.c
+++ b/src/3rdparty/libwebp/src/dsp/upsampling.c
@@ -107,57 +107,6 @@ UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
#endif // FANCY_UPSAMPLING
//------------------------------------------------------------------------------
-// simple point-sampling
-
-#define SAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
-static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
- const uint8_t* u, const uint8_t* v, \
- uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
- int i; \
- for (i = 0; i < len - 1; i += 2) { \
- FUNC(top_y[0], u[0], v[0], top_dst); \
- FUNC(top_y[1], u[0], v[0], top_dst + XSTEP); \
- FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
- FUNC(bottom_y[1], u[0], v[0], bottom_dst + XSTEP); \
- top_y += 2; \
- bottom_y += 2; \
- u++; \
- v++; \
- top_dst += 2 * XSTEP; \
- bottom_dst += 2 * XSTEP; \
- } \
- if (i == len - 1) { /* last one */ \
- FUNC(top_y[0], u[0], v[0], top_dst); \
- FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
- } \
-}
-
-// All variants implemented.
-SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
-SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
-SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
-SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
-SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
-SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
-SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
-
-#undef SAMPLE_FUNC
-
-const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
- SampleRgbLinePair, // MODE_RGB
- SampleRgbaLinePair, // MODE_RGBA
- SampleBgrLinePair, // MODE_BGR
- SampleBgraLinePair, // MODE_BGRA
- SampleArgbLinePair, // MODE_ARGB
- SampleRgba4444LinePair, // MODE_RGBA_4444
- SampleRgb565LinePair, // MODE_RGB_565
- SampleRgbaLinePair, // MODE_rgbA
- SampleBgraLinePair, // MODE_bgrA
- SampleArgbLinePair, // MODE_Argb
- SampleRgba4444LinePair // MODE_rgbA_4444
-};
-
-//------------------------------------------------------------------------------
#if !defined(FANCY_UPSAMPLING)
#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \
@@ -235,85 +184,17 @@ const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
};
//------------------------------------------------------------------------------
-// Premultiplied modes
-
-// non dithered-modes
-
-// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
-// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
-// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
-#if 1 // (int)(x * a / 255.)
-#define MULTIPLIER(a) ((a) * 32897UL)
-#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
-#else // (int)(x * a / 255. + .5)
-#define MULTIPLIER(a) ((a) * 65793UL)
-#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
-#endif
-
-static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
- int w, int h, int stride) {
- while (h-- > 0) {
- uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
- const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t a = alpha[4 * i];
- if (a != 0xff) {
- const uint32_t mult = MULTIPLIER(a);
- rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
- rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
- rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
- }
- }
- rgba += stride;
- }
-}
-#undef MULTIPLIER
-#undef PREMULTIPLY
-
-// rgbA4444
-
-#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
-
-static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
- return (x & 0xf0) | (x >> 4);
-}
-
-static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
- return (x & 0x0f) | (x << 4);
-}
-
-static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
- return (x * m) >> 16;
-}
+// Main calls
-static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
- int w, int h, int stride) {
- while (h-- > 0) {
- int i;
- for (i = 0; i < w; ++i) {
- const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
- const uint32_t mult = MULTIPLIER(a);
- const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
- const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
- const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
- rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
- rgba4444[2 * i + 1] = (b & 0xf0) | a;
- }
- rgba4444 += stride;
- }
-}
-#undef MULTIPLIER
-
-void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
- = ApplyAlphaMultiply;
-void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
- = ApplyAlphaMultiply4444;
+extern void WebPInitUpsamplersSSE2(void);
+extern void WebPInitUpsamplersNEON(void);
-//------------------------------------------------------------------------------
-// Main call
+static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 =
+ (VP8CPUInfo)&upsampling_last_cpuinfo_used2;
void WebPInitUpsamplers(void) {
+ if (upsampling_last_cpuinfo_used2 == VP8GetCPUInfo) return;
+
#ifdef FANCY_UPSAMPLING
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
@@ -322,45 +203,26 @@ void WebPInitUpsamplers(void) {
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
-
- // If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
- if (VP8GetCPUInfo(kSSE2)) {
- WebPInitUpsamplersSSE2();
- }
-#endif
-#if defined(WEBP_USE_NEON)
- if (VP8GetCPUInfo(kNEON)) {
- WebPInitUpsamplersNEON();
- }
-#endif
- }
-#endif // FANCY_UPSAMPLING
-}
-
-void WebPInitPremultiply(void) {
- WebPApplyAlphaMultiply = ApplyAlphaMultiply;
- WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
-
-#ifdef FANCY_UPSAMPLING
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
- WebPInitPremultiplySSE2();
+ WebPInitUpsamplersSSE2();
}
#endif
#if defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
- WebPInitPremultiplyNEON();
+ WebPInitUpsamplersNEON();
}
#endif
}
#endif // FANCY_UPSAMPLING
+ upsampling_last_cpuinfo_used2 = VP8GetCPUInfo;
}
+//------------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/dsp/upsampling_neon.c b/src/3rdparty/libwebp/src/dsp/upsampling_neon.c
index 791222f..d31ed4d 100644
--- a/src/3rdparty/libwebp/src/dsp/upsampling_neon.c
+++ b/src/3rdparty/libwebp/src/dsp/upsampling_neon.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include <arm_neon.h>
#include <string.h>
+#include "./neon.h"
#include "./yuv.h"
#ifdef FANCY_UPSAMPLING
@@ -61,8 +62,9 @@
d = vrhadd_u8(d, diag1); \
\
{ \
- const uint8x8x2_t a_b = {{ a, b }}; \
- const uint8x8x2_t c_d = {{ c, d }}; \
+ uint8x8x2_t a_b, c_d; \
+ INIT_VECTOR2(a_b, a, b); \
+ INIT_VECTOR2(c_d, c, d); \
vst2_u8(out, a_b); \
vst2_u8(out + 32, c_d); \
} \
@@ -89,25 +91,29 @@ static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
static const int16_t kCoeffs[4] = { kYScale, kVToR, kUToG, kVToG };
-#define v255 vmov_n_u8(255)
+#define v255 vdup_n_u8(255)
#define STORE_Rgb(out, r, g, b) do { \
- const uint8x8x3_t r_g_b = {{ r, g, b }}; \
+ uint8x8x3_t r_g_b; \
+ INIT_VECTOR3(r_g_b, r, g, b); \
vst3_u8(out, r_g_b); \
} while (0)
#define STORE_Bgr(out, r, g, b) do { \
- const uint8x8x3_t b_g_r = {{ b, g, r }}; \
+ uint8x8x3_t b_g_r; \
+ INIT_VECTOR3(b_g_r, b, g, r); \
vst3_u8(out, b_g_r); \
} while (0)
#define STORE_Rgba(out, r, g, b) do { \
- const uint8x8x4_t r_g_b_v255 = {{ r, g, b, v255 }}; \
+ uint8x8x4_t r_g_b_v255; \
+ INIT_VECTOR4(r_g_b_v255, r, g, b, v255); \
vst4_u8(out, r_g_b_v255); \
} while (0)
#define STORE_Bgra(out, r, g, b) do { \
- const uint8x8x4_t b_g_r_v255 = {{ b, g, r, v255 }}; \
+ uint8x8x4_t b_g_r_v255; \
+ INIT_VECTOR4(b_g_r_v255, b, g, r, v255); \
vst4_u8(out, b_g_r_v255); \
} while (0)
@@ -190,9 +196,9 @@ static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \
const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
\
const int16x4_t cf16 = vld1_s16(kCoeffs); \
- const int32x2_t cf32 = vmov_n_s32(kUToB); \
- const uint8x8_t u16 = vmov_n_u8(16); \
- const uint8x8_t u128 = vmov_n_u8(128); \
+ const int32x2_t cf32 = vdup_n_s32(kUToB); \
+ const uint8x8_t u16 = vdup_n_u8(16); \
+ const uint8x8_t u128 = vdup_n_u8(128); \
\
/* Treat the first pixel in regular way */ \
assert(top_y != NULL); \
@@ -225,10 +231,10 @@ static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \
}
// NEON variants of the fancy upsampler.
-NEON_UPSAMPLE_FUNC(UpsampleRgbLinePairNEON, Rgb, 3)
-NEON_UPSAMPLE_FUNC(UpsampleBgrLinePairNEON, Bgr, 3)
-NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePairNEON, Rgba, 4)
-NEON_UPSAMPLE_FUNC(UpsampleBgraLinePairNEON, Bgra, 4)
+NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair, Rgb, 3)
+NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair, Bgr, 3)
+NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair, Rgba, 4)
+NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair, Bgra, 4)
#endif // FANCY_UPSAMPLING
@@ -236,30 +242,26 @@ NEON_UPSAMPLE_FUNC(UpsampleBgraLinePairNEON, Bgra, 4)
//------------------------------------------------------------------------------
+extern void WebPInitUpsamplersNEON(void);
+
#ifdef FANCY_UPSAMPLING
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
void WebPInitUpsamplersNEON(void) {
#if defined(WEBP_USE_NEON)
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairNEON;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairNEON;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairNEON;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairNEON;
-#endif // WEBP_USE_NEON
-}
-
-void WebPInitPremultiplyNEON(void) {
-#if defined(WEBP_USE_NEON)
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairNEON;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairNEON;
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
#endif // WEBP_USE_NEON
}
#else
// this empty function is to avoid an empty .o
-void WebPInitPremultiplyNEON(void) {}
+void WebPInitUpsamplersNEON(void) {}
#endif // FANCY_UPSAMPLING
-
diff --git a/src/3rdparty/libwebp/src/dsp/upsampling_sse2.c b/src/3rdparty/libwebp/src/dsp/upsampling_sse2.c
index 0db0798..45cf090 100644
--- a/src/3rdparty/libwebp/src/dsp/upsampling_sse2.c
+++ b/src/3rdparty/libwebp/src/dsp/upsampling_sse2.c
@@ -169,10 +169,10 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
}
// SSE2 variants of the fancy upsampler.
-SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4)
-SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
#undef GET_M
#undef PACK_AND_STORE
@@ -188,6 +188,8 @@ SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
//------------------------------------------------------------------------------
+extern void WebPInitUpsamplersSSE2(void);
+
#ifdef FANCY_UPSAMPLING
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
@@ -195,24 +197,18 @@ extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
void WebPInitUpsamplersSSE2(void) {
#if defined(WEBP_USE_SSE2)
VP8YUVInitSSE2();
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
-#endif // WEBP_USE_SSE2
-}
-
-void WebPInitPremultiplySSE2(void) {
-#if defined(WEBP_USE_SSE2)
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
#endif // WEBP_USE_SSE2
}
#else
// this empty function is to avoid an empty .o
-void WebPInitPremultiplySSE2(void) {}
+void WebPInitUpsamplersSSE2(void) {}
#endif // FANCY_UPSAMPLING
-
diff --git a/src/3rdparty/libwebp/src/dsp/yuv.c b/src/3rdparty/libwebp/src/dsp/yuv.c
index 4f9cafc..6f422da 100644
--- a/src/3rdparty/libwebp/src/dsp/yuv.c
+++ b/src/3rdparty/libwebp/src/dsp/yuv.c
@@ -7,13 +7,12 @@
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// YUV->RGB conversion function
+// YUV->RGB conversion functions
//
// Author: Skal (pascal.massimino@gmail.com)
#include "./yuv.h"
-
#if defined(WEBP_YUV_USE_TABLE)
static int done = 0;
@@ -68,140 +67,94 @@ void VP8YUVInit(void) {}
#endif // WEBP_YUV_USE_TABLE
//-----------------------------------------------------------------------------
-// SSE2 extras
-
-#if defined(WEBP_USE_SSE2)
-
-#ifdef FANCY_UPSAMPLING
-
-#include <emmintrin.h>
-#include <string.h> // for memcpy
-
-typedef union { // handy struct for converting SSE2 registers
- int32_t i32[4];
- uint8_t u8[16];
- __m128i m;
-} VP8kCstSSE2;
-
-static int done_sse2 = 0;
-static VP8kCstSSE2 VP8kUtoRGBA[256], VP8kVtoRGBA[256], VP8kYtoRGBA[256];
-
-void VP8YUVInitSSE2(void) {
- if (!done_sse2) {
- int i;
- for (i = 0; i < 256; ++i) {
- VP8kYtoRGBA[i].i32[0] =
- VP8kYtoRGBA[i].i32[1] =
- VP8kYtoRGBA[i].i32[2] = (i - 16) * kYScale + YUV_HALF2;
- VP8kYtoRGBA[i].i32[3] = 0xff << YUV_FIX2;
-
- VP8kUtoRGBA[i].i32[0] = 0;
- VP8kUtoRGBA[i].i32[1] = -kUToG * (i - 128);
- VP8kUtoRGBA[i].i32[2] = kUToB * (i - 128);
- VP8kUtoRGBA[i].i32[3] = 0;
-
- VP8kVtoRGBA[i].i32[0] = kVToR * (i - 128);
- VP8kVtoRGBA[i].i32[1] = -kVToG * (i - 128);
- VP8kVtoRGBA[i].i32[2] = 0;
- VP8kVtoRGBA[i].i32[3] = 0;
+// Plain-C version
+
+#define ROW_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ const uint8_t* const end = dst + (len & ~1) * XSTEP; \
+ while (dst != end) { \
+ FUNC(y[0], u[0], v[0], dst); \
+ FUNC(y[1], u[0], v[0], dst + XSTEP); \
+ y += 2; \
+ ++u; \
+ ++v; \
+ dst += 2 * XSTEP; \
+ } \
+ if (len & 1) { \
+ FUNC(y[0], u[0], v[0], dst); \
+ } \
+} \
+
+// All variants implemented.
+ROW_FUNC(YuvToRgbRow, VP8YuvToRgb, 3)
+ROW_FUNC(YuvToBgrRow, VP8YuvToBgr, 3)
+ROW_FUNC(YuvToRgbaRow, VP8YuvToRgba, 4)
+ROW_FUNC(YuvToBgraRow, VP8YuvToBgra, 4)
+ROW_FUNC(YuvToArgbRow, VP8YuvToArgb, 4)
+ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2)
+ROW_FUNC(YuvToRgb565Row, VP8YuvToRgb565, 2)
+
+#undef ROW_FUNC
+
+// Main call for processing a plane with a WebPSamplerRowFunc function:
+void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
+ const uint8_t* u, const uint8_t* v, int uv_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height, WebPSamplerRowFunc func) {
+ int j;
+ for (j = 0; j < height; ++j) {
+ func(y, u, v, dst, width);
+ y += y_stride;
+ if (j & 1) {
+ u += uv_stride;
+ v += uv_stride;
}
- done_sse2 = 1;
+ dst += dst_stride;
}
}
-static WEBP_INLINE __m128i VP8GetRGBA32b(int y, int u, int v) {
- const __m128i u_part = _mm_loadu_si128(&VP8kUtoRGBA[u].m);
- const __m128i v_part = _mm_loadu_si128(&VP8kVtoRGBA[v].m);
- const __m128i y_part = _mm_loadu_si128(&VP8kYtoRGBA[y].m);
- const __m128i uv_part = _mm_add_epi32(u_part, v_part);
- const __m128i rgba1 = _mm_add_epi32(y_part, uv_part);
- const __m128i rgba2 = _mm_srai_epi32(rgba1, YUV_FIX2);
- return rgba2;
-}
+//-----------------------------------------------------------------------------
+// Main call
-static WEBP_INLINE void VP8YuvToRgbSSE2(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const rgb) {
- const __m128i tmp0 = VP8GetRGBA32b(y, u, v);
- const __m128i tmp1 = _mm_packs_epi32(tmp0, tmp0);
- const __m128i tmp2 = _mm_packus_epi16(tmp1, tmp1);
- // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
- _mm_storel_epi64((__m128i*)rgb, tmp2);
-}
+WebPSamplerRowFunc WebPSamplers[MODE_LAST];
-static WEBP_INLINE void VP8YuvToBgrSSE2(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const bgr) {
- const __m128i tmp0 = VP8GetRGBA32b(y, u, v);
- const __m128i tmp1 = _mm_shuffle_epi32(tmp0, _MM_SHUFFLE(3, 0, 1, 2));
- const __m128i tmp2 = _mm_packs_epi32(tmp1, tmp1);
- const __m128i tmp3 = _mm_packus_epi16(tmp2, tmp2);
- // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
- _mm_storel_epi64((__m128i*)bgr, tmp3);
-}
+extern void WebPInitSamplersSSE2(void);
+extern void WebPInitSamplersMIPS32(void);
-void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
- int n;
- for (n = 0; n < 32; n += 4) {
- const __m128i tmp0_1 = VP8GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
- const __m128i tmp0_2 = VP8GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
- const __m128i tmp0_3 = VP8GetRGBA32b(y[n + 2], u[n + 2], v[n + 2]);
- const __m128i tmp0_4 = VP8GetRGBA32b(y[n + 3], u[n + 3], v[n + 3]);
- const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
- const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
- const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
- _mm_storeu_si128((__m128i*)dst, tmp2);
- dst += 4 * 4;
- }
-}
+static volatile VP8CPUInfo yuv_last_cpuinfo_used =
+ (VP8CPUInfo)&yuv_last_cpuinfo_used;
-void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
- int n;
- for (n = 0; n < 32; n += 2) {
- const __m128i tmp0_1 = VP8GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
- const __m128i tmp0_2 = VP8GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
- const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
- const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
- const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
- const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
- _mm_storel_epi64((__m128i*)dst, tmp3);
- dst += 4 * 2;
- }
-}
+void WebPInitSamplers(void) {
+ if (yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
-void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
- int n;
- uint8_t tmp0[2 * 3 + 5 + 15];
- uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
- for (n = 0; n < 30; ++n) { // we directly stomp the *dst memory
- VP8YuvToRgbSSE2(y[n], u[n], v[n], dst + n * 3);
- }
- // Last two pixels are special: we write in a tmp buffer before sending
- // to dst.
- VP8YuvToRgbSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
- VP8YuvToRgbSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
- memcpy(dst + n * 3, tmp, 2 * 3);
-}
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+ WebPSamplers[MODE_ARGB] = YuvToArgbRow;
+ WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row;
+ WebPSamplers[MODE_RGB_565] = YuvToRgb565Row;
+ WebPSamplers[MODE_rgbA] = YuvToRgbaRow;
+ WebPSamplers[MODE_bgrA] = YuvToBgraRow;
+ WebPSamplers[MODE_Argb] = YuvToArgbRow;
+ WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row;
-void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
- uint8_t* dst) {
- int n;
- uint8_t tmp0[2 * 3 + 5 + 15];
- uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
- for (n = 0; n < 30; ++n) {
- VP8YuvToBgrSSE2(y[n], u[n], v[n], dst + n * 3);
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitSamplersSSE2();
+ }
+#endif // WEBP_USE_SSE2
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ WebPInitSamplersMIPS32();
+ }
+#endif // WEBP_USE_MIPS32
}
- VP8YuvToBgrSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
- VP8YuvToBgrSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
- memcpy(dst + n * 3, tmp, 2 * 3);
+ yuv_last_cpuinfo_used = VP8GetCPUInfo;
}
-#else
-
-void VP8YUVInitSSE2(void) {}
-
-#endif // FANCY_UPSAMPLING
-
-#endif // WEBP_USE_SSE2
-
+//-----------------------------------------------------------------------------
diff --git a/src/3rdparty/libwebp/src/dsp/yuv.h b/src/3rdparty/libwebp/src/dsp/yuv.h
index dd778f9..8a47edd 100644
--- a/src/3rdparty/libwebp/src/dsp/yuv.h
+++ b/src/3rdparty/libwebp/src/dsp/yuv.h
@@ -245,6 +245,10 @@ void VP8YUVInit(void);
#if defined(WEBP_USE_SSE2)
+// When the following is defined, tables are initialized statically, adding ~12k
+// to the binary size. Otherwise, they are initialized at run-time (small cost).
+#define WEBP_YUV_USE_SSE2_TABLES
+
#if defined(FANCY_UPSAMPLING)
// Process 32 pixels and store the result (24b or 32b per pixel) in *dst.
void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
@@ -298,12 +302,12 @@ static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
return (luma + rounding) >> YUV_FIX; // no need to clip
}
-static WEBP_INLINE int VP8_RGB_TO_U(int r, int g, int b, int rounding) {
+static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
const int u = -11058 * r - 21710 * g + 32768 * b;
return VP8ClipUV(u, rounding);
}
-static WEBP_INLINE int VP8_RGB_TO_V(int r, int g, int b, int rounding) {
+static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
const int v = 32768 * r - 27439 * g - 5329 * b;
return VP8ClipUV(v, rounding);
}
diff --git a/src/3rdparty/libwebp/src/dsp/yuv_mips32.c b/src/3rdparty/libwebp/src/dsp/yuv_mips32.c
new file mode 100644
index 0000000..c82b4df
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/yuv_mips32.c
@@ -0,0 +1,100 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of YUV to RGB upsampling functions.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "./yuv.h"
+
+//------------------------------------------------------------------------------
+// simple point-sampling
+
+#define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \
+static void FUNC_NAME(const uint8_t* y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i, r, g, b; \
+ int temp0, temp1, temp2, temp3, temp4; \
+ for (i = 0; i < (len >> 1); i++) { \
+ temp1 = kVToR * v[0]; \
+ temp3 = kVToG * v[0]; \
+ temp2 = kUToG * u[0]; \
+ temp4 = kUToB * u[0]; \
+ temp0 = kYScale * y[0]; \
+ temp1 += kRCst; \
+ temp3 -= kGCst; \
+ temp2 += temp3; \
+ temp4 += kBCst; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ temp0 = kYScale * y[1]; \
+ dst[R] = r; \
+ dst[G] = g; \
+ dst[B] = b; \
+ if (A) dst[A] = 0xff; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ dst[R + XSTEP] = r; \
+ dst[G + XSTEP] = g; \
+ dst[B + XSTEP] = b; \
+ if (A) dst[A + XSTEP] = 0xff; \
+ y += 2; \
+ ++u; \
+ ++v; \
+ dst += 2 * XSTEP; \
+ } \
+ if (len & 1) { \
+ temp1 = kVToR * v[0]; \
+ temp3 = kVToG * v[0]; \
+ temp2 = kUToG * u[0]; \
+ temp4 = kUToB * u[0]; \
+ temp0 = kYScale * y[0]; \
+ temp1 += kRCst; \
+ temp3 -= kGCst; \
+ temp2 += temp3; \
+ temp4 += kBCst; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ dst[R] = r; \
+ dst[G] = g; \
+ dst[B] = b; \
+ if (A) dst[A] = 0xff; \
+ } \
+}
+
+ROW_FUNC(YuvToRgbRow, 3, 0, 1, 2, 0)
+ROW_FUNC(YuvToRgbaRow, 4, 0, 1, 2, 3)
+ROW_FUNC(YuvToBgrRow, 3, 2, 1, 0, 0)
+ROW_FUNC(YuvToBgraRow, 4, 2, 1, 0, 3)
+
+#undef ROW_FUNC
+
+#endif // WEBP_USE_MIPS32
+
+//------------------------------------------------------------------------------
+
+extern void WebPInitSamplersMIPS32(void);
+
+void WebPInitSamplersMIPS32(void) {
+#if defined(WEBP_USE_MIPS32)
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+#endif // WEBP_USE_MIPS32
+}
diff --git a/src/3rdparty/libwebp/src/dsp/yuv_sse2.c b/src/3rdparty/libwebp/src/dsp/yuv_sse2.c
new file mode 100644
index 0000000..6fe0f3b
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/yuv_sse2.c
@@ -0,0 +1,322 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// YUV->RGB conversion functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./yuv.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <emmintrin.h>
+#include <string.h> // for memcpy
+
+typedef union { // handy struct for converting SSE2 registers
+ int32_t i32[4];
+ uint8_t u8[16];
+ __m128i m;
+} VP8kCstSSE2;
+
+#if defined(WEBP_YUV_USE_SSE2_TABLES)
+
+#include "./yuv_tables_sse2.h"
+
+void VP8YUVInitSSE2(void) {}
+
+#else
+
+static int done_sse2 = 0;
+static VP8kCstSSE2 VP8kUtoRGBA[256], VP8kVtoRGBA[256], VP8kYtoRGBA[256];
+
+void VP8YUVInitSSE2(void) {
+ if (!done_sse2) {
+ int i;
+ for (i = 0; i < 256; ++i) {
+ VP8kYtoRGBA[i].i32[0] =
+ VP8kYtoRGBA[i].i32[1] =
+ VP8kYtoRGBA[i].i32[2] = (i - 16) * kYScale + YUV_HALF2;
+ VP8kYtoRGBA[i].i32[3] = 0xff << YUV_FIX2;
+
+ VP8kUtoRGBA[i].i32[0] = 0;
+ VP8kUtoRGBA[i].i32[1] = -kUToG * (i - 128);
+ VP8kUtoRGBA[i].i32[2] = kUToB * (i - 128);
+ VP8kUtoRGBA[i].i32[3] = 0;
+
+ VP8kVtoRGBA[i].i32[0] = kVToR * (i - 128);
+ VP8kVtoRGBA[i].i32[1] = -kVToG * (i - 128);
+ VP8kVtoRGBA[i].i32[2] = 0;
+ VP8kVtoRGBA[i].i32[3] = 0;
+ }
+ done_sse2 = 1;
+
+#if 0 // code used to generate 'yuv_tables_sse2.h'
+ printf("static const VP8kCstSSE2 VP8kYtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x}},\n",
+ VP8kYtoRGBA[i].i32[0], VP8kYtoRGBA[i].i32[1],
+ VP8kYtoRGBA[i].i32[2], VP8kYtoRGBA[i].i32[3]);
+ }
+ printf("};\n\n");
+ printf("static const VP8kCstSSE2 VP8kUtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0, 0x%.8x, 0x%.8x, 0}},\n",
+ VP8kUtoRGBA[i].i32[1], VP8kUtoRGBA[i].i32[2]);
+ }
+ printf("};\n\n");
+ printf("static VP8kCstSSE2 VP8kVtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0x%.8x, 0x%.8x, 0, 0}},\n",
+ VP8kVtoRGBA[i].i32[0], VP8kVtoRGBA[i].i32[1]);
+ }
+ printf("};\n\n");
+#endif
+ }
+}
+
+#endif // WEBP_YUV_USE_SSE2_TABLES
+
+//-----------------------------------------------------------------------------
+
+static WEBP_INLINE __m128i LoadUVPart(int u, int v) {
+ const __m128i u_part = _mm_loadu_si128(&VP8kUtoRGBA[u].m);
+ const __m128i v_part = _mm_loadu_si128(&VP8kVtoRGBA[v].m);
+ const __m128i uv_part = _mm_add_epi32(u_part, v_part);
+ return uv_part;
+}
+
+static WEBP_INLINE __m128i GetRGBA32bWithUV(int y, const __m128i uv_part) {
+ const __m128i y_part = _mm_loadu_si128(&VP8kYtoRGBA[y].m);
+ const __m128i rgba1 = _mm_add_epi32(y_part, uv_part);
+ const __m128i rgba2 = _mm_srai_epi32(rgba1, YUV_FIX2);
+ return rgba2;
+}
+
+static WEBP_INLINE __m128i GetRGBA32b(int y, int u, int v) {
+ const __m128i uv_part = LoadUVPart(u, v);
+ return GetRGBA32bWithUV(y, uv_part);
+}
+
+static WEBP_INLINE void YuvToRgbSSE2(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgb) {
+ const __m128i tmp0 = GetRGBA32b(y, u, v);
+ const __m128i tmp1 = _mm_packs_epi32(tmp0, tmp0);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1, tmp1);
+ // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
+ _mm_storel_epi64((__m128i*)rgb, tmp2);
+}
+
+static WEBP_INLINE void YuvToBgrSSE2(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgr) {
+ const __m128i tmp0 = GetRGBA32b(y, u, v);
+ const __m128i tmp1 = _mm_shuffle_epi32(tmp0, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2 = _mm_packs_epi32(tmp1, tmp1);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2, tmp2);
+ // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
+ _mm_storel_epi64((__m128i*)bgr, tmp3);
+}
+
+//-----------------------------------------------------------------------------
+// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
+
+#ifdef FANCY_UPSAMPLING
+
+void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ for (n = 0; n < 32; n += 4) {
+ const __m128i tmp0_1 = GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
+ const __m128i tmp0_2 = GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
+ const __m128i tmp0_3 = GetRGBA32b(y[n + 2], u[n + 2], v[n + 2]);
+ const __m128i tmp0_4 = GetRGBA32b(y[n + 3], u[n + 3], v[n + 3]);
+ const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
+ const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
+ _mm_storeu_si128((__m128i*)dst, tmp2);
+ dst += 4 * 4;
+ }
+}
+
+void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ for (n = 0; n < 32; n += 2) {
+ const __m128i tmp0_1 = GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
+ const __m128i tmp0_2 = GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ }
+}
+
+void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ uint8_t tmp0[2 * 3 + 5 + 15];
+ uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
+ for (n = 0; n < 30; ++n) { // we directly stomp the *dst memory
+ YuvToRgbSSE2(y[n], u[n], v[n], dst + n * 3);
+ }
+ // Last two pixels are special: we write in a tmp buffer before sending
+ // to dst.
+ YuvToRgbSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
+ YuvToRgbSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
+ memcpy(dst + n * 3, tmp, 2 * 3);
+}
+
+void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ uint8_t tmp0[2 * 3 + 5 + 15];
+ uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
+ for (n = 0; n < 30; ++n) {
+ YuvToBgrSSE2(y[n], u[n], v[n], dst + n * 3);
+ }
+ YuvToBgrSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
+ YuvToBgrSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
+ memcpy(dst + n * 3, tmp, 2 * 3);
+}
+
+#endif // FANCY_UPSAMPLING
+
+//-----------------------------------------------------------------------------
+// Arbitrary-length row conversion functions
+
+static void YuvToRgbaRowSSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 4 <= len; n += 4) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i uv_1 = LoadUVPart(u[1], v[1]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp0_3 = GetRGBA32bWithUV(y[2], uv_1);
+ const __m128i tmp0_4 = GetRGBA32bWithUV(y[3], uv_1);
+ const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
+ const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
+ _mm_storeu_si128((__m128i*)dst, tmp2);
+ dst += 4 * 4;
+ y += 4;
+ u += 2;
+ v += 2;
+ }
+ // Finish off
+ while (n < len) {
+ VP8YuvToRgba(y[0], u[0], v[0], dst);
+ dst += 4;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ ++n;
+ }
+}
+
+static void YuvToBgraRowSSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 <= len; n += 2) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ y += 2;
+ ++u;
+ ++v;
+ }
+ // Finish off
+ if (len & 1) {
+ VP8YuvToBgra(y[0], u[0], v[0], dst);
+ }
+}
+
+static void YuvToArgbRowSSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 <= len; n += 2) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(2, 1, 0, 3));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(2, 1, 0, 3));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ y += 2;
+ ++u;
+ ++v;
+ }
+ // Finish off
+ if (len & 1) {
+ VP8YuvToArgb(y[0], u[0], v[0], dst);
+ }
+}
+
+static void YuvToRgbRowSSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 < len; ++n) { // we directly stomp the *dst memory
+ YuvToRgbSSE2(y[0], u[0], v[0], dst); // stomps 8 bytes
+ dst += 3;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ }
+ VP8YuvToRgb(y[0], u[0], v[0], dst);
+ if (len > 1) {
+ VP8YuvToRgb(y[1], u[n & 1], v[n & 1], dst + 3);
+ }
+}
+
+static void YuvToBgrRowSSE2(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 < len; ++n) { // we directly stomp the *dst memory
+ YuvToBgrSSE2(y[0], u[0], v[0], dst); // stomps 8 bytes
+ dst += 3;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ }
+ VP8YuvToBgr(y[0], u[0], v[0], dst + 0);
+ if (len > 1) {
+ VP8YuvToBgr(y[1], u[n & 1], v[n & 1], dst + 3);
+ }
+}
+
+#endif // WEBP_USE_SSE2
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitSamplersSSE2(void);
+
+void WebPInitSamplersSSE2(void) {
+#if defined(WEBP_USE_SSE2)
+ WebPSamplers[MODE_RGB] = YuvToRgbRowSSE2;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRowSSE2;
+ WebPSamplers[MODE_BGR] = YuvToBgrRowSSE2;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRowSSE2;
+ WebPSamplers[MODE_ARGB] = YuvToArgbRowSSE2;
+#endif // WEBP_USE_SSE2
+}
diff --git a/src/3rdparty/libwebp/src/dsp/yuv_tables_sse2.h b/src/3rdparty/libwebp/src/dsp/yuv_tables_sse2.h
new file mode 100644
index 0000000..2b0f057
--- /dev/null
+++ b/src/3rdparty/libwebp/src/dsp/yuv_tables_sse2.h
@@ -0,0 +1,536 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 tables for YUV->RGB conversion (12kB overall)
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+// This file is not compiled, but #include'd directly from yuv.c
+// Only used if WEBP_YUV_USE_SSE2_TABLES is defined.
+
+static const VP8kCstSSE2 VP8kYtoRGBA[256] = {
+ {{0xfffb77b0, 0xfffb77b0, 0xfffb77b0, 0x003fc000}},
+ {{0xfffbc235, 0xfffbc235, 0xfffbc235, 0x003fc000}},
+ {{0xfffc0cba, 0xfffc0cba, 0xfffc0cba, 0x003fc000}},
+ {{0xfffc573f, 0xfffc573f, 0xfffc573f, 0x003fc000}},
+ {{0xfffca1c4, 0xfffca1c4, 0xfffca1c4, 0x003fc000}},
+ {{0xfffcec49, 0xfffcec49, 0xfffcec49, 0x003fc000}},
+ {{0xfffd36ce, 0xfffd36ce, 0xfffd36ce, 0x003fc000}},
+ {{0xfffd8153, 0xfffd8153, 0xfffd8153, 0x003fc000}},
+ {{0xfffdcbd8, 0xfffdcbd8, 0xfffdcbd8, 0x003fc000}},
+ {{0xfffe165d, 0xfffe165d, 0xfffe165d, 0x003fc000}},
+ {{0xfffe60e2, 0xfffe60e2, 0xfffe60e2, 0x003fc000}},
+ {{0xfffeab67, 0xfffeab67, 0xfffeab67, 0x003fc000}},
+ {{0xfffef5ec, 0xfffef5ec, 0xfffef5ec, 0x003fc000}},
+ {{0xffff4071, 0xffff4071, 0xffff4071, 0x003fc000}},
+ {{0xffff8af6, 0xffff8af6, 0xffff8af6, 0x003fc000}},
+ {{0xffffd57b, 0xffffd57b, 0xffffd57b, 0x003fc000}},
+ {{0x00002000, 0x00002000, 0x00002000, 0x003fc000}},
+ {{0x00006a85, 0x00006a85, 0x00006a85, 0x003fc000}},
+ {{0x0000b50a, 0x0000b50a, 0x0000b50a, 0x003fc000}},
+ {{0x0000ff8f, 0x0000ff8f, 0x0000ff8f, 0x003fc000}},
+ {{0x00014a14, 0x00014a14, 0x00014a14, 0x003fc000}},
+ {{0x00019499, 0x00019499, 0x00019499, 0x003fc000}},
+ {{0x0001df1e, 0x0001df1e, 0x0001df1e, 0x003fc000}},
+ {{0x000229a3, 0x000229a3, 0x000229a3, 0x003fc000}},
+ {{0x00027428, 0x00027428, 0x00027428, 0x003fc000}},
+ {{0x0002bead, 0x0002bead, 0x0002bead, 0x003fc000}},
+ {{0x00030932, 0x00030932, 0x00030932, 0x003fc000}},
+ {{0x000353b7, 0x000353b7, 0x000353b7, 0x003fc000}},
+ {{0x00039e3c, 0x00039e3c, 0x00039e3c, 0x003fc000}},
+ {{0x0003e8c1, 0x0003e8c1, 0x0003e8c1, 0x003fc000}},
+ {{0x00043346, 0x00043346, 0x00043346, 0x003fc000}},
+ {{0x00047dcb, 0x00047dcb, 0x00047dcb, 0x003fc000}},
+ {{0x0004c850, 0x0004c850, 0x0004c850, 0x003fc000}},
+ {{0x000512d5, 0x000512d5, 0x000512d5, 0x003fc000}},
+ {{0x00055d5a, 0x00055d5a, 0x00055d5a, 0x003fc000}},
+ {{0x0005a7df, 0x0005a7df, 0x0005a7df, 0x003fc000}},
+ {{0x0005f264, 0x0005f264, 0x0005f264, 0x003fc000}},
+ {{0x00063ce9, 0x00063ce9, 0x00063ce9, 0x003fc000}},
+ {{0x0006876e, 0x0006876e, 0x0006876e, 0x003fc000}},
+ {{0x0006d1f3, 0x0006d1f3, 0x0006d1f3, 0x003fc000}},
+ {{0x00071c78, 0x00071c78, 0x00071c78, 0x003fc000}},
+ {{0x000766fd, 0x000766fd, 0x000766fd, 0x003fc000}},
+ {{0x0007b182, 0x0007b182, 0x0007b182, 0x003fc000}},
+ {{0x0007fc07, 0x0007fc07, 0x0007fc07, 0x003fc000}},
+ {{0x0008468c, 0x0008468c, 0x0008468c, 0x003fc000}},
+ {{0x00089111, 0x00089111, 0x00089111, 0x003fc000}},
+ {{0x0008db96, 0x0008db96, 0x0008db96, 0x003fc000}},
+ {{0x0009261b, 0x0009261b, 0x0009261b, 0x003fc000}},
+ {{0x000970a0, 0x000970a0, 0x000970a0, 0x003fc000}},
+ {{0x0009bb25, 0x0009bb25, 0x0009bb25, 0x003fc000}},
+ {{0x000a05aa, 0x000a05aa, 0x000a05aa, 0x003fc000}},
+ {{0x000a502f, 0x000a502f, 0x000a502f, 0x003fc000}},
+ {{0x000a9ab4, 0x000a9ab4, 0x000a9ab4, 0x003fc000}},
+ {{0x000ae539, 0x000ae539, 0x000ae539, 0x003fc000}},
+ {{0x000b2fbe, 0x000b2fbe, 0x000b2fbe, 0x003fc000}},
+ {{0x000b7a43, 0x000b7a43, 0x000b7a43, 0x003fc000}},
+ {{0x000bc4c8, 0x000bc4c8, 0x000bc4c8, 0x003fc000}},
+ {{0x000c0f4d, 0x000c0f4d, 0x000c0f4d, 0x003fc000}},
+ {{0x000c59d2, 0x000c59d2, 0x000c59d2, 0x003fc000}},
+ {{0x000ca457, 0x000ca457, 0x000ca457, 0x003fc000}},
+ {{0x000ceedc, 0x000ceedc, 0x000ceedc, 0x003fc000}},
+ {{0x000d3961, 0x000d3961, 0x000d3961, 0x003fc000}},
+ {{0x000d83e6, 0x000d83e6, 0x000d83e6, 0x003fc000}},
+ {{0x000dce6b, 0x000dce6b, 0x000dce6b, 0x003fc000}},
+ {{0x000e18f0, 0x000e18f0, 0x000e18f0, 0x003fc000}},
+ {{0x000e6375, 0x000e6375, 0x000e6375, 0x003fc000}},
+ {{0x000eadfa, 0x000eadfa, 0x000eadfa, 0x003fc000}},
+ {{0x000ef87f, 0x000ef87f, 0x000ef87f, 0x003fc000}},
+ {{0x000f4304, 0x000f4304, 0x000f4304, 0x003fc000}},
+ {{0x000f8d89, 0x000f8d89, 0x000f8d89, 0x003fc000}},
+ {{0x000fd80e, 0x000fd80e, 0x000fd80e, 0x003fc000}},
+ {{0x00102293, 0x00102293, 0x00102293, 0x003fc000}},
+ {{0x00106d18, 0x00106d18, 0x00106d18, 0x003fc000}},
+ {{0x0010b79d, 0x0010b79d, 0x0010b79d, 0x003fc000}},
+ {{0x00110222, 0x00110222, 0x00110222, 0x003fc000}},
+ {{0x00114ca7, 0x00114ca7, 0x00114ca7, 0x003fc000}},
+ {{0x0011972c, 0x0011972c, 0x0011972c, 0x003fc000}},
+ {{0x0011e1b1, 0x0011e1b1, 0x0011e1b1, 0x003fc000}},
+ {{0x00122c36, 0x00122c36, 0x00122c36, 0x003fc000}},
+ {{0x001276bb, 0x001276bb, 0x001276bb, 0x003fc000}},
+ {{0x0012c140, 0x0012c140, 0x0012c140, 0x003fc000}},
+ {{0x00130bc5, 0x00130bc5, 0x00130bc5, 0x003fc000}},
+ {{0x0013564a, 0x0013564a, 0x0013564a, 0x003fc000}},
+ {{0x0013a0cf, 0x0013a0cf, 0x0013a0cf, 0x003fc000}},
+ {{0x0013eb54, 0x0013eb54, 0x0013eb54, 0x003fc000}},
+ {{0x001435d9, 0x001435d9, 0x001435d9, 0x003fc000}},
+ {{0x0014805e, 0x0014805e, 0x0014805e, 0x003fc000}},
+ {{0x0014cae3, 0x0014cae3, 0x0014cae3, 0x003fc000}},
+ {{0x00151568, 0x00151568, 0x00151568, 0x003fc000}},
+ {{0x00155fed, 0x00155fed, 0x00155fed, 0x003fc000}},
+ {{0x0015aa72, 0x0015aa72, 0x0015aa72, 0x003fc000}},
+ {{0x0015f4f7, 0x0015f4f7, 0x0015f4f7, 0x003fc000}},
+ {{0x00163f7c, 0x00163f7c, 0x00163f7c, 0x003fc000}},
+ {{0x00168a01, 0x00168a01, 0x00168a01, 0x003fc000}},
+ {{0x0016d486, 0x0016d486, 0x0016d486, 0x003fc000}},
+ {{0x00171f0b, 0x00171f0b, 0x00171f0b, 0x003fc000}},
+ {{0x00176990, 0x00176990, 0x00176990, 0x003fc000}},
+ {{0x0017b415, 0x0017b415, 0x0017b415, 0x003fc000}},
+ {{0x0017fe9a, 0x0017fe9a, 0x0017fe9a, 0x003fc000}},
+ {{0x0018491f, 0x0018491f, 0x0018491f, 0x003fc000}},
+ {{0x001893a4, 0x001893a4, 0x001893a4, 0x003fc000}},
+ {{0x0018de29, 0x0018de29, 0x0018de29, 0x003fc000}},
+ {{0x001928ae, 0x001928ae, 0x001928ae, 0x003fc000}},
+ {{0x00197333, 0x00197333, 0x00197333, 0x003fc000}},
+ {{0x0019bdb8, 0x0019bdb8, 0x0019bdb8, 0x003fc000}},
+ {{0x001a083d, 0x001a083d, 0x001a083d, 0x003fc000}},
+ {{0x001a52c2, 0x001a52c2, 0x001a52c2, 0x003fc000}},
+ {{0x001a9d47, 0x001a9d47, 0x001a9d47, 0x003fc000}},
+ {{0x001ae7cc, 0x001ae7cc, 0x001ae7cc, 0x003fc000}},
+ {{0x001b3251, 0x001b3251, 0x001b3251, 0x003fc000}},
+ {{0x001b7cd6, 0x001b7cd6, 0x001b7cd6, 0x003fc000}},
+ {{0x001bc75b, 0x001bc75b, 0x001bc75b, 0x003fc000}},
+ {{0x001c11e0, 0x001c11e0, 0x001c11e0, 0x003fc000}},
+ {{0x001c5c65, 0x001c5c65, 0x001c5c65, 0x003fc000}},
+ {{0x001ca6ea, 0x001ca6ea, 0x001ca6ea, 0x003fc000}},
+ {{0x001cf16f, 0x001cf16f, 0x001cf16f, 0x003fc000}},
+ {{0x001d3bf4, 0x001d3bf4, 0x001d3bf4, 0x003fc000}},
+ {{0x001d8679, 0x001d8679, 0x001d8679, 0x003fc000}},
+ {{0x001dd0fe, 0x001dd0fe, 0x001dd0fe, 0x003fc000}},
+ {{0x001e1b83, 0x001e1b83, 0x001e1b83, 0x003fc000}},
+ {{0x001e6608, 0x001e6608, 0x001e6608, 0x003fc000}},
+ {{0x001eb08d, 0x001eb08d, 0x001eb08d, 0x003fc000}},
+ {{0x001efb12, 0x001efb12, 0x001efb12, 0x003fc000}},
+ {{0x001f4597, 0x001f4597, 0x001f4597, 0x003fc000}},
+ {{0x001f901c, 0x001f901c, 0x001f901c, 0x003fc000}},
+ {{0x001fdaa1, 0x001fdaa1, 0x001fdaa1, 0x003fc000}},
+ {{0x00202526, 0x00202526, 0x00202526, 0x003fc000}},
+ {{0x00206fab, 0x00206fab, 0x00206fab, 0x003fc000}},
+ {{0x0020ba30, 0x0020ba30, 0x0020ba30, 0x003fc000}},
+ {{0x002104b5, 0x002104b5, 0x002104b5, 0x003fc000}},
+ {{0x00214f3a, 0x00214f3a, 0x00214f3a, 0x003fc000}},
+ {{0x002199bf, 0x002199bf, 0x002199bf, 0x003fc000}},
+ {{0x0021e444, 0x0021e444, 0x0021e444, 0x003fc000}},
+ {{0x00222ec9, 0x00222ec9, 0x00222ec9, 0x003fc000}},
+ {{0x0022794e, 0x0022794e, 0x0022794e, 0x003fc000}},
+ {{0x0022c3d3, 0x0022c3d3, 0x0022c3d3, 0x003fc000}},
+ {{0x00230e58, 0x00230e58, 0x00230e58, 0x003fc000}},
+ {{0x002358dd, 0x002358dd, 0x002358dd, 0x003fc000}},
+ {{0x0023a362, 0x0023a362, 0x0023a362, 0x003fc000}},
+ {{0x0023ede7, 0x0023ede7, 0x0023ede7, 0x003fc000}},
+ {{0x0024386c, 0x0024386c, 0x0024386c, 0x003fc000}},
+ {{0x002482f1, 0x002482f1, 0x002482f1, 0x003fc000}},
+ {{0x0024cd76, 0x0024cd76, 0x0024cd76, 0x003fc000}},
+ {{0x002517fb, 0x002517fb, 0x002517fb, 0x003fc000}},
+ {{0x00256280, 0x00256280, 0x00256280, 0x003fc000}},
+ {{0x0025ad05, 0x0025ad05, 0x0025ad05, 0x003fc000}},
+ {{0x0025f78a, 0x0025f78a, 0x0025f78a, 0x003fc000}},
+ {{0x0026420f, 0x0026420f, 0x0026420f, 0x003fc000}},
+ {{0x00268c94, 0x00268c94, 0x00268c94, 0x003fc000}},
+ {{0x0026d719, 0x0026d719, 0x0026d719, 0x003fc000}},
+ {{0x0027219e, 0x0027219e, 0x0027219e, 0x003fc000}},
+ {{0x00276c23, 0x00276c23, 0x00276c23, 0x003fc000}},
+ {{0x0027b6a8, 0x0027b6a8, 0x0027b6a8, 0x003fc000}},
+ {{0x0028012d, 0x0028012d, 0x0028012d, 0x003fc000}},
+ {{0x00284bb2, 0x00284bb2, 0x00284bb2, 0x003fc000}},
+ {{0x00289637, 0x00289637, 0x00289637, 0x003fc000}},
+ {{0x0028e0bc, 0x0028e0bc, 0x0028e0bc, 0x003fc000}},
+ {{0x00292b41, 0x00292b41, 0x00292b41, 0x003fc000}},
+ {{0x002975c6, 0x002975c6, 0x002975c6, 0x003fc000}},
+ {{0x0029c04b, 0x0029c04b, 0x0029c04b, 0x003fc000}},
+ {{0x002a0ad0, 0x002a0ad0, 0x002a0ad0, 0x003fc000}},
+ {{0x002a5555, 0x002a5555, 0x002a5555, 0x003fc000}},
+ {{0x002a9fda, 0x002a9fda, 0x002a9fda, 0x003fc000}},
+ {{0x002aea5f, 0x002aea5f, 0x002aea5f, 0x003fc000}},
+ {{0x002b34e4, 0x002b34e4, 0x002b34e4, 0x003fc000}},
+ {{0x002b7f69, 0x002b7f69, 0x002b7f69, 0x003fc000}},
+ {{0x002bc9ee, 0x002bc9ee, 0x002bc9ee, 0x003fc000}},
+ {{0x002c1473, 0x002c1473, 0x002c1473, 0x003fc000}},
+ {{0x002c5ef8, 0x002c5ef8, 0x002c5ef8, 0x003fc000}},
+ {{0x002ca97d, 0x002ca97d, 0x002ca97d, 0x003fc000}},
+ {{0x002cf402, 0x002cf402, 0x002cf402, 0x003fc000}},
+ {{0x002d3e87, 0x002d3e87, 0x002d3e87, 0x003fc000}},
+ {{0x002d890c, 0x002d890c, 0x002d890c, 0x003fc000}},
+ {{0x002dd391, 0x002dd391, 0x002dd391, 0x003fc000}},
+ {{0x002e1e16, 0x002e1e16, 0x002e1e16, 0x003fc000}},
+ {{0x002e689b, 0x002e689b, 0x002e689b, 0x003fc000}},
+ {{0x002eb320, 0x002eb320, 0x002eb320, 0x003fc000}},
+ {{0x002efda5, 0x002efda5, 0x002efda5, 0x003fc000}},
+ {{0x002f482a, 0x002f482a, 0x002f482a, 0x003fc000}},
+ {{0x002f92af, 0x002f92af, 0x002f92af, 0x003fc000}},
+ {{0x002fdd34, 0x002fdd34, 0x002fdd34, 0x003fc000}},
+ {{0x003027b9, 0x003027b9, 0x003027b9, 0x003fc000}},
+ {{0x0030723e, 0x0030723e, 0x0030723e, 0x003fc000}},
+ {{0x0030bcc3, 0x0030bcc3, 0x0030bcc3, 0x003fc000}},
+ {{0x00310748, 0x00310748, 0x00310748, 0x003fc000}},
+ {{0x003151cd, 0x003151cd, 0x003151cd, 0x003fc000}},
+ {{0x00319c52, 0x00319c52, 0x00319c52, 0x003fc000}},
+ {{0x0031e6d7, 0x0031e6d7, 0x0031e6d7, 0x003fc000}},
+ {{0x0032315c, 0x0032315c, 0x0032315c, 0x003fc000}},
+ {{0x00327be1, 0x00327be1, 0x00327be1, 0x003fc000}},
+ {{0x0032c666, 0x0032c666, 0x0032c666, 0x003fc000}},
+ {{0x003310eb, 0x003310eb, 0x003310eb, 0x003fc000}},
+ {{0x00335b70, 0x00335b70, 0x00335b70, 0x003fc000}},
+ {{0x0033a5f5, 0x0033a5f5, 0x0033a5f5, 0x003fc000}},
+ {{0x0033f07a, 0x0033f07a, 0x0033f07a, 0x003fc000}},
+ {{0x00343aff, 0x00343aff, 0x00343aff, 0x003fc000}},
+ {{0x00348584, 0x00348584, 0x00348584, 0x003fc000}},
+ {{0x0034d009, 0x0034d009, 0x0034d009, 0x003fc000}},
+ {{0x00351a8e, 0x00351a8e, 0x00351a8e, 0x003fc000}},
+ {{0x00356513, 0x00356513, 0x00356513, 0x003fc000}},
+ {{0x0035af98, 0x0035af98, 0x0035af98, 0x003fc000}},
+ {{0x0035fa1d, 0x0035fa1d, 0x0035fa1d, 0x003fc000}},
+ {{0x003644a2, 0x003644a2, 0x003644a2, 0x003fc000}},
+ {{0x00368f27, 0x00368f27, 0x00368f27, 0x003fc000}},
+ {{0x0036d9ac, 0x0036d9ac, 0x0036d9ac, 0x003fc000}},
+ {{0x00372431, 0x00372431, 0x00372431, 0x003fc000}},
+ {{0x00376eb6, 0x00376eb6, 0x00376eb6, 0x003fc000}},
+ {{0x0037b93b, 0x0037b93b, 0x0037b93b, 0x003fc000}},
+ {{0x003803c0, 0x003803c0, 0x003803c0, 0x003fc000}},
+ {{0x00384e45, 0x00384e45, 0x00384e45, 0x003fc000}},
+ {{0x003898ca, 0x003898ca, 0x003898ca, 0x003fc000}},
+ {{0x0038e34f, 0x0038e34f, 0x0038e34f, 0x003fc000}},
+ {{0x00392dd4, 0x00392dd4, 0x00392dd4, 0x003fc000}},
+ {{0x00397859, 0x00397859, 0x00397859, 0x003fc000}},
+ {{0x0039c2de, 0x0039c2de, 0x0039c2de, 0x003fc000}},
+ {{0x003a0d63, 0x003a0d63, 0x003a0d63, 0x003fc000}},
+ {{0x003a57e8, 0x003a57e8, 0x003a57e8, 0x003fc000}},
+ {{0x003aa26d, 0x003aa26d, 0x003aa26d, 0x003fc000}},
+ {{0x003aecf2, 0x003aecf2, 0x003aecf2, 0x003fc000}},
+ {{0x003b3777, 0x003b3777, 0x003b3777, 0x003fc000}},
+ {{0x003b81fc, 0x003b81fc, 0x003b81fc, 0x003fc000}},
+ {{0x003bcc81, 0x003bcc81, 0x003bcc81, 0x003fc000}},
+ {{0x003c1706, 0x003c1706, 0x003c1706, 0x003fc000}},
+ {{0x003c618b, 0x003c618b, 0x003c618b, 0x003fc000}},
+ {{0x003cac10, 0x003cac10, 0x003cac10, 0x003fc000}},
+ {{0x003cf695, 0x003cf695, 0x003cf695, 0x003fc000}},
+ {{0x003d411a, 0x003d411a, 0x003d411a, 0x003fc000}},
+ {{0x003d8b9f, 0x003d8b9f, 0x003d8b9f, 0x003fc000}},
+ {{0x003dd624, 0x003dd624, 0x003dd624, 0x003fc000}},
+ {{0x003e20a9, 0x003e20a9, 0x003e20a9, 0x003fc000}},
+ {{0x003e6b2e, 0x003e6b2e, 0x003e6b2e, 0x003fc000}},
+ {{0x003eb5b3, 0x003eb5b3, 0x003eb5b3, 0x003fc000}},
+ {{0x003f0038, 0x003f0038, 0x003f0038, 0x003fc000}},
+ {{0x003f4abd, 0x003f4abd, 0x003f4abd, 0x003fc000}},
+ {{0x003f9542, 0x003f9542, 0x003f9542, 0x003fc000}},
+ {{0x003fdfc7, 0x003fdfc7, 0x003fdfc7, 0x003fc000}},
+ {{0x00402a4c, 0x00402a4c, 0x00402a4c, 0x003fc000}},
+ {{0x004074d1, 0x004074d1, 0x004074d1, 0x003fc000}},
+ {{0x0040bf56, 0x0040bf56, 0x0040bf56, 0x003fc000}},
+ {{0x004109db, 0x004109db, 0x004109db, 0x003fc000}},
+ {{0x00415460, 0x00415460, 0x00415460, 0x003fc000}},
+ {{0x00419ee5, 0x00419ee5, 0x00419ee5, 0x003fc000}},
+ {{0x0041e96a, 0x0041e96a, 0x0041e96a, 0x003fc000}},
+ {{0x004233ef, 0x004233ef, 0x004233ef, 0x003fc000}},
+ {{0x00427e74, 0x00427e74, 0x00427e74, 0x003fc000}},
+ {{0x0042c8f9, 0x0042c8f9, 0x0042c8f9, 0x003fc000}},
+ {{0x0043137e, 0x0043137e, 0x0043137e, 0x003fc000}},
+ {{0x00435e03, 0x00435e03, 0x00435e03, 0x003fc000}},
+ {{0x0043a888, 0x0043a888, 0x0043a888, 0x003fc000}},
+ {{0x0043f30d, 0x0043f30d, 0x0043f30d, 0x003fc000}},
+ {{0x00443d92, 0x00443d92, 0x00443d92, 0x003fc000}},
+ {{0x00448817, 0x00448817, 0x00448817, 0x003fc000}},
+ {{0x0044d29c, 0x0044d29c, 0x0044d29c, 0x003fc000}},
+ {{0x00451d21, 0x00451d21, 0x00451d21, 0x003fc000}},
+ {{0x004567a6, 0x004567a6, 0x004567a6, 0x003fc000}},
+ {{0x0045b22b, 0x0045b22b, 0x0045b22b, 0x003fc000}}
+};
+
+static const VP8kCstSSE2 VP8kUtoRGBA[256] = {
+ {{0, 0x000c8980, 0xffbf7300, 0}}, {{0, 0x000c706d, 0xffbff41a, 0}},
+ {{0, 0x000c575a, 0xffc07534, 0}}, {{0, 0x000c3e47, 0xffc0f64e, 0}},
+ {{0, 0x000c2534, 0xffc17768, 0}}, {{0, 0x000c0c21, 0xffc1f882, 0}},
+ {{0, 0x000bf30e, 0xffc2799c, 0}}, {{0, 0x000bd9fb, 0xffc2fab6, 0}},
+ {{0, 0x000bc0e8, 0xffc37bd0, 0}}, {{0, 0x000ba7d5, 0xffc3fcea, 0}},
+ {{0, 0x000b8ec2, 0xffc47e04, 0}}, {{0, 0x000b75af, 0xffc4ff1e, 0}},
+ {{0, 0x000b5c9c, 0xffc58038, 0}}, {{0, 0x000b4389, 0xffc60152, 0}},
+ {{0, 0x000b2a76, 0xffc6826c, 0}}, {{0, 0x000b1163, 0xffc70386, 0}},
+ {{0, 0x000af850, 0xffc784a0, 0}}, {{0, 0x000adf3d, 0xffc805ba, 0}},
+ {{0, 0x000ac62a, 0xffc886d4, 0}}, {{0, 0x000aad17, 0xffc907ee, 0}},
+ {{0, 0x000a9404, 0xffc98908, 0}}, {{0, 0x000a7af1, 0xffca0a22, 0}},
+ {{0, 0x000a61de, 0xffca8b3c, 0}}, {{0, 0x000a48cb, 0xffcb0c56, 0}},
+ {{0, 0x000a2fb8, 0xffcb8d70, 0}}, {{0, 0x000a16a5, 0xffcc0e8a, 0}},
+ {{0, 0x0009fd92, 0xffcc8fa4, 0}}, {{0, 0x0009e47f, 0xffcd10be, 0}},
+ {{0, 0x0009cb6c, 0xffcd91d8, 0}}, {{0, 0x0009b259, 0xffce12f2, 0}},
+ {{0, 0x00099946, 0xffce940c, 0}}, {{0, 0x00098033, 0xffcf1526, 0}},
+ {{0, 0x00096720, 0xffcf9640, 0}}, {{0, 0x00094e0d, 0xffd0175a, 0}},
+ {{0, 0x000934fa, 0xffd09874, 0}}, {{0, 0x00091be7, 0xffd1198e, 0}},
+ {{0, 0x000902d4, 0xffd19aa8, 0}}, {{0, 0x0008e9c1, 0xffd21bc2, 0}},
+ {{0, 0x0008d0ae, 0xffd29cdc, 0}}, {{0, 0x0008b79b, 0xffd31df6, 0}},
+ {{0, 0x00089e88, 0xffd39f10, 0}}, {{0, 0x00088575, 0xffd4202a, 0}},
+ {{0, 0x00086c62, 0xffd4a144, 0}}, {{0, 0x0008534f, 0xffd5225e, 0}},
+ {{0, 0x00083a3c, 0xffd5a378, 0}}, {{0, 0x00082129, 0xffd62492, 0}},
+ {{0, 0x00080816, 0xffd6a5ac, 0}}, {{0, 0x0007ef03, 0xffd726c6, 0}},
+ {{0, 0x0007d5f0, 0xffd7a7e0, 0}}, {{0, 0x0007bcdd, 0xffd828fa, 0}},
+ {{0, 0x0007a3ca, 0xffd8aa14, 0}}, {{0, 0x00078ab7, 0xffd92b2e, 0}},
+ {{0, 0x000771a4, 0xffd9ac48, 0}}, {{0, 0x00075891, 0xffda2d62, 0}},
+ {{0, 0x00073f7e, 0xffdaae7c, 0}}, {{0, 0x0007266b, 0xffdb2f96, 0}},
+ {{0, 0x00070d58, 0xffdbb0b0, 0}}, {{0, 0x0006f445, 0xffdc31ca, 0}},
+ {{0, 0x0006db32, 0xffdcb2e4, 0}}, {{0, 0x0006c21f, 0xffdd33fe, 0}},
+ {{0, 0x0006a90c, 0xffddb518, 0}}, {{0, 0x00068ff9, 0xffde3632, 0}},
+ {{0, 0x000676e6, 0xffdeb74c, 0}}, {{0, 0x00065dd3, 0xffdf3866, 0}},
+ {{0, 0x000644c0, 0xffdfb980, 0}}, {{0, 0x00062bad, 0xffe03a9a, 0}},
+ {{0, 0x0006129a, 0xffe0bbb4, 0}}, {{0, 0x0005f987, 0xffe13cce, 0}},
+ {{0, 0x0005e074, 0xffe1bde8, 0}}, {{0, 0x0005c761, 0xffe23f02, 0}},
+ {{0, 0x0005ae4e, 0xffe2c01c, 0}}, {{0, 0x0005953b, 0xffe34136, 0}},
+ {{0, 0x00057c28, 0xffe3c250, 0}}, {{0, 0x00056315, 0xffe4436a, 0}},
+ {{0, 0x00054a02, 0xffe4c484, 0}}, {{0, 0x000530ef, 0xffe5459e, 0}},
+ {{0, 0x000517dc, 0xffe5c6b8, 0}}, {{0, 0x0004fec9, 0xffe647d2, 0}},
+ {{0, 0x0004e5b6, 0xffe6c8ec, 0}}, {{0, 0x0004cca3, 0xffe74a06, 0}},
+ {{0, 0x0004b390, 0xffe7cb20, 0}}, {{0, 0x00049a7d, 0xffe84c3a, 0}},
+ {{0, 0x0004816a, 0xffe8cd54, 0}}, {{0, 0x00046857, 0xffe94e6e, 0}},
+ {{0, 0x00044f44, 0xffe9cf88, 0}}, {{0, 0x00043631, 0xffea50a2, 0}},
+ {{0, 0x00041d1e, 0xffead1bc, 0}}, {{0, 0x0004040b, 0xffeb52d6, 0}},
+ {{0, 0x0003eaf8, 0xffebd3f0, 0}}, {{0, 0x0003d1e5, 0xffec550a, 0}},
+ {{0, 0x0003b8d2, 0xffecd624, 0}}, {{0, 0x00039fbf, 0xffed573e, 0}},
+ {{0, 0x000386ac, 0xffedd858, 0}}, {{0, 0x00036d99, 0xffee5972, 0}},
+ {{0, 0x00035486, 0xffeeda8c, 0}}, {{0, 0x00033b73, 0xffef5ba6, 0}},
+ {{0, 0x00032260, 0xffefdcc0, 0}}, {{0, 0x0003094d, 0xfff05dda, 0}},
+ {{0, 0x0002f03a, 0xfff0def4, 0}}, {{0, 0x0002d727, 0xfff1600e, 0}},
+ {{0, 0x0002be14, 0xfff1e128, 0}}, {{0, 0x0002a501, 0xfff26242, 0}},
+ {{0, 0x00028bee, 0xfff2e35c, 0}}, {{0, 0x000272db, 0xfff36476, 0}},
+ {{0, 0x000259c8, 0xfff3e590, 0}}, {{0, 0x000240b5, 0xfff466aa, 0}},
+ {{0, 0x000227a2, 0xfff4e7c4, 0}}, {{0, 0x00020e8f, 0xfff568de, 0}},
+ {{0, 0x0001f57c, 0xfff5e9f8, 0}}, {{0, 0x0001dc69, 0xfff66b12, 0}},
+ {{0, 0x0001c356, 0xfff6ec2c, 0}}, {{0, 0x0001aa43, 0xfff76d46, 0}},
+ {{0, 0x00019130, 0xfff7ee60, 0}}, {{0, 0x0001781d, 0xfff86f7a, 0}},
+ {{0, 0x00015f0a, 0xfff8f094, 0}}, {{0, 0x000145f7, 0xfff971ae, 0}},
+ {{0, 0x00012ce4, 0xfff9f2c8, 0}}, {{0, 0x000113d1, 0xfffa73e2, 0}},
+ {{0, 0x0000fabe, 0xfffaf4fc, 0}}, {{0, 0x0000e1ab, 0xfffb7616, 0}},
+ {{0, 0x0000c898, 0xfffbf730, 0}}, {{0, 0x0000af85, 0xfffc784a, 0}},
+ {{0, 0x00009672, 0xfffcf964, 0}}, {{0, 0x00007d5f, 0xfffd7a7e, 0}},
+ {{0, 0x0000644c, 0xfffdfb98, 0}}, {{0, 0x00004b39, 0xfffe7cb2, 0}},
+ {{0, 0x00003226, 0xfffefdcc, 0}}, {{0, 0x00001913, 0xffff7ee6, 0}},
+ {{0, 0x00000000, 0x00000000, 0}}, {{0, 0xffffe6ed, 0x0000811a, 0}},
+ {{0, 0xffffcdda, 0x00010234, 0}}, {{0, 0xffffb4c7, 0x0001834e, 0}},
+ {{0, 0xffff9bb4, 0x00020468, 0}}, {{0, 0xffff82a1, 0x00028582, 0}},
+ {{0, 0xffff698e, 0x0003069c, 0}}, {{0, 0xffff507b, 0x000387b6, 0}},
+ {{0, 0xffff3768, 0x000408d0, 0}}, {{0, 0xffff1e55, 0x000489ea, 0}},
+ {{0, 0xffff0542, 0x00050b04, 0}}, {{0, 0xfffeec2f, 0x00058c1e, 0}},
+ {{0, 0xfffed31c, 0x00060d38, 0}}, {{0, 0xfffeba09, 0x00068e52, 0}},
+ {{0, 0xfffea0f6, 0x00070f6c, 0}}, {{0, 0xfffe87e3, 0x00079086, 0}},
+ {{0, 0xfffe6ed0, 0x000811a0, 0}}, {{0, 0xfffe55bd, 0x000892ba, 0}},
+ {{0, 0xfffe3caa, 0x000913d4, 0}}, {{0, 0xfffe2397, 0x000994ee, 0}},
+ {{0, 0xfffe0a84, 0x000a1608, 0}}, {{0, 0xfffdf171, 0x000a9722, 0}},
+ {{0, 0xfffdd85e, 0x000b183c, 0}}, {{0, 0xfffdbf4b, 0x000b9956, 0}},
+ {{0, 0xfffda638, 0x000c1a70, 0}}, {{0, 0xfffd8d25, 0x000c9b8a, 0}},
+ {{0, 0xfffd7412, 0x000d1ca4, 0}}, {{0, 0xfffd5aff, 0x000d9dbe, 0}},
+ {{0, 0xfffd41ec, 0x000e1ed8, 0}}, {{0, 0xfffd28d9, 0x000e9ff2, 0}},
+ {{0, 0xfffd0fc6, 0x000f210c, 0}}, {{0, 0xfffcf6b3, 0x000fa226, 0}},
+ {{0, 0xfffcdda0, 0x00102340, 0}}, {{0, 0xfffcc48d, 0x0010a45a, 0}},
+ {{0, 0xfffcab7a, 0x00112574, 0}}, {{0, 0xfffc9267, 0x0011a68e, 0}},
+ {{0, 0xfffc7954, 0x001227a8, 0}}, {{0, 0xfffc6041, 0x0012a8c2, 0}},
+ {{0, 0xfffc472e, 0x001329dc, 0}}, {{0, 0xfffc2e1b, 0x0013aaf6, 0}},
+ {{0, 0xfffc1508, 0x00142c10, 0}}, {{0, 0xfffbfbf5, 0x0014ad2a, 0}},
+ {{0, 0xfffbe2e2, 0x00152e44, 0}}, {{0, 0xfffbc9cf, 0x0015af5e, 0}},
+ {{0, 0xfffbb0bc, 0x00163078, 0}}, {{0, 0xfffb97a9, 0x0016b192, 0}},
+ {{0, 0xfffb7e96, 0x001732ac, 0}}, {{0, 0xfffb6583, 0x0017b3c6, 0}},
+ {{0, 0xfffb4c70, 0x001834e0, 0}}, {{0, 0xfffb335d, 0x0018b5fa, 0}},
+ {{0, 0xfffb1a4a, 0x00193714, 0}}, {{0, 0xfffb0137, 0x0019b82e, 0}},
+ {{0, 0xfffae824, 0x001a3948, 0}}, {{0, 0xfffacf11, 0x001aba62, 0}},
+ {{0, 0xfffab5fe, 0x001b3b7c, 0}}, {{0, 0xfffa9ceb, 0x001bbc96, 0}},
+ {{0, 0xfffa83d8, 0x001c3db0, 0}}, {{0, 0xfffa6ac5, 0x001cbeca, 0}},
+ {{0, 0xfffa51b2, 0x001d3fe4, 0}}, {{0, 0xfffa389f, 0x001dc0fe, 0}},
+ {{0, 0xfffa1f8c, 0x001e4218, 0}}, {{0, 0xfffa0679, 0x001ec332, 0}},
+ {{0, 0xfff9ed66, 0x001f444c, 0}}, {{0, 0xfff9d453, 0x001fc566, 0}},
+ {{0, 0xfff9bb40, 0x00204680, 0}}, {{0, 0xfff9a22d, 0x0020c79a, 0}},
+ {{0, 0xfff9891a, 0x002148b4, 0}}, {{0, 0xfff97007, 0x0021c9ce, 0}},
+ {{0, 0xfff956f4, 0x00224ae8, 0}}, {{0, 0xfff93de1, 0x0022cc02, 0}},
+ {{0, 0xfff924ce, 0x00234d1c, 0}}, {{0, 0xfff90bbb, 0x0023ce36, 0}},
+ {{0, 0xfff8f2a8, 0x00244f50, 0}}, {{0, 0xfff8d995, 0x0024d06a, 0}},
+ {{0, 0xfff8c082, 0x00255184, 0}}, {{0, 0xfff8a76f, 0x0025d29e, 0}},
+ {{0, 0xfff88e5c, 0x002653b8, 0}}, {{0, 0xfff87549, 0x0026d4d2, 0}},
+ {{0, 0xfff85c36, 0x002755ec, 0}}, {{0, 0xfff84323, 0x0027d706, 0}},
+ {{0, 0xfff82a10, 0x00285820, 0}}, {{0, 0xfff810fd, 0x0028d93a, 0}},
+ {{0, 0xfff7f7ea, 0x00295a54, 0}}, {{0, 0xfff7ded7, 0x0029db6e, 0}},
+ {{0, 0xfff7c5c4, 0x002a5c88, 0}}, {{0, 0xfff7acb1, 0x002adda2, 0}},
+ {{0, 0xfff7939e, 0x002b5ebc, 0}}, {{0, 0xfff77a8b, 0x002bdfd6, 0}},
+ {{0, 0xfff76178, 0x002c60f0, 0}}, {{0, 0xfff74865, 0x002ce20a, 0}},
+ {{0, 0xfff72f52, 0x002d6324, 0}}, {{0, 0xfff7163f, 0x002de43e, 0}},
+ {{0, 0xfff6fd2c, 0x002e6558, 0}}, {{0, 0xfff6e419, 0x002ee672, 0}},
+ {{0, 0xfff6cb06, 0x002f678c, 0}}, {{0, 0xfff6b1f3, 0x002fe8a6, 0}},
+ {{0, 0xfff698e0, 0x003069c0, 0}}, {{0, 0xfff67fcd, 0x0030eada, 0}},
+ {{0, 0xfff666ba, 0x00316bf4, 0}}, {{0, 0xfff64da7, 0x0031ed0e, 0}},
+ {{0, 0xfff63494, 0x00326e28, 0}}, {{0, 0xfff61b81, 0x0032ef42, 0}},
+ {{0, 0xfff6026e, 0x0033705c, 0}}, {{0, 0xfff5e95b, 0x0033f176, 0}},
+ {{0, 0xfff5d048, 0x00347290, 0}}, {{0, 0xfff5b735, 0x0034f3aa, 0}},
+ {{0, 0xfff59e22, 0x003574c4, 0}}, {{0, 0xfff5850f, 0x0035f5de, 0}},
+ {{0, 0xfff56bfc, 0x003676f8, 0}}, {{0, 0xfff552e9, 0x0036f812, 0}},
+ {{0, 0xfff539d6, 0x0037792c, 0}}, {{0, 0xfff520c3, 0x0037fa46, 0}},
+ {{0, 0xfff507b0, 0x00387b60, 0}}, {{0, 0xfff4ee9d, 0x0038fc7a, 0}},
+ {{0, 0xfff4d58a, 0x00397d94, 0}}, {{0, 0xfff4bc77, 0x0039feae, 0}},
+ {{0, 0xfff4a364, 0x003a7fc8, 0}}, {{0, 0xfff48a51, 0x003b00e2, 0}},
+ {{0, 0xfff4713e, 0x003b81fc, 0}}, {{0, 0xfff4582b, 0x003c0316, 0}},
+ {{0, 0xfff43f18, 0x003c8430, 0}}, {{0, 0xfff42605, 0x003d054a, 0}},
+ {{0, 0xfff40cf2, 0x003d8664, 0}}, {{0, 0xfff3f3df, 0x003e077e, 0}},
+ {{0, 0xfff3dacc, 0x003e8898, 0}}, {{0, 0xfff3c1b9, 0x003f09b2, 0}},
+ {{0, 0xfff3a8a6, 0x003f8acc, 0}}, {{0, 0xfff38f93, 0x00400be6, 0}}
+};
+
+static VP8kCstSSE2 VP8kVtoRGBA[256] = {
+ {{0xffcced80, 0x001a0400, 0, 0}}, {{0xffcd53a5, 0x0019cff8, 0, 0}},
+ {{0xffcdb9ca, 0x00199bf0, 0, 0}}, {{0xffce1fef, 0x001967e8, 0, 0}},
+ {{0xffce8614, 0x001933e0, 0, 0}}, {{0xffceec39, 0x0018ffd8, 0, 0}},
+ {{0xffcf525e, 0x0018cbd0, 0, 0}}, {{0xffcfb883, 0x001897c8, 0, 0}},
+ {{0xffd01ea8, 0x001863c0, 0, 0}}, {{0xffd084cd, 0x00182fb8, 0, 0}},
+ {{0xffd0eaf2, 0x0017fbb0, 0, 0}}, {{0xffd15117, 0x0017c7a8, 0, 0}},
+ {{0xffd1b73c, 0x001793a0, 0, 0}}, {{0xffd21d61, 0x00175f98, 0, 0}},
+ {{0xffd28386, 0x00172b90, 0, 0}}, {{0xffd2e9ab, 0x0016f788, 0, 0}},
+ {{0xffd34fd0, 0x0016c380, 0, 0}}, {{0xffd3b5f5, 0x00168f78, 0, 0}},
+ {{0xffd41c1a, 0x00165b70, 0, 0}}, {{0xffd4823f, 0x00162768, 0, 0}},
+ {{0xffd4e864, 0x0015f360, 0, 0}}, {{0xffd54e89, 0x0015bf58, 0, 0}},
+ {{0xffd5b4ae, 0x00158b50, 0, 0}}, {{0xffd61ad3, 0x00155748, 0, 0}},
+ {{0xffd680f8, 0x00152340, 0, 0}}, {{0xffd6e71d, 0x0014ef38, 0, 0}},
+ {{0xffd74d42, 0x0014bb30, 0, 0}}, {{0xffd7b367, 0x00148728, 0, 0}},
+ {{0xffd8198c, 0x00145320, 0, 0}}, {{0xffd87fb1, 0x00141f18, 0, 0}},
+ {{0xffd8e5d6, 0x0013eb10, 0, 0}}, {{0xffd94bfb, 0x0013b708, 0, 0}},
+ {{0xffd9b220, 0x00138300, 0, 0}}, {{0xffda1845, 0x00134ef8, 0, 0}},
+ {{0xffda7e6a, 0x00131af0, 0, 0}}, {{0xffdae48f, 0x0012e6e8, 0, 0}},
+ {{0xffdb4ab4, 0x0012b2e0, 0, 0}}, {{0xffdbb0d9, 0x00127ed8, 0, 0}},
+ {{0xffdc16fe, 0x00124ad0, 0, 0}}, {{0xffdc7d23, 0x001216c8, 0, 0}},
+ {{0xffdce348, 0x0011e2c0, 0, 0}}, {{0xffdd496d, 0x0011aeb8, 0, 0}},
+ {{0xffddaf92, 0x00117ab0, 0, 0}}, {{0xffde15b7, 0x001146a8, 0, 0}},
+ {{0xffde7bdc, 0x001112a0, 0, 0}}, {{0xffdee201, 0x0010de98, 0, 0}},
+ {{0xffdf4826, 0x0010aa90, 0, 0}}, {{0xffdfae4b, 0x00107688, 0, 0}},
+ {{0xffe01470, 0x00104280, 0, 0}}, {{0xffe07a95, 0x00100e78, 0, 0}},
+ {{0xffe0e0ba, 0x000fda70, 0, 0}}, {{0xffe146df, 0x000fa668, 0, 0}},
+ {{0xffe1ad04, 0x000f7260, 0, 0}}, {{0xffe21329, 0x000f3e58, 0, 0}},
+ {{0xffe2794e, 0x000f0a50, 0, 0}}, {{0xffe2df73, 0x000ed648, 0, 0}},
+ {{0xffe34598, 0x000ea240, 0, 0}}, {{0xffe3abbd, 0x000e6e38, 0, 0}},
+ {{0xffe411e2, 0x000e3a30, 0, 0}}, {{0xffe47807, 0x000e0628, 0, 0}},
+ {{0xffe4de2c, 0x000dd220, 0, 0}}, {{0xffe54451, 0x000d9e18, 0, 0}},
+ {{0xffe5aa76, 0x000d6a10, 0, 0}}, {{0xffe6109b, 0x000d3608, 0, 0}},
+ {{0xffe676c0, 0x000d0200, 0, 0}}, {{0xffe6dce5, 0x000ccdf8, 0, 0}},
+ {{0xffe7430a, 0x000c99f0, 0, 0}}, {{0xffe7a92f, 0x000c65e8, 0, 0}},
+ {{0xffe80f54, 0x000c31e0, 0, 0}}, {{0xffe87579, 0x000bfdd8, 0, 0}},
+ {{0xffe8db9e, 0x000bc9d0, 0, 0}}, {{0xffe941c3, 0x000b95c8, 0, 0}},
+ {{0xffe9a7e8, 0x000b61c0, 0, 0}}, {{0xffea0e0d, 0x000b2db8, 0, 0}},
+ {{0xffea7432, 0x000af9b0, 0, 0}}, {{0xffeada57, 0x000ac5a8, 0, 0}},
+ {{0xffeb407c, 0x000a91a0, 0, 0}}, {{0xffeba6a1, 0x000a5d98, 0, 0}},
+ {{0xffec0cc6, 0x000a2990, 0, 0}}, {{0xffec72eb, 0x0009f588, 0, 0}},
+ {{0xffecd910, 0x0009c180, 0, 0}}, {{0xffed3f35, 0x00098d78, 0, 0}},
+ {{0xffeda55a, 0x00095970, 0, 0}}, {{0xffee0b7f, 0x00092568, 0, 0}},
+ {{0xffee71a4, 0x0008f160, 0, 0}}, {{0xffeed7c9, 0x0008bd58, 0, 0}},
+ {{0xffef3dee, 0x00088950, 0, 0}}, {{0xffefa413, 0x00085548, 0, 0}},
+ {{0xfff00a38, 0x00082140, 0, 0}}, {{0xfff0705d, 0x0007ed38, 0, 0}},
+ {{0xfff0d682, 0x0007b930, 0, 0}}, {{0xfff13ca7, 0x00078528, 0, 0}},
+ {{0xfff1a2cc, 0x00075120, 0, 0}}, {{0xfff208f1, 0x00071d18, 0, 0}},
+ {{0xfff26f16, 0x0006e910, 0, 0}}, {{0xfff2d53b, 0x0006b508, 0, 0}},
+ {{0xfff33b60, 0x00068100, 0, 0}}, {{0xfff3a185, 0x00064cf8, 0, 0}},
+ {{0xfff407aa, 0x000618f0, 0, 0}}, {{0xfff46dcf, 0x0005e4e8, 0, 0}},
+ {{0xfff4d3f4, 0x0005b0e0, 0, 0}}, {{0xfff53a19, 0x00057cd8, 0, 0}},
+ {{0xfff5a03e, 0x000548d0, 0, 0}}, {{0xfff60663, 0x000514c8, 0, 0}},
+ {{0xfff66c88, 0x0004e0c0, 0, 0}}, {{0xfff6d2ad, 0x0004acb8, 0, 0}},
+ {{0xfff738d2, 0x000478b0, 0, 0}}, {{0xfff79ef7, 0x000444a8, 0, 0}},
+ {{0xfff8051c, 0x000410a0, 0, 0}}, {{0xfff86b41, 0x0003dc98, 0, 0}},
+ {{0xfff8d166, 0x0003a890, 0, 0}}, {{0xfff9378b, 0x00037488, 0, 0}},
+ {{0xfff99db0, 0x00034080, 0, 0}}, {{0xfffa03d5, 0x00030c78, 0, 0}},
+ {{0xfffa69fa, 0x0002d870, 0, 0}}, {{0xfffad01f, 0x0002a468, 0, 0}},
+ {{0xfffb3644, 0x00027060, 0, 0}}, {{0xfffb9c69, 0x00023c58, 0, 0}},
+ {{0xfffc028e, 0x00020850, 0, 0}}, {{0xfffc68b3, 0x0001d448, 0, 0}},
+ {{0xfffcced8, 0x0001a040, 0, 0}}, {{0xfffd34fd, 0x00016c38, 0, 0}},
+ {{0xfffd9b22, 0x00013830, 0, 0}}, {{0xfffe0147, 0x00010428, 0, 0}},
+ {{0xfffe676c, 0x0000d020, 0, 0}}, {{0xfffecd91, 0x00009c18, 0, 0}},
+ {{0xffff33b6, 0x00006810, 0, 0}}, {{0xffff99db, 0x00003408, 0, 0}},
+ {{0x00000000, 0x00000000, 0, 0}}, {{0x00006625, 0xffffcbf8, 0, 0}},
+ {{0x0000cc4a, 0xffff97f0, 0, 0}}, {{0x0001326f, 0xffff63e8, 0, 0}},
+ {{0x00019894, 0xffff2fe0, 0, 0}}, {{0x0001feb9, 0xfffefbd8, 0, 0}},
+ {{0x000264de, 0xfffec7d0, 0, 0}}, {{0x0002cb03, 0xfffe93c8, 0, 0}},
+ {{0x00033128, 0xfffe5fc0, 0, 0}}, {{0x0003974d, 0xfffe2bb8, 0, 0}},
+ {{0x0003fd72, 0xfffdf7b0, 0, 0}}, {{0x00046397, 0xfffdc3a8, 0, 0}},
+ {{0x0004c9bc, 0xfffd8fa0, 0, 0}}, {{0x00052fe1, 0xfffd5b98, 0, 0}},
+ {{0x00059606, 0xfffd2790, 0, 0}}, {{0x0005fc2b, 0xfffcf388, 0, 0}},
+ {{0x00066250, 0xfffcbf80, 0, 0}}, {{0x0006c875, 0xfffc8b78, 0, 0}},
+ {{0x00072e9a, 0xfffc5770, 0, 0}}, {{0x000794bf, 0xfffc2368, 0, 0}},
+ {{0x0007fae4, 0xfffbef60, 0, 0}}, {{0x00086109, 0xfffbbb58, 0, 0}},
+ {{0x0008c72e, 0xfffb8750, 0, 0}}, {{0x00092d53, 0xfffb5348, 0, 0}},
+ {{0x00099378, 0xfffb1f40, 0, 0}}, {{0x0009f99d, 0xfffaeb38, 0, 0}},
+ {{0x000a5fc2, 0xfffab730, 0, 0}}, {{0x000ac5e7, 0xfffa8328, 0, 0}},
+ {{0x000b2c0c, 0xfffa4f20, 0, 0}}, {{0x000b9231, 0xfffa1b18, 0, 0}},
+ {{0x000bf856, 0xfff9e710, 0, 0}}, {{0x000c5e7b, 0xfff9b308, 0, 0}},
+ {{0x000cc4a0, 0xfff97f00, 0, 0}}, {{0x000d2ac5, 0xfff94af8, 0, 0}},
+ {{0x000d90ea, 0xfff916f0, 0, 0}}, {{0x000df70f, 0xfff8e2e8, 0, 0}},
+ {{0x000e5d34, 0xfff8aee0, 0, 0}}, {{0x000ec359, 0xfff87ad8, 0, 0}},
+ {{0x000f297e, 0xfff846d0, 0, 0}}, {{0x000f8fa3, 0xfff812c8, 0, 0}},
+ {{0x000ff5c8, 0xfff7dec0, 0, 0}}, {{0x00105bed, 0xfff7aab8, 0, 0}},
+ {{0x0010c212, 0xfff776b0, 0, 0}}, {{0x00112837, 0xfff742a8, 0, 0}},
+ {{0x00118e5c, 0xfff70ea0, 0, 0}}, {{0x0011f481, 0xfff6da98, 0, 0}},
+ {{0x00125aa6, 0xfff6a690, 0, 0}}, {{0x0012c0cb, 0xfff67288, 0, 0}},
+ {{0x001326f0, 0xfff63e80, 0, 0}}, {{0x00138d15, 0xfff60a78, 0, 0}},
+ {{0x0013f33a, 0xfff5d670, 0, 0}}, {{0x0014595f, 0xfff5a268, 0, 0}},
+ {{0x0014bf84, 0xfff56e60, 0, 0}}, {{0x001525a9, 0xfff53a58, 0, 0}},
+ {{0x00158bce, 0xfff50650, 0, 0}}, {{0x0015f1f3, 0xfff4d248, 0, 0}},
+ {{0x00165818, 0xfff49e40, 0, 0}}, {{0x0016be3d, 0xfff46a38, 0, 0}},
+ {{0x00172462, 0xfff43630, 0, 0}}, {{0x00178a87, 0xfff40228, 0, 0}},
+ {{0x0017f0ac, 0xfff3ce20, 0, 0}}, {{0x001856d1, 0xfff39a18, 0, 0}},
+ {{0x0018bcf6, 0xfff36610, 0, 0}}, {{0x0019231b, 0xfff33208, 0, 0}},
+ {{0x00198940, 0xfff2fe00, 0, 0}}, {{0x0019ef65, 0xfff2c9f8, 0, 0}},
+ {{0x001a558a, 0xfff295f0, 0, 0}}, {{0x001abbaf, 0xfff261e8, 0, 0}},
+ {{0x001b21d4, 0xfff22de0, 0, 0}}, {{0x001b87f9, 0xfff1f9d8, 0, 0}},
+ {{0x001bee1e, 0xfff1c5d0, 0, 0}}, {{0x001c5443, 0xfff191c8, 0, 0}},
+ {{0x001cba68, 0xfff15dc0, 0, 0}}, {{0x001d208d, 0xfff129b8, 0, 0}},
+ {{0x001d86b2, 0xfff0f5b0, 0, 0}}, {{0x001decd7, 0xfff0c1a8, 0, 0}},
+ {{0x001e52fc, 0xfff08da0, 0, 0}}, {{0x001eb921, 0xfff05998, 0, 0}},
+ {{0x001f1f46, 0xfff02590, 0, 0}}, {{0x001f856b, 0xffeff188, 0, 0}},
+ {{0x001feb90, 0xffefbd80, 0, 0}}, {{0x002051b5, 0xffef8978, 0, 0}},
+ {{0x0020b7da, 0xffef5570, 0, 0}}, {{0x00211dff, 0xffef2168, 0, 0}},
+ {{0x00218424, 0xffeeed60, 0, 0}}, {{0x0021ea49, 0xffeeb958, 0, 0}},
+ {{0x0022506e, 0xffee8550, 0, 0}}, {{0x0022b693, 0xffee5148, 0, 0}},
+ {{0x00231cb8, 0xffee1d40, 0, 0}}, {{0x002382dd, 0xffede938, 0, 0}},
+ {{0x0023e902, 0xffedb530, 0, 0}}, {{0x00244f27, 0xffed8128, 0, 0}},
+ {{0x0024b54c, 0xffed4d20, 0, 0}}, {{0x00251b71, 0xffed1918, 0, 0}},
+ {{0x00258196, 0xffece510, 0, 0}}, {{0x0025e7bb, 0xffecb108, 0, 0}},
+ {{0x00264de0, 0xffec7d00, 0, 0}}, {{0x0026b405, 0xffec48f8, 0, 0}},
+ {{0x00271a2a, 0xffec14f0, 0, 0}}, {{0x0027804f, 0xffebe0e8, 0, 0}},
+ {{0x0027e674, 0xffebace0, 0, 0}}, {{0x00284c99, 0xffeb78d8, 0, 0}},
+ {{0x0028b2be, 0xffeb44d0, 0, 0}}, {{0x002918e3, 0xffeb10c8, 0, 0}},
+ {{0x00297f08, 0xffeadcc0, 0, 0}}, {{0x0029e52d, 0xffeaa8b8, 0, 0}},
+ {{0x002a4b52, 0xffea74b0, 0, 0}}, {{0x002ab177, 0xffea40a8, 0, 0}},
+ {{0x002b179c, 0xffea0ca0, 0, 0}}, {{0x002b7dc1, 0xffe9d898, 0, 0}},
+ {{0x002be3e6, 0xffe9a490, 0, 0}}, {{0x002c4a0b, 0xffe97088, 0, 0}},
+ {{0x002cb030, 0xffe93c80, 0, 0}}, {{0x002d1655, 0xffe90878, 0, 0}},
+ {{0x002d7c7a, 0xffe8d470, 0, 0}}, {{0x002de29f, 0xffe8a068, 0, 0}},
+ {{0x002e48c4, 0xffe86c60, 0, 0}}, {{0x002eaee9, 0xffe83858, 0, 0}},
+ {{0x002f150e, 0xffe80450, 0, 0}}, {{0x002f7b33, 0xffe7d048, 0, 0}},
+ {{0x002fe158, 0xffe79c40, 0, 0}}, {{0x0030477d, 0xffe76838, 0, 0}},
+ {{0x0030ada2, 0xffe73430, 0, 0}}, {{0x003113c7, 0xffe70028, 0, 0}},
+ {{0x003179ec, 0xffe6cc20, 0, 0}}, {{0x0031e011, 0xffe69818, 0, 0}},
+ {{0x00324636, 0xffe66410, 0, 0}}, {{0x0032ac5b, 0xffe63008, 0, 0}}
+};