Path: blob/master/thirdparty/libwebp/src/dsp/common_sse2.h
9913 views
// Copyright 2016 Google Inc. All Rights Reserved.1//2// Use of this source code is governed by a BSD-style license3// that can be found in the COPYING file in the root of the source4// tree. An additional intellectual property rights grant can be found5// in the file PATENTS. All contributing project authors may6// be found in the AUTHORS file in the root of the source tree.7// -----------------------------------------------------------------------------8//9// SSE2 code common to several files.10//11// Author: Vincent Rabaud ([email protected])1213#ifndef WEBP_DSP_COMMON_SSE2_H_14#define WEBP_DSP_COMMON_SSE2_H_1516#ifdef __cplusplus17extern "C" {18#endif1920#if defined(WEBP_USE_SSE2)2122#include <emmintrin.h>2324//------------------------------------------------------------------------------25// Quite useful macro for debugging. Left here for convenience.2627#if 028#include <stdio.h>29static WEBP_INLINE void PrintReg(const __m128i r, const char* const name,30int size) {31int n;32union {33__m128i r;34uint8_t i8[16];35uint16_t i16[8];36uint32_t i32[4];37uint64_t i64[2];38} tmp;39tmp.r = r;40fprintf(stderr, "%s\t: ", name);41if (size == 8) {42for (n = 0; n < 16; ++n) fprintf(stderr, "%.2x ", tmp.i8[n]);43} else if (size == 16) {44for (n = 0; n < 8; ++n) fprintf(stderr, "%.4x ", tmp.i16[n]);45} else if (size == 32) {46for (n = 0; n < 4; ++n) fprintf(stderr, "%.8x ", tmp.i32[n]);47} else {48for (n = 0; n < 2; ++n) fprintf(stderr, "%.16lx ", tmp.i64[n]);49}50fprintf(stderr, "\n");51}52#endif5354//------------------------------------------------------------------------------55// Math functions.5657// Return the sum of all the 8b in the register.58static WEBP_INLINE int VP8HorizontalAdd8b(const __m128i* const a) {59const __m128i zero = _mm_setzero_si128();60const __m128i sad8x2 = _mm_sad_epu8(*a, zero);61// sum the two sads: sad8x2[0:1] + sad8x2[8:9]62const __m128i sum = _mm_add_epi32(sad8x2, _mm_shuffle_epi32(sad8x2, 2));63return _mm_cvtsi128_si32(sum);64}6566// Transpose two 4x4 16b matrices horizontally stored in registers.67static WEBP_INLINE void VP8Transpose_2_4x4_16b(68const __m128i* const in0, const __m128i* const in1,69const __m128i* const in2, const __m128i* const in3, __m128i* const out0,70__m128i* const out1, __m128i* const out2, __m128i* const out3) {71// Transpose the two 4x4.72// a00 a01 a02 a03 b00 b01 b02 b0373// a10 a11 a12 a13 b10 b11 b12 b1374// a20 a21 a22 a23 b20 b21 b22 b2375// a30 a31 a32 a33 b30 b31 b32 b3376const __m128i transpose0_0 = _mm_unpacklo_epi16(*in0, *in1);77const __m128i transpose0_1 = _mm_unpacklo_epi16(*in2, *in3);78const __m128i transpose0_2 = _mm_unpackhi_epi16(*in0, *in1);79const __m128i transpose0_3 = _mm_unpackhi_epi16(*in2, *in3);80// a00 a10 a01 a11 a02 a12 a03 a1381// a20 a30 a21 a31 a22 a32 a23 a3382// b00 b10 b01 b11 b02 b12 b03 b1383// b20 b30 b21 b31 b22 b32 b23 b3384const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);85const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);86const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);87const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);88// a00 a10 a20 a30 a01 a11 a21 a3189// b00 b10 b20 b30 b01 b11 b21 b3190// a02 a12 a22 a32 a03 a13 a23 a3391// b02 b12 a22 b32 b03 b13 b23 b3392*out0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);93*out1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);94*out2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);95*out3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);96// a00 a10 a20 a30 b00 b10 b20 b3097// a01 a11 a21 a31 b01 b11 b21 b3198// a02 a12 a22 a32 b02 b12 b22 b3299// a03 a13 a23 a33 b03 b13 b23 b33100}101102//------------------------------------------------------------------------------103// Channel mixing.104105// Function used several times in VP8PlanarTo24b.106// It samples the in buffer as follows: one every two unsigned char is stored107// at the beginning of the buffer, while the other half is stored at the end.108#define VP8PlanarTo24bHelper(IN, OUT) \109do { \110const __m128i v_mask = _mm_set1_epi16(0x00ff); \111/* Take one every two upper 8b values.*/ \112(OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask), \113_mm_and_si128((IN##1), v_mask)); \114(OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask), \115_mm_and_si128((IN##3), v_mask)); \116(OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask), \117_mm_and_si128((IN##5), v_mask)); \118/* Take one every two lower 8b values.*/ \119(OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8), \120_mm_srli_epi16((IN##1), 8)); \121(OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8), \122_mm_srli_epi16((IN##3), 8)); \123(OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8), \124_mm_srli_epi16((IN##5), 8)); \125} while (0)126127// Pack the planar buffers128// rrrr... rrrr... gggg... gggg... bbbb... bbbb....129// triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...130static WEBP_INLINE void VP8PlanarTo24b_SSE2(131__m128i* const in0, __m128i* const in1, __m128i* const in2,132__m128i* const in3, __m128i* const in4, __m128i* const in5) {133// The input is 6 registers of sixteen 8b but for the sake of explanation,134// let's take 6 registers of four 8b values.135// To pack, we will keep taking one every two 8b integer and move it136// around as follows:137// Input:138// r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7139// Split the 6 registers in two sets of 3 registers: the first set as the even140// 8b bytes, the second the odd ones:141// r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7142// Repeat the same permutations twice more:143// r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7144// r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7145__m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;146VP8PlanarTo24bHelper(*in, tmp);147VP8PlanarTo24bHelper(tmp, *in);148VP8PlanarTo24bHelper(*in, tmp);149// We need to do it two more times than the example as we have sixteen bytes.150{151__m128i out0, out1, out2, out3, out4, out5;152VP8PlanarTo24bHelper(tmp, out);153VP8PlanarTo24bHelper(out, *in);154}155}156157#undef VP8PlanarTo24bHelper158159// Convert four packed four-channel buffers like argbargbargbargb... into the160// split channels aaaaa ... rrrr ... gggg .... bbbbb ......161static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0,162__m128i* const in1,163__m128i* const in2,164__m128i* const in3) {165// Column-wise transpose.166const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);167const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);168const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3);169const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3);170const __m128i B0 = _mm_unpacklo_epi8(A0, A1);171const __m128i B1 = _mm_unpackhi_epi8(A0, A1);172const __m128i B2 = _mm_unpacklo_epi8(A2, A3);173const __m128i B3 = _mm_unpackhi_epi8(A2, A3);174// C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0175// C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0176const __m128i C0 = _mm_unpacklo_epi8(B0, B1);177const __m128i C1 = _mm_unpackhi_epi8(B0, B1);178const __m128i C2 = _mm_unpacklo_epi8(B2, B3);179const __m128i C3 = _mm_unpackhi_epi8(B2, B3);180// Gather the channels.181*in0 = _mm_unpackhi_epi64(C1, C3);182*in1 = _mm_unpacklo_epi64(C1, C3);183*in2 = _mm_unpackhi_epi64(C0, C2);184*in3 = _mm_unpacklo_epi64(C0, C2);185}186187#endif // WEBP_USE_SSE2188189#ifdef __cplusplus190} // extern "C"191#endif192193#endif // WEBP_DSP_COMMON_SSE2_H_194195196