separate SSE2 lossless functions into its own file
expose the predictor array as function pointers instead of each individual sub-function + merged Average2() into ClampedAddSubtractHalf directly + unified the signature as "VP8LProcessBlueAndRedFunc" no speed diff observed Change-Id: Ic3c45dff11884a8330a9ad38c2c8e82491c6e044
This commit is contained in:
parent
514fc251df
commit
0f4f721b12
@ -32,6 +32,7 @@ LOCAL_SRC_FILES := \
|
||||
src/dsp/enc.c \
|
||||
src/dsp/enc_sse2.c \
|
||||
src/dsp/lossless.c \
|
||||
src/dsp/lossless_sse2.c \
|
||||
src/dsp/upsampling.c \
|
||||
src/dsp/upsampling_mips32.c \
|
||||
src/dsp/upsampling_sse2.c \
|
||||
|
@ -174,6 +174,7 @@ DSP_DEC_OBJS = \
|
||||
$(DIROBJ)\dsp\dec_neon.obj \
|
||||
$(DIROBJ)\dsp\dec_sse2.obj \
|
||||
$(DIROBJ)\dsp\lossless.obj \
|
||||
$(DIROBJ)\dsp\lossless_sse2.obj \
|
||||
$(DIROBJ)\dsp\upsampling.obj \
|
||||
$(DIROBJ)\dsp\upsampling_mips32.obj \
|
||||
$(DIROBJ)\dsp\upsampling_neon.obj \
|
||||
|
@ -105,6 +105,7 @@ DSP_DEC_OBJS = \
|
||||
src/dsp/dec_neon.o \
|
||||
src/dsp/dec_sse2.o \
|
||||
src/dsp/lossless.o \
|
||||
src/dsp/lossless_sse2.o \
|
||||
src/dsp/upsampling.o \
|
||||
src/dsp/upsampling_mips32.o \
|
||||
src/dsp/upsampling_neon.o \
|
||||
|
@ -17,6 +17,7 @@ COMMON_SOURCES += dec_neon.c
|
||||
COMMON_SOURCES += dec_sse2.c
|
||||
COMMON_SOURCES += dsp.h
|
||||
COMMON_SOURCES += lossless.c
|
||||
COMMON_SOURCES += lossless_sse2.c
|
||||
COMMON_SOURCES += lossless.h
|
||||
COMMON_SOURCES += upsampling.c
|
||||
COMMON_SOURCES += upsampling_mips32.c
|
||||
|
@ -15,10 +15,6 @@
|
||||
|
||||
#include "./dsp.h"
|
||||
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "./lossless.h"
|
||||
@ -519,21 +515,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,
|
||||
@ -610,7 +604,7 @@ static int GetBestPredictorForTile(int width, int height,
|
||||
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;
|
||||
int histo_argb[4][256];
|
||||
@ -653,7 +647,7 @@ static void CopyTileWithPrediction(int width, int height,
|
||||
const int tile_size = 1 << bits;
|
||||
const int max_y = GetMin(tile_size, height - row_start);
|
||||
const int max_x = GetMin(tile_size, width - col_start);
|
||||
const PredictorFunc pred_func = kPredictors[mode];
|
||||
const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
|
||||
const uint32_t* current_row = argb_scratch;
|
||||
|
||||
int y;
|
||||
@ -758,14 +752,14 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
|
||||
while (y < y_end) {
|
||||
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:
|
||||
while (x < safe_width) {
|
||||
pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
|
||||
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);
|
||||
@ -773,7 +767,7 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
|
||||
t = 0;
|
||||
}
|
||||
if (x < width) {
|
||||
pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
|
||||
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);
|
||||
@ -788,9 +782,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;
|
||||
@ -801,14 +795,15 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1248,7 +1243,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);
|
||||
@ -1293,8 +1288,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++;
|
||||
@ -1304,8 +1299,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++;
|
||||
@ -1316,8 +1311,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++;
|
||||
@ -1333,8 +1328,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++;
|
||||
@ -1350,8 +1345,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++;
|
||||
@ -1469,246 +1464,9 @@ 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 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);
|
||||
}
|
||||
// fallthrough and finish off with plain-C
|
||||
SubtractGreenFromBlueAndRed(argb_data + i, num_pixs - i);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
// fallthrough and finish off with plain-C
|
||||
AddGreenToBlueAndRed(data, data_end);
|
||||
}
|
||||
|
||||
static void ConvertBGRAToRGBASSE2(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
|
||||
ConvertBGRAToRGBA((const uint32_t*)in, num_pixels, (uint8_t*)out);
|
||||
}
|
||||
|
||||
static void ConvertBGRAToRGBA4444SSE2(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
|
||||
ConvertBGRAToRGBA4444((const uint32_t*)in, num_pixels, (uint8_t*)out);
|
||||
}
|
||||
|
||||
static void ConvertBGRAToRGB565SSE2(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
|
||||
ConvertBGRAToRGB565((const uint32_t*)in, num_pixels, (uint8_t*)out);
|
||||
}
|
||||
|
||||
static void ConvertBGRAToBGRSSE2(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
|
||||
ConvertBGRAToBGR((const uint32_t*)in, num_pixels, dst);
|
||||
}
|
||||
|
||||
extern void VP8LDspInitSSE2(void);
|
||||
|
||||
void VP8LDspInitSSE2(void) {
|
||||
VP8LClampedAddSubtractFull = ClampedAddSubtractFullSSE2;
|
||||
VP8LClampedAddSubtractHalf = ClampedAddSubtractHalfSSE2;
|
||||
VP8LSelect = SelectSSE2;
|
||||
VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRedSSE2;
|
||||
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRedSSE2;
|
||||
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBASSE2;
|
||||
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444SSE2;
|
||||
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565SSE2;
|
||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGRSSE2;
|
||||
}
|
||||
|
||||
#endif // WEBP_USE_SSE2
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
VP8LPredClampedAddSubFunc VP8LClampedAddSubtractFull;
|
||||
VP8LPredClampedAddSubFunc VP8LClampedAddSubtractHalf;
|
||||
VP8LPredSelectFunc VP8LSelect;
|
||||
VP8LSubtractGreenFromBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
||||
VP8LAddGreenToBlueAndRedFunc VP8LAddGreenToBlueAndRed;
|
||||
VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
||||
VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
|
||||
VP8LPredictorFunc VP8LPredictors[16];
|
||||
|
||||
VP8LConvertFunc VP8LConvertBGRAToRGB;
|
||||
VP8LConvertFunc VP8LConvertBGRAToRGBA;
|
||||
@ -1717,17 +1475,16 @@ VP8LConvertFunc VP8LConvertBGRAToRGB565;
|
||||
VP8LConvertFunc VP8LConvertBGRAToBGR;
|
||||
|
||||
void VP8LDspInit(void) {
|
||||
VP8LClampedAddSubtractFull = ClampedAddSubtractFull;
|
||||
VP8LClampedAddSubtractHalf = ClampedAddSubtractHalf;
|
||||
VP8LSelect = Select;
|
||||
VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
|
||||
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
|
||||
memcpy(VP8LPredictors, kPredictorsC, sizeof(VP8LPredictors));
|
||||
|
||||
VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
|
||||
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
|
||||
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
|
||||
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
|
||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
|
||||
VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C;
|
||||
VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
|
||||
|
||||
VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
|
||||
VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
|
||||
VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
|
||||
VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
|
||||
VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
|
||||
|
||||
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
|
||||
if (VP8GetCPUInfo != NULL) {
|
||||
|
@ -23,21 +23,14 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Signatures and generic function-pointers
|
||||
|
||||
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 uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top);
|
||||
extern VP8LPredictorFunc VP8LPredictors[16];
|
||||
|
||||
extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractFull;
|
||||
extern VP8LPredClampedAddSubFunc VP8LClampedAddSubtractHalf;
|
||||
extern VP8LPredSelectFunc VP8LSelect;
|
||||
extern VP8LSubtractGreenFromBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
||||
extern VP8LAddGreenToBlueAndRedFunc VP8LAddGreenToBlueAndRed;
|
||||
typedef void (*VP8LProcessBlueAndRedFunc)(uint32_t* argb_data, int num_pixels);
|
||||
extern VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
|
||||
extern VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
|
||||
|
||||
typedef void (*VP8LConvertFunc)(const uint32_t* src, int num_pixels,
|
||||
uint8_t* dst);
|
||||
@ -47,6 +40,23 @@ extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444;
|
||||
extern VP8LConvertFunc VP8LConvertBGRAToRGB565;
|
||||
extern VP8LConvertFunc VP8LConvertBGRAToBGR;
|
||||
|
||||
extern void VP8LDspInitSSE2(void);
|
||||
|
||||
// Expose some C-only fallback functions
|
||||
extern void VP8LConvertBGRAToRGB_C(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst);
|
||||
extern void VP8LConvertBGRAToRGBA_C(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst);
|
||||
extern void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst);
|
||||
extern void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst);
|
||||
extern void VP8LConvertBGRAToBGR_C(const uint32_t* src,
|
||||
int num_pixels, uint8_t* dst);
|
||||
extern void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data,
|
||||
int num_pixels);
|
||||
extern void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels);
|
||||
|
||||
// Must be called before calling any of the above methods.
|
||||
void VP8LDspInit(void);
|
||||
|
||||
|
306
src/dsp/lossless_sse2.c
Normal file
306
src/dsp/lossless_sse2.c
Normal file
@ -0,0 +1,306 @@
|
||||
// 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"
|
||||
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#include "./lossless.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Predictors
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// TODO(skal): optimize these to SSE2 too.
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Colorspace conversion functions
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#endif // WEBP_USE_SSE2
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void VP8LDspInitSSE2(void) {
|
||||
#if defined(WEBP_USE_SSE2)
|
||||
VP8LPredictors[11] = Predictor11;
|
||||
VP8LPredictors[12] = Predictor12;
|
||||
VP8LPredictors[13] = Predictor13;
|
||||
|
||||
VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
|
||||
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
|
||||
|
||||
VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
|
||||
VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
|
||||
VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
|
||||
VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
|
||||
#endif // WEBP_USE_SSE2
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
Loading…
Reference in New Issue
Block a user