common_sse2.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // Copyright 2016 Google Inc. All Rights Reserved.
  2. //
  3. // Use of this source code is governed by a BSD-style license
  4. // that can be found in the COPYING file in the root of the source
  5. // tree. An additional intellectual property rights grant can be found
  6. // in the file PATENTS. All contributing project authors may
  7. // be found in the AUTHORS file in the root of the source tree.
  8. // -----------------------------------------------------------------------------
  9. //
  10. // SSE2 code common to several files.
  11. //
  12. // Author: Vincent Rabaud (vrabaud@google.com)
  13. #ifndef WEBP_DSP_COMMON_SSE2_H_
  14. #define WEBP_DSP_COMMON_SSE2_H_
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. #if defined(WEBP_USE_SSE2)
  19. #include <emmintrin.h>
  20. //------------------------------------------------------------------------------
  21. // Quite useful macro for debugging. Left here for convenience.
  22. #if 0
  23. #include <stdio.h>
  24. static WEBP_INLINE void PrintReg(const __m128i r, const char* const name,
  25. int size) {
  26. int n;
  27. union {
  28. __m128i r;
  29. uint8_t i8[16];
  30. uint16_t i16[8];
  31. uint32_t i32[4];
  32. uint64_t i64[2];
  33. } tmp;
  34. tmp.r = r;
  35. fprintf(stderr, "%s\t: ", name);
  36. if (size == 8) {
  37. for (n = 0; n < 16; ++n) fprintf(stderr, "%.2x ", tmp.i8[n]);
  38. } else if (size == 16) {
  39. for (n = 0; n < 8; ++n) fprintf(stderr, "%.4x ", tmp.i16[n]);
  40. } else if (size == 32) {
  41. for (n = 0; n < 4; ++n) fprintf(stderr, "%.8x ", tmp.i32[n]);
  42. } else {
  43. for (n = 0; n < 2; ++n) fprintf(stderr, "%.16lx ", tmp.i64[n]);
  44. }
  45. fprintf(stderr, "\n");
  46. }
  47. #endif
  48. //------------------------------------------------------------------------------
  49. // Math functions.
  50. // Return the sum of all the 8b in the register.
  51. static WEBP_INLINE int VP8HorizontalAdd8b(const __m128i* const a) {
  52. const __m128i zero = _mm_setzero_si128();
  53. const __m128i sad8x2 = _mm_sad_epu8(*a, zero);
  54. // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
  55. const __m128i sum = _mm_add_epi32(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
  56. return _mm_cvtsi128_si32(sum);
  57. }
  58. // Transpose two 4x4 16b matrices horizontally stored in registers.
  59. static WEBP_INLINE void VP8Transpose_2_4x4_16b(
  60. const __m128i* const in0, const __m128i* const in1,
  61. const __m128i* const in2, const __m128i* const in3, __m128i* const out0,
  62. __m128i* const out1, __m128i* const out2, __m128i* const out3) {
  63. // Transpose the two 4x4.
  64. // a00 a01 a02 a03 b00 b01 b02 b03
  65. // a10 a11 a12 a13 b10 b11 b12 b13
  66. // a20 a21 a22 a23 b20 b21 b22 b23
  67. // a30 a31 a32 a33 b30 b31 b32 b33
  68. const __m128i transpose0_0 = _mm_unpacklo_epi16(*in0, *in1);
  69. const __m128i transpose0_1 = _mm_unpacklo_epi16(*in2, *in3);
  70. const __m128i transpose0_2 = _mm_unpackhi_epi16(*in0, *in1);
  71. const __m128i transpose0_3 = _mm_unpackhi_epi16(*in2, *in3);
  72. // a00 a10 a01 a11 a02 a12 a03 a13
  73. // a20 a30 a21 a31 a22 a32 a23 a33
  74. // b00 b10 b01 b11 b02 b12 b03 b13
  75. // b20 b30 b21 b31 b22 b32 b23 b33
  76. const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
  77. const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
  78. const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
  79. const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
  80. // a00 a10 a20 a30 a01 a11 a21 a31
  81. // b00 b10 b20 b30 b01 b11 b21 b31
  82. // a02 a12 a22 a32 a03 a13 a23 a33
  83. // b02 b12 a22 b32 b03 b13 b23 b33
  84. *out0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
  85. *out1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
  86. *out2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
  87. *out3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
  88. // a00 a10 a20 a30 b00 b10 b20 b30
  89. // a01 a11 a21 a31 b01 b11 b21 b31
  90. // a02 a12 a22 a32 b02 b12 b22 b32
  91. // a03 a13 a23 a33 b03 b13 b23 b33
  92. }
  93. //------------------------------------------------------------------------------
  94. // Channel mixing.
  95. // Function used several times in VP8PlanarTo24b.
  96. // It samples the in buffer as follows: one every two unsigned char is stored
  97. // at the beginning of the buffer, while the other half is stored at the end.
  98. #define VP8PlanarTo24bHelper(IN, OUT) \
  99. do { \
  100. const __m128i v_mask = _mm_set1_epi16(0x00ff); \
  101. /* Take one every two upper 8b values.*/ \
  102. (OUT##0) = _mm_packus_epi16(_mm_and_si128((IN##0), v_mask), \
  103. _mm_and_si128((IN##1), v_mask)); \
  104. (OUT##1) = _mm_packus_epi16(_mm_and_si128((IN##2), v_mask), \
  105. _mm_and_si128((IN##3), v_mask)); \
  106. (OUT##2) = _mm_packus_epi16(_mm_and_si128((IN##4), v_mask), \
  107. _mm_and_si128((IN##5), v_mask)); \
  108. /* Take one every two lower 8b values.*/ \
  109. (OUT##3) = _mm_packus_epi16(_mm_srli_epi16((IN##0), 8), \
  110. _mm_srli_epi16((IN##1), 8)); \
  111. (OUT##4) = _mm_packus_epi16(_mm_srli_epi16((IN##2), 8), \
  112. _mm_srli_epi16((IN##3), 8)); \
  113. (OUT##5) = _mm_packus_epi16(_mm_srli_epi16((IN##4), 8), \
  114. _mm_srli_epi16((IN##5), 8)); \
  115. } while (0)
  116. // Pack the planar buffers
  117. // rrrr... rrrr... gggg... gggg... bbbb... bbbb....
  118. // triplet by triplet in the output buffer rgb as rgbrgbrgbrgb ...
  119. static WEBP_INLINE void VP8PlanarTo24b_SSE2(
  120. __m128i* const in0, __m128i* const in1, __m128i* const in2,
  121. __m128i* const in3, __m128i* const in4, __m128i* const in5) {
  122. // The input is 6 registers of sixteen 8b but for the sake of explanation,
  123. // let's take 6 registers of four 8b values.
  124. // To pack, we will keep taking one every two 8b integer and move it
  125. // around as follows:
  126. // Input:
  127. // r0r1r2r3 | r4r5r6r7 | g0g1g2g3 | g4g5g6g7 | b0b1b2b3 | b4b5b6b7
  128. // Split the 6 registers in two sets of 3 registers: the first set as the even
  129. // 8b bytes, the second the odd ones:
  130. // r0r2r4r6 | g0g2g4g6 | b0b2b4b6 | r1r3r5r7 | g1g3g5g7 | b1b3b5b7
  131. // Repeat the same permutations twice more:
  132. // r0r4g0g4 | b0b4r1r5 | g1g5b1b5 | r2r6g2g6 | b2b6r3r7 | g3g7b3b7
  133. // r0g0b0r1 | g1b1r2g2 | b2r3g3b3 | r4g4b4r5 | g5b5r6g6 | b6r7g7b7
  134. __m128i tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
  135. VP8PlanarTo24bHelper(*in, tmp);
  136. VP8PlanarTo24bHelper(tmp, *in);
  137. VP8PlanarTo24bHelper(*in, tmp);
  138. // We need to do it two more times than the example as we have sixteen bytes.
  139. {
  140. __m128i out0, out1, out2, out3, out4, out5;
  141. VP8PlanarTo24bHelper(tmp, out);
  142. VP8PlanarTo24bHelper(out, *in);
  143. }
  144. }
  145. #undef VP8PlanarTo24bHelper
  146. // Convert four packed four-channel buffers like argbargbargbargb... into the
  147. // split channels aaaaa ... rrrr ... gggg .... bbbbb ......
  148. static WEBP_INLINE void VP8L32bToPlanar_SSE2(__m128i* const in0,
  149. __m128i* const in1,
  150. __m128i* const in2,
  151. __m128i* const in3) {
  152. // Column-wise transpose.
  153. const __m128i A0 = _mm_unpacklo_epi8(*in0, *in1);
  154. const __m128i A1 = _mm_unpackhi_epi8(*in0, *in1);
  155. const __m128i A2 = _mm_unpacklo_epi8(*in2, *in3);
  156. const __m128i A3 = _mm_unpackhi_epi8(*in2, *in3);
  157. const __m128i B0 = _mm_unpacklo_epi8(A0, A1);
  158. const __m128i B1 = _mm_unpackhi_epi8(A0, A1);
  159. const __m128i B2 = _mm_unpacklo_epi8(A2, A3);
  160. const __m128i B3 = _mm_unpackhi_epi8(A2, A3);
  161. // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0
  162. // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0
  163. const __m128i C0 = _mm_unpacklo_epi8(B0, B1);
  164. const __m128i C1 = _mm_unpackhi_epi8(B0, B1);
  165. const __m128i C2 = _mm_unpacklo_epi8(B2, B3);
  166. const __m128i C3 = _mm_unpackhi_epi8(B2, B3);
  167. // Gather the channels.
  168. *in0 = _mm_unpackhi_epi64(C1, C3);
  169. *in1 = _mm_unpacklo_epi64(C1, C3);
  170. *in2 = _mm_unpackhi_epi64(C0, C2);
  171. *in3 = _mm_unpacklo_epi64(C0, C2);
  172. }
  173. #endif // WEBP_USE_SSE2
  174. #ifdef __cplusplus
  175. } // extern "C"
  176. #endif
  177. #endif // WEBP_DSP_COMMON_SSE2_H_