Moved applyGain to the new mode

This commit is contained in:
Paul Ferrand 2020-05-30 22:17:33 +02:00 committed by Jean Pierre Cimalando
parent 3c551d8f34
commit 1ab1ab802b
5 changed files with 140 additions and 130 deletions

View file

@ -66,14 +66,14 @@ BENCHMARK_DEFINE_F(GainSingle, Straight)(benchmark::State& state) {
BENCHMARK_DEFINE_F(GainSingle, Scalar)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
}
}
BENCHMARK_DEFINE_F(GainSingle, SIMD)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
}
}
@ -88,28 +88,28 @@ BENCHMARK_DEFINE_F(GainArray, Straight)(benchmark::State& state) {
BENCHMARK_DEFINE_F(GainArray, Scalar)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
}
}
BENCHMARK_DEFINE_F(GainArray, SIMD)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
}
}
BENCHMARK_DEFINE_F(GainArray, Scalar_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, false>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
sfz::applyGain<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
}
}
BENCHMARK_DEFINE_F(GainArray, SIMD_Unaligned)(benchmark::State& state) {
for (auto _ : state)
{
sfz::applyGain<float, true>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
sfz::applyGain<float>(absl::MakeSpan(gain).subspan(1), absl::MakeSpan(input).subspan(1), absl::MakeSpan(output).subspan(1));
}
}

View file

@ -13,6 +13,7 @@ namespace sfz {
static std::array<bool, static_cast<unsigned>(SIMDOps::_sentinel)> simdStatus;
static bool simdStatusInitialized = false;
static cpuid::cpuinfo cpuInfo;
void resetSIMDStatus()
{
@ -58,7 +59,7 @@ bool getSIMDOpStatus(SIMDOps op)
constexpr uintptr_t TypeAlignment = 4;
template<class T>
template <class T>
inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight)
{
*outputLeft++ = *input++;
@ -75,7 +76,7 @@ inline void tickWrite(T*& output, const T*& inputLeft, const T*& inputRight)
void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept
{
const auto sentinel = input + inputSize - 1;
cpuid::cpuinfo cpuInfo;
if (getSIMDOpStatus(SIMDOps::readInterleaved)) {
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
if (cpuInfo.has_sse()) {
@ -109,8 +110,7 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou
{
const auto sentinel = output + outputSize - 1;
cpuid::cpuinfo cpuInfo;
if (getSIMDOpStatus(SIMDOps::readInterleaved)) {
if (getSIMDOpStatus(SIMDOps::writeInterleaved)) {
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
if (cpuInfo.has_sse()) {
const auto* lastAligned = prevAligned(output + outputSize - 4);
@ -136,5 +136,56 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou
tickWrite(output, inputLeft, inputRight);
}
template<>
void applyGain<float>(float gain, const float* input, float* output, unsigned size) noexcept
{
const auto sentinel = output + size;
if (getSIMDOpStatus(SIMDOps::gain)) {
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
if (cpuInfo.has_sse()) {
const auto* lastAligned = prevAligned(sentinel);
const auto mmGain = _mm_set_ps1(gain);
while (unaligned(input, output) && output < lastAligned)
*output++ = gain * (*input++);
while (output < lastAligned) {
_mm_store_ps(output, _mm_mul_ps(mmGain, _mm_load_ps(input)));
incrementAll<4>(input, output);
}
// fallthrough from lastAligned to sentinel
}
#endif
}
while (output < sentinel)
*output++ = gain * (*input++);
}
template<>
void applyGain<float>(const float* gain, const float* input, float* output, unsigned size) noexcept
{
const auto sentinel = output + size;
if (getSIMDOpStatus(SIMDOps::gain)) {
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
if (cpuInfo.has_sse()) {
const auto* lastAligned = prevAligned(sentinel);
while (unaligned(input, output) && output < lastAligned)
*output++ = (*gain++) * (*input++);
while (output < lastAligned) {
_mm_store_ps(output, _mm_mul_ps(_mm_load_ps(gain), _mm_load_ps(input)));
incrementAll<4>(gain, input, output);
}
// fallthrough from lastAligned to sentinel
}
#endif
}
while (output < sentinel)
*output++ = (*gain++) * (*input++);
}
}

View file

@ -112,14 +112,13 @@ void readInterleaved(const float* input, float* outputLeft, float* outputRight,
inline void readInterleaved(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
{
// The size of the output is not big enough for the input...
CHECK(outputLeft.size() >= input.size() / 2);
CHECK(outputRight.size() >= input.size() / 2);
// Something is fishy with the sizes
CHECK(outputLeft.size() == input.size() / 2);
CHECK(outputRight.size() == input.size() / 2);
const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size());
readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size);
}
/**
* @brief Write a pair of left and right stereo input into a single buffer interleaved.
*
@ -132,9 +131,9 @@ void writeInterleaved(const float* inputLeft, const float* inputRight, float* ou
inline void writeInterleaved(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
{
// Not enough data in the inputs
CHECK(inputLeft.size() >= output.size() / 2);
CHECK(inputRight.size() >= output.size() / 2);
// Something is fishy with the sizes
CHECK(inputLeft.size() == output.size() / 2);
CHECK(inputRight.size() == output.size() / 2);
const auto size = min(output.size(), 2 * inputLeft.size(), 2 * inputRight.size());
writeInterleaved(inputLeft.data(), inputRight.data(), output.data(), size);
}
@ -152,103 +151,96 @@ void fill(absl::Span<T> output, T value) noexcept
absl::c_fill(output, value);
}
namespace _internals {
template <class T>
inline void snippetGain(T gain, const T*& input, T*& output)
{
*output++ = gain * (*input++);
}
}
/**
* @brief Applies a scalar gain to the input
*
* The output size will be the minimum of the input span and output span size.
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param gain the gain to apply
* @param input
* @param output
* @param size
*/
template <class T, bool SIMD = SIMDConfig::gain>
void applyGain(T gain, absl::Span<const T> input, absl::Span<T> output) noexcept
template<class T>
void applyGain(T gain, const T* input, T* output, unsigned size) noexcept
{
CHECK(input.size() <= output.size());
auto* in = input.begin();
auto* out = output.begin();
auto* sentinel = out + std::min(output.size(), input.size());
while (out < sentinel)
_internals::snippetGain<T>(gain, in, out);
const auto sentinel = output + size;
while (output < sentinel)
*output++ = gain * (*input++);
}
namespace _internals {
template <class T>
inline void snippetGainSpan(const T*& gain, const T*& input, T*& output)
{
*output++ = (*gain++) * (*input++);
}
template<>
void applyGain<float>(float gain, const float* input, float* output, unsigned size) noexcept;
template<class T>
inline void applyGain(T gain, absl::Span<const T> input, absl::Span<T> output) noexcept
{
CHECK_SPAN_SIZES(input, output);
applyGain<T>(gain, input.data(), output.data(), minSpanSize(input, output));
}
/**
* @brief Applies a vector gain to an input stap
* @brief Applies a scalar gain inplace
*
* The output size will be the minimum of the gain, input span and output span size.
* @param gain the gain to apply
* @param array
* @param size
*/
template<class T>
inline void applyGain(float gain, float* array, unsigned size) noexcept
{
applyGain<T>(gain, array, array, size);
}
template<class T>
inline void applyGain(float gain, absl::Span<float> array) noexcept
{
applyGain<T>(gain, array.data(), array.data(), array.size());
}
/**
* @brief Applies a vector gain to an input span
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param gain
* @param input
* @param output
* @param size
*/
template <class T, bool SIMD = SIMDConfig::gain>
void applyGain(absl::Span<const T> gain, absl::Span<const T> input, absl::Span<T> output) noexcept
template<class T>
void applyGain(const T* gain, const T* input, T* output, unsigned size) noexcept
{
CHECK(gain.size() == input.size());
CHECK(input.size() <= output.size());
auto* in = input.begin();
auto* g = gain.begin();
auto* out = output.begin();
auto* sentinel = out + std::min(gain.size(), std::min(output.size(), input.size()));
while (out < sentinel)
_internals::snippetGainSpan<T>(g, in, out);
const auto sentinel = output + size;
while (output < sentinel)
*output++ = (*gain++) * (*input++);
}
/**
* @brief Applies a scalar gain in-place on a span
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param gain
* @param output
*/
template <class T, bool SIMD = SIMDConfig::gain>
void applyGain(T gain, absl::Span<T> output) noexcept
template<>
void applyGain<float>(const float* gain, const float* input, float* output, unsigned size) noexcept;
template<class T>
inline void applyGain(absl::Span<const T> gain, absl::Span<const T> input, absl::Span<T> output) noexcept
{
applyGain<T, SIMD>(gain, output, output);
CHECK_SPAN_SIZES(gain, input, output);
applyGain<T>(gain.data(), input.data(), output.data(), minSpanSize(gain, input, output));
}
/**
* @brief Applies a vector gain in-place on a span
*
* The output size will be the minimum of the gain span and output span size.
*
* @tparam T the underlying type
* @tparam SIMD use the SIMD version or the scalar version
* @param gain
* @param output
* @param array
* @param size
*/
template <class T, bool SIMD = SIMDConfig::gain>
void applyGain(absl::Span<const T> gain, absl::Span<T> output) noexcept
template<class T>
inline void applyGain(const T* gain, T* array, unsigned size) noexcept
{
applyGain<T, SIMD>(gain, output, output);
applyGain<T>(gain, array, array, size);
}
template <>
void applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept;
template <>
void applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept;
template<class T>
inline void applyGain(absl::Span<const T> gain, absl::Span<T> array) noexcept
{
CHECK_SPAN_SIZES(gain, array);
applyGain<T>(gain.data(), array.data(), array.data(), minSpanSize(gain, array));
}
namespace _internals {
template <class T>

View file

@ -16,47 +16,6 @@
constexpr uintptr_t TypeAlignment = 4;
template <>
void sfz::applyGain<float, true>(float gain, absl::Span<const float> input, absl::Span<float> output) noexcept
{
auto* in = input.begin();
auto* out = output.begin();
const auto size = std::min(output.size(), input.size());
const auto* lastAligned = prevAligned(output.begin() + size);
const auto mmGain = _mm_set_ps1(gain);
while (unaligned(out, in) && out < lastAligned)
*out++ = gain * (*in++);
while (out < lastAligned) {
_mm_store_ps(out, _mm_mul_ps(mmGain, _mm_load_ps(in)));
incrementAll<TypeAlignment>(out, in);
}
while (out < output.end())
*out++ = gain * (*in++);
}
template <>
void sfz::applyGain<float, true>(absl::Span<const float> gain, absl::Span<const float> input, absl::Span<float> output) noexcept
{
auto* in = input.begin();
auto* out = output.begin();
auto* g = gain.begin();
const auto size = std::min(output.size(), std::min(input.size(), gain.size()));
const auto* lastAligned = prevAligned(output.begin() + size);
while (unaligned(out, in, g) && out < lastAligned)
_internals::snippetGainSpan<float>(g, in, out);
while (out < lastAligned) {
_mm_store_ps(out, _mm_mul_ps(_mm_load_ps(g), _mm_load_ps(in)));
incrementAll<TypeAlignment>(g, in, out);
}
while (out < output.end())
_internals::snippetGainSpan<float>(g, in, out);
}
template <>

View file

@ -275,7 +275,8 @@ TEST_CASE("[Helpers] Gain, single")
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
sfz::applyGain<float, false>(fillValue, input, absl::MakeSpan(output));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false);
sfz::applyGain<float>(fillValue, input, absl::MakeSpan(output));
REQUIRE(output == expected);
}
@ -283,7 +284,8 @@ TEST_CASE("[Helpers] Gain, single and inplace")
{
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
sfz::applyGain<float, false>(fillValue, buffer, absl::MakeSpan(buffer));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false);
sfz::applyGain<float>(fillValue, buffer, absl::MakeSpan(buffer));
REQUIRE(buffer == expected);
}
@ -293,7 +295,8 @@ TEST_CASE("[Helpers] Gain, spans")
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
sfz::applyGain<float, false>(gain, input, absl::MakeSpan(output));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false);
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
REQUIRE(output == expected);
}
@ -302,7 +305,8 @@ TEST_CASE("[Helpers] Gain, spans and inplace")
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
sfz::applyGain<float, false>(gain, buffer, absl::MakeSpan(buffer));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, false);
sfz::applyGain<float>(gain, buffer, absl::MakeSpan(buffer));
REQUIRE(buffer == expected);
}
@ -311,7 +315,8 @@ TEST_CASE("[Helpers] Gain, single (SIMD)")
std::array<float, 5> input { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
sfz::applyGain<float, true>(fillValue, input, absl::MakeSpan(output));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true);
sfz::applyGain<float>(fillValue, input, absl::MakeSpan(output));
REQUIRE(output == expected);
}
@ -319,7 +324,8 @@ TEST_CASE("[Helpers] Gain, single and inplace (SIMD)")
{
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> expected { fillValue, fillValue, fillValue, fillValue, fillValue };
sfz::applyGain<float, true>(fillValue, buffer, absl::MakeSpan(buffer));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true);
sfz::applyGain<float>(fillValue, buffer, absl::MakeSpan(buffer));
REQUIRE(buffer == expected);
}
@ -329,7 +335,8 @@ TEST_CASE("[Helpers] Gain, spans (SIMD)")
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
std::array<float, 5> output { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
sfz::applyGain<float, true>(gain, input, absl::MakeSpan(output));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true);
sfz::applyGain<float>(gain, input, absl::MakeSpan(output));
REQUIRE(output == expected);
}
@ -338,7 +345,8 @@ TEST_CASE("[Helpers] Gain, spans and inplace (SIMD)")
std::array<float, 5> buffer { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
std::array<float, 5> gain { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
std::array<float, 5> expected { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f };
sfz::applyGain<float, true>(gain, buffer, absl::MakeSpan(buffer));
sfz::setSIMDOpStatus(sfz::SIMDOps::gain, true);
sfz::applyGain<float>(gain, buffer, absl::MakeSpan(buffer));
REQUIRE(buffer == expected);
}