mixer_sse41.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2014 by Timothy Arceri <[email protected]>.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <xmmintrin.h>
  22. #include <emmintrin.h>
  23. #include <smmintrin.h>
  24. #include <algorithm>
  25. #include <array>
  26. #include <cstddef>
  27. #include <variant>
  28. #include "alnumeric.h"
  29. #include "alspan.h"
  30. #include "core/cubic_defs.h"
  31. #include "core/resampler_limits.h"
  32. #include "defs.h"
  33. #include "opthelpers.h"
  34. struct SSE4Tag;
  35. struct LerpTag;
  36. struct CubicTag;
  37. #if defined(__GNUC__) && !defined(__clang__) && !defined(__SSE4_1__)
  38. #pragma GCC target("sse4.1")
  39. #endif
  40. using uint = unsigned int;
  41. namespace {
  42. constexpr uint CubicPhaseDiffBits{MixerFracBits - CubicPhaseBits};
  43. constexpr uint CubicPhaseDiffOne{1 << CubicPhaseDiffBits};
  44. constexpr uint CubicPhaseDiffMask{CubicPhaseDiffOne - 1u};
  45. force_inline __m128 vmadd(const __m128 x, const __m128 y, const __m128 z) noexcept
  46. { return _mm_add_ps(x, _mm_mul_ps(y, z)); }
  47. } // namespace
  48. template<>
  49. void Resample_<LerpTag,SSE4Tag>(const InterpState*, const al::span<const float> src, uint frac,
  50. const uint increment, const al::span<float> dst)
  51. {
  52. ASSUME(frac < MixerFracOne);
  53. const __m128i increment4{_mm_set1_epi32(static_cast<int>(increment*4))};
  54. const __m128 fracOne4{_mm_set1_ps(1.0f/MixerFracOne)};
  55. const __m128i fracMask4{_mm_set1_epi32(MixerFracMask)};
  56. std::array<uint,4> pos_{}, frac_{};
  57. InitPosArrays(MaxResamplerEdge, frac, increment, al::span{frac_}, al::span{pos_});
  58. __m128i frac4{_mm_setr_epi32(static_cast<int>(frac_[0]), static_cast<int>(frac_[1]),
  59. static_cast<int>(frac_[2]), static_cast<int>(frac_[3]))};
  60. __m128i pos4{_mm_setr_epi32(static_cast<int>(pos_[0]), static_cast<int>(pos_[1]),
  61. static_cast<int>(pos_[2]), static_cast<int>(pos_[3]))};
  62. auto vecout = al::span{reinterpret_cast<__m128*>(dst.data()), dst.size()/4};
  63. std::generate(vecout.begin(), vecout.end(), [=,&pos4,&frac4]
  64. {
  65. const auto pos0 = static_cast<uint>(_mm_extract_epi32(pos4, 0));
  66. const auto pos1 = static_cast<uint>(_mm_extract_epi32(pos4, 1));
  67. const auto pos2 = static_cast<uint>(_mm_extract_epi32(pos4, 2));
  68. const auto pos3 = static_cast<uint>(_mm_extract_epi32(pos4, 3));
  69. ASSUME(pos0 <= pos1); ASSUME(pos1 <= pos2); ASSUME(pos2 <= pos3);
  70. const __m128 val1{_mm_setr_ps(src[pos0], src[pos1], src[pos2], src[pos3])};
  71. const __m128 val2{_mm_setr_ps(src[pos0+1_uz], src[pos1+1_uz], src[pos2+1_uz], src[pos3+1_uz])};
  72. /* val1 + (val2-val1)*mu */
  73. const __m128 r0{_mm_sub_ps(val2, val1)};
  74. const __m128 mu{_mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4)};
  75. const __m128 out{_mm_add_ps(val1, _mm_mul_ps(mu, r0))};
  76. frac4 = _mm_add_epi32(frac4, increment4);
  77. pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, MixerFracBits));
  78. frac4 = _mm_and_si128(frac4, fracMask4);
  79. return out;
  80. });
  81. if(size_t todo{dst.size()&3})
  82. {
  83. /* NOTE: These four elements represent the position *after* the last
  84. * four samples, so the lowest element is the next position to
  85. * resample.
  86. */
  87. auto pos = size_t{static_cast<uint>(_mm_cvtsi128_si32(pos4))};
  88. frac = static_cast<uint>(_mm_cvtsi128_si32(frac4));
  89. auto out = dst.last(todo);
  90. std::generate(out.begin(), out.end(), [&pos,&frac,src,increment]
  91. {
  92. const float smp{lerpf(src[pos+0], src[pos+1],
  93. static_cast<float>(frac) * (1.0f/MixerFracOne))};
  94. frac += increment;
  95. pos += frac>>MixerFracBits;
  96. frac &= MixerFracMask;
  97. return smp;
  98. });
  99. }
  100. }
  101. template<>
  102. void Resample_<CubicTag,SSE4Tag>(const InterpState *state, const al::span<const float> src,
  103. uint frac, const uint increment, const al::span<float> dst)
  104. {
  105. ASSUME(frac < MixerFracOne);
  106. const auto filter = std::get<CubicState>(*state).filter;
  107. const __m128i increment4{_mm_set1_epi32(static_cast<int>(increment*4))};
  108. const __m128i fracMask4{_mm_set1_epi32(MixerFracMask)};
  109. const __m128 fracDiffOne4{_mm_set1_ps(1.0f/CubicPhaseDiffOne)};
  110. const __m128i fracDiffMask4{_mm_set1_epi32(CubicPhaseDiffMask)};
  111. std::array<uint,4> pos_{}, frac_{};
  112. InitPosArrays(MaxResamplerEdge-1, frac, increment, al::span{frac_}, al::span{pos_});
  113. __m128i frac4{_mm_setr_epi32(static_cast<int>(frac_[0]), static_cast<int>(frac_[1]),
  114. static_cast<int>(frac_[2]), static_cast<int>(frac_[3]))};
  115. __m128i pos4{_mm_setr_epi32(static_cast<int>(pos_[0]), static_cast<int>(pos_[1]),
  116. static_cast<int>(pos_[2]), static_cast<int>(pos_[3]))};
  117. auto vecout = al::span{reinterpret_cast<__m128*>(dst.data()), dst.size()/4};
  118. std::generate(vecout.begin(), vecout.end(), [=,&pos4,&frac4]
  119. {
  120. const auto pos0 = static_cast<uint>(_mm_extract_epi32(pos4, 0));
  121. const auto pos1 = static_cast<uint>(_mm_extract_epi32(pos4, 1));
  122. const auto pos2 = static_cast<uint>(_mm_extract_epi32(pos4, 2));
  123. const auto pos3 = static_cast<uint>(_mm_extract_epi32(pos4, 3));
  124. ASSUME(pos0 <= pos1); ASSUME(pos1 <= pos2); ASSUME(pos2 <= pos3);
  125. const __m128 val0{_mm_loadu_ps(&src[pos0])};
  126. const __m128 val1{_mm_loadu_ps(&src[pos1])};
  127. const __m128 val2{_mm_loadu_ps(&src[pos2])};
  128. const __m128 val3{_mm_loadu_ps(&src[pos3])};
  129. const __m128i pi4{_mm_srli_epi32(frac4, CubicPhaseDiffBits)};
  130. const auto pi0 = static_cast<uint>(_mm_extract_epi32(pi4, 0));
  131. const auto pi1 = static_cast<uint>(_mm_extract_epi32(pi4, 1));
  132. const auto pi2 = static_cast<uint>(_mm_extract_epi32(pi4, 2));
  133. const auto pi3 = static_cast<uint>(_mm_extract_epi32(pi4, 3));
  134. ASSUME(pi0 < CubicPhaseCount); ASSUME(pi1 < CubicPhaseCount);
  135. ASSUME(pi2 < CubicPhaseCount); ASSUME(pi3 < CubicPhaseCount);
  136. const __m128 pf4{_mm_mul_ps(_mm_cvtepi32_ps(_mm_and_si128(frac4, fracDiffMask4)),
  137. fracDiffOne4)};
  138. __m128 r0{_mm_mul_ps(val0,
  139. vmadd(_mm_load_ps(filter[pi0].mCoeffs.data()),
  140. _mm_shuffle_ps(pf4, pf4, _MM_SHUFFLE(0, 0, 0, 0)),
  141. _mm_load_ps(filter[pi0].mDeltas.data())))};
  142. __m128 r1{_mm_mul_ps(val1,
  143. vmadd(_mm_load_ps(filter[pi1].mCoeffs.data()),
  144. _mm_shuffle_ps(pf4, pf4, _MM_SHUFFLE(1, 1, 1, 1)),
  145. _mm_load_ps(filter[pi1].mDeltas.data())))};
  146. __m128 r2{_mm_mul_ps(val2,
  147. vmadd(_mm_load_ps(filter[pi2].mCoeffs.data()),
  148. _mm_shuffle_ps(pf4, pf4, _MM_SHUFFLE(2, 2, 2, 2)),
  149. _mm_load_ps(filter[pi2].mDeltas.data())))};
  150. __m128 r3{_mm_mul_ps(val3,
  151. vmadd(_mm_load_ps(filter[pi3].mCoeffs.data()),
  152. _mm_shuffle_ps(pf4, pf4, _MM_SHUFFLE(3, 3, 3, 3)),
  153. _mm_load_ps(filter[pi3].mDeltas.data())))};
  154. _MM_TRANSPOSE4_PS(r0, r1, r2, r3);
  155. r0 = _mm_add_ps(_mm_add_ps(r0, r1), _mm_add_ps(r2, r3));
  156. frac4 = _mm_add_epi32(frac4, increment4);
  157. pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, MixerFracBits));
  158. frac4 = _mm_and_si128(frac4, fracMask4);
  159. return r0;
  160. });
  161. if(const size_t todo{dst.size()&3})
  162. {
  163. auto pos = size_t{static_cast<uint>(_mm_cvtsi128_si32(pos4))};
  164. frac = static_cast<uint>(_mm_cvtsi128_si32(frac4));
  165. auto out = dst.last(todo);
  166. std::generate(out.begin(), out.end(), [&pos,&frac,src,increment,filter]
  167. {
  168. const uint pi{frac >> CubicPhaseDiffBits}; ASSUME(pi < CubicPhaseCount);
  169. const float pf{static_cast<float>(frac&CubicPhaseDiffMask) * (1.0f/CubicPhaseDiffOne)};
  170. const __m128 pf4{_mm_set1_ps(pf)};
  171. const __m128 f4 = vmadd(_mm_load_ps(filter[pi].mCoeffs.data()), pf4,
  172. _mm_load_ps(filter[pi].mDeltas.data()));
  173. __m128 r4{_mm_mul_ps(f4, _mm_loadu_ps(&src[pos]))};
  174. r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3)));
  175. r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4));
  176. const float output{_mm_cvtss_f32(r4)};
  177. frac += increment;
  178. pos += frac>>MixerFracBits;
  179. frac &= MixerFracMask;
  180. return output;
  181. });
  182. }
  183. }