Update the read and write SIMD helpers with the new approach
This commit is contained in:
parent
91435249c0
commit
f827e7c2e5
6 changed files with 168 additions and 175 deletions
|
|
@ -3,6 +3,7 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
|
|||
|
||||
list (APPEND ${SOURCES_VAR}
|
||||
${PREFIX}/sfizz/SIMDSSE.cpp
|
||||
${PREFIX}/sfizz/SIMDHelpers.cpp
|
||||
${PREFIX}/sfizz/SIMDNEON.cpp
|
||||
${PREFIX}/sfizz/SIMDDummy.cpp)
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void readBaseFile(SndfileHandle& sndFile, sfz::FileAudioBuffer& output, uint32_t
|
|||
output.clear();
|
||||
sfz::Buffer<float> tempReadBuffer { 2 * numFrames };
|
||||
sndFile.readf(tempReadBuffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
||||
sfz::readInterleaved(tempReadBuffer, output.getSpan(0), output.getSpan(1));
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
|
|
@ -87,7 +87,6 @@ std::unique_ptr<sfz::FileAudioBuffer> readFromFile(SndfileHandle& sndFile, uint3
|
|||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void streamFromFile(SndfileHandle& sndFile, uint32_t numFrames, sfz::Oversampling factor, bool reverse, sfz::FileAudioBuffer& output, std::atomic<size_t>* filledFrames = nullptr)
|
||||
{
|
||||
if (factor == sfz::Oversampling::x1) {
|
||||
|
|
@ -400,7 +399,7 @@ void sfz::FilePool::loadingThread() noexcept
|
|||
continue;
|
||||
}
|
||||
const auto frames = static_cast<uint32_t>(sndFile.frames());
|
||||
streamFromFile<float>(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames);
|
||||
streamFromFile(sndFile, frames, oversamplingFactor, promise->fileId.isReverse(), promise->fileData, &promise->availableFrames);
|
||||
promise->dataStatus = FilePromise::DataStatus::Ready;
|
||||
const auto loadDuration = std::chrono::high_resolution_clock::now() - loadStartTime;
|
||||
logger.logFileTime(waitDuration, loadDuration, frames, promise->fileId.filename());
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
#include "SIMDHelpers.h"
|
||||
#include <array>
|
||||
#include "cpuid/cpuinfo.hpp"
|
||||
|
||||
namespace sfz{
|
||||
#include "SIMDConfig.h"
|
||||
|
||||
static std::array<bool, static_cast<unsigned>(sfz::SIMDOps::_sentinel)> simdStatus;
|
||||
#if SFIZZ_HAVE_SSE2
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace sfz {
|
||||
|
||||
static std::array<bool, static_cast<unsigned>(SIMDOps::_sentinel)> simdStatus;
|
||||
static bool simdStatusInitialized = false;
|
||||
|
||||
static void resetSIMDStatus()
|
||||
void resetSIMDStatus()
|
||||
{
|
||||
simdStatus[static_cast<unsigned>(SIMDOps::writeInterleaved)] = true;
|
||||
simdStatus[static_cast<unsigned>(SIMDOps::readInterleaved)] = true;
|
||||
|
|
@ -32,14 +40,15 @@ static void resetSIMDStatus()
|
|||
simdStatusInitialized = true;
|
||||
}
|
||||
|
||||
static void setSIMDOpStatus(SIMDOps op, bool status)
|
||||
void setSIMDOpStatus(SIMDOps op, bool status)
|
||||
{
|
||||
if (!simdStatusInitialized)
|
||||
resetSIMDStatus();
|
||||
|
||||
simdStatus[static_cast<unsigned>(op)] = status;
|
||||
}
|
||||
static bool getSIMDOpStatus(SIMDOps op)
|
||||
|
||||
bool getSIMDOpStatus(SIMDOps op)
|
||||
{
|
||||
if (!simdStatusInitialized)
|
||||
resetSIMDStatus();
|
||||
|
|
@ -47,5 +56,85 @@ static bool getSIMDOpStatus(SIMDOps op)
|
|||
return simdStatus[static_cast<unsigned>(op)];
|
||||
}
|
||||
|
||||
constexpr uintptr_t TypeAlignment = 4;
|
||||
|
||||
template<class T>
|
||||
inline void tickRead(const T*& input, T*& outputLeft, T*& outputRight)
|
||||
{
|
||||
*outputLeft++ = *input++;
|
||||
*outputRight++ = *input++;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void tickWrite(T*& output, const T*& inputLeft, const T*& inputRight)
|
||||
{
|
||||
*output++ = *inputLeft++;
|
||||
*output++ = *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()) {
|
||||
const auto* lastAligned = prevAligned(input + inputSize - 4);
|
||||
while (unaligned(input, outputLeft, outputRight) && input < lastAligned)
|
||||
tickRead(input, outputLeft, outputRight);
|
||||
|
||||
while (input < lastAligned) {
|
||||
auto register0 = _mm_load_ps(input);
|
||||
auto register1 = _mm_load_ps(input + 4);
|
||||
auto register2 = register0;
|
||||
// register 2 holds the copy of register 0 that is going to get erased by the first operation
|
||||
// Remember that the bit mask reads from the end; 10 00 10 00 means
|
||||
// "take 0 from a, take 2 from a, take 0 from b, take 2 from b"
|
||||
register0 = _mm_shuffle_ps(register0, register1, 0b10001000);
|
||||
register1 = _mm_shuffle_ps(register2, register1, 0b11011101);
|
||||
_mm_store_ps(outputLeft, register0);
|
||||
_mm_store_ps(outputRight, register1);
|
||||
incrementAll<4>(input, input, outputLeft, outputRight);
|
||||
}
|
||||
// Fallthrough from lastAligned to sentinel
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while (input < sentinel)
|
||||
tickRead(input, outputLeft, outputRight);
|
||||
}
|
||||
|
||||
void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept
|
||||
{
|
||||
const auto sentinel = output + outputSize - 1;
|
||||
|
||||
cpuid::cpuinfo cpuInfo;
|
||||
if (getSIMDOpStatus(SIMDOps::readInterleaved)) {
|
||||
#if SFIZZ_CPU_FAMILY_X86_64 || SFIZZ_CPU_FAMILY_I386
|
||||
if (cpuInfo.has_sse()) {
|
||||
const auto* lastAligned = prevAligned(output + outputSize - 4);
|
||||
|
||||
while (unaligned(output, inputRight, inputLeft) && output < lastAligned)
|
||||
tickWrite(output, inputLeft, inputRight);
|
||||
|
||||
while (output < lastAligned) {
|
||||
const auto lInRegister = _mm_load_ps(inputLeft);
|
||||
const auto rInRegister = _mm_load_ps(inputRight);
|
||||
const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(output, outRegister1);
|
||||
const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(output + 4, outRegister2);
|
||||
incrementAll<4>(output, output, inputLeft, inputRight);
|
||||
}
|
||||
// fallthrough from lastAligned to sentinel
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
while (output < sentinel)
|
||||
tickWrite(output, inputLeft, inputRight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,18 +69,35 @@ enum class SIMDOps {
|
|||
upsampling,
|
||||
_sentinel //
|
||||
};
|
||||
|
||||
// Enable or disable SIMD accelerators at runtime
|
||||
static void setSIMDOpStatus(SIMDOps op, bool status);
|
||||
static bool getSIMDOpStatus(SIMDOps op);
|
||||
void setSIMDOpStatus(SIMDOps op, bool status);
|
||||
bool getSIMDOpStatus(SIMDOps op);
|
||||
|
||||
constexpr uintptr_t ByteAlignmentMask { config::defaultAlignment - 1 };
|
||||
|
||||
namespace _internals {
|
||||
template <class T>
|
||||
inline void snippetRead(const T*& input, T*& outputLeft, T*& outputRight)
|
||||
{
|
||||
*outputLeft++ = *input++;
|
||||
*outputRight++ = *input++;
|
||||
}
|
||||
template<class T>
|
||||
T* nextAligned(const T* ptr)
|
||||
{
|
||||
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T* prevAligned(const T* ptr)
|
||||
{
|
||||
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool unaligned(const T* ptr)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask )!= 0;
|
||||
}
|
||||
|
||||
template<class T, class... Args>
|
||||
bool unaligned(const T* ptr1, Args... rest)
|
||||
{
|
||||
return unaligned(ptr1) || unaligned(rest...);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,33 +106,21 @@ namespace _internals {
|
|||
* The output size will be the minimum of the input span and output spans size.
|
||||
*
|
||||
* @tparam T the underlying type
|
||||
* @tparam SIMD use the SIMD version or the scalar version
|
||||
* @param input
|
||||
* @param outputLeft
|
||||
* @param outputRight
|
||||
*/
|
||||
template <class T, bool SIMD = SIMDConfig::readInterleaved>
|
||||
void readInterleaved(absl::Span<const T> input, absl::Span<T> outputLeft, absl::Span<T> outputRight) noexcept
|
||||
void readInterleaved(const float* input, float* outputLeft, float* outputRight, unsigned inputSize) noexcept;
|
||||
|
||||
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);
|
||||
|
||||
auto* in = input.begin();
|
||||
auto* lOut = outputLeft.begin();
|
||||
auto* rOut = outputRight.begin();
|
||||
while (in < (input.end() - 1) && lOut < outputLeft.end() && rOut < outputRight.end())
|
||||
_internals::snippetRead<T>(in, lOut, rOut);
|
||||
const auto size = min(input.size(), 2 * outputLeft.size(), 2 * outputRight.size());
|
||||
readInterleaved(input.data(), outputLeft.data(), outputRight.data(), size);
|
||||
}
|
||||
|
||||
namespace _internals {
|
||||
template <class T>
|
||||
inline void snippetWrite(T*& output, const T*& inputLeft, const T*& inputRight)
|
||||
{
|
||||
*output++ = *inputLeft++;
|
||||
*output++ = *inputRight++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write a pair of left and right stereo input into a single buffer interleaved.
|
||||
|
|
@ -123,30 +128,21 @@ namespace _internals {
|
|||
* The output size will be the minimum of the input spans and output span size.
|
||||
*
|
||||
* @tparam T the underlying type
|
||||
* @tparam SIMD use the SIMD version or the scalar version
|
||||
* @param inputLeft
|
||||
* @param inputRight
|
||||
* @param output
|
||||
*/
|
||||
template <class T, bool SIMD = SIMDConfig::writeInterleaved>
|
||||
void writeInterleaved(absl::Span<const T> inputLeft, absl::Span<const T> inputRight, absl::Span<T> output) noexcept
|
||||
void writeInterleaved(const float* inputLeft, const float* inputRight, float* output, unsigned outputSize) noexcept;
|
||||
|
||||
inline void writeInterleaved(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||
{
|
||||
CHECK(inputLeft.size() <= output.size() / 2);
|
||||
CHECK(inputRight.size() <= output.size() / 2);
|
||||
|
||||
auto* lIn = inputLeft.begin();
|
||||
auto* rIn = inputRight.begin();
|
||||
auto* out = output.begin();
|
||||
while (lIn < inputLeft.end() && rIn < inputRight.end() && out < (output.end() - 1))
|
||||
_internals::snippetWrite<T>(out, lIn, rIn);
|
||||
// Not enough data in the inputs
|
||||
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);
|
||||
}
|
||||
|
||||
// Specializations
|
||||
template <>
|
||||
void writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept;
|
||||
template <>
|
||||
void readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Fill a buffer with a value; comparable to std::fill in essence.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -12,116 +12,9 @@
|
|||
#include <array>
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
#include "mathfuns/sse_mathfun.h"
|
||||
|
||||
using Type = float;
|
||||
constexpr uintptr_t TypeAlignment { 4 };
|
||||
constexpr uintptr_t ByteAlignment { TypeAlignment * sizeof(Type) };
|
||||
constexpr uintptr_t ByteAlignmentMask { ByteAlignment - 1 };
|
||||
|
||||
struct AlignmentSentinels {
|
||||
float* nextAligned;
|
||||
float* lastAligned;
|
||||
};
|
||||
|
||||
float* nextAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>((reinterpret_cast<uintptr_t>(ptr) + ByteAlignmentMask) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
float* prevAligned(const float* ptr)
|
||||
{
|
||||
return reinterpret_cast<float*>(reinterpret_cast<uintptr_t>(ptr) & (~ByteAlignmentMask));
|
||||
}
|
||||
|
||||
bool unaligned(const float* ptr)
|
||||
{
|
||||
return (reinterpret_cast<uintptr_t>(ptr) & ByteAlignmentMask) != 0;
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
bool unaligned(const float* ptr1, Args... rest)
|
||||
{
|
||||
return unaligned(ptr1) || unaligned(rest...);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::readInterleaved<float, true>(absl::Span<const float> input, absl::Span<float> outputLeft, absl::Span<float> outputRight) noexcept
|
||||
{
|
||||
// The size of the outputs is not big enough for the input...
|
||||
CHECK(outputLeft.size() >= input.size() / 2);
|
||||
CHECK(outputRight.size() >= input.size() / 2);
|
||||
// Input is too small
|
||||
CHECK(input.size() > 1);
|
||||
|
||||
auto* in = input.begin();
|
||||
auto* lOut = outputLeft.begin();
|
||||
auto* rOut = outputRight.begin();
|
||||
|
||||
const auto size = std::min(input.size(), std::min(outputLeft.size() * 2, outputRight.size() * 2));
|
||||
const auto* lastAligned = prevAligned(input.begin() + size - TypeAlignment);
|
||||
|
||||
while (unaligned(in, lOut, rOut) && in < lastAligned)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
|
||||
while (in < lastAligned) {
|
||||
auto register0 = _mm_load_ps(in);
|
||||
in += TypeAlignment;
|
||||
auto register1 = _mm_load_ps(in);
|
||||
in += TypeAlignment;
|
||||
auto register2 = register0;
|
||||
// register 2 holds the copy of register 0 that is going to get erased by the first operation
|
||||
// Remember that the bit mask reads from the end; 10 00 10 00 means
|
||||
// "take 0 from a, take 2 from a, take 0 from b, take 2 from b"
|
||||
register0 = _mm_shuffle_ps(register0, register1, 0b10001000);
|
||||
register1 = _mm_shuffle_ps(register2, register1, 0b11011101);
|
||||
_mm_store_ps(lOut, register0);
|
||||
_mm_store_ps(rOut, register1);
|
||||
lOut += TypeAlignment;
|
||||
rOut += TypeAlignment;
|
||||
}
|
||||
|
||||
while (in < input.end() - 1)
|
||||
_internals::snippetRead<float>(in, lOut, rOut);
|
||||
}
|
||||
|
||||
template <>
|
||||
void sfz::writeInterleaved<float, true>(absl::Span<const float> inputLeft, absl::Span<const float> inputRight, absl::Span<float> output) noexcept
|
||||
{
|
||||
// The size of the output is not big enough for the inputs...
|
||||
CHECK(inputLeft.size() <= output.size() / 2);
|
||||
CHECK(inputRight.size() <= output.size() / 2);
|
||||
|
||||
auto* lIn = inputLeft.begin();
|
||||
auto* rIn = inputRight.begin();
|
||||
auto* out = output.begin();
|
||||
|
||||
const auto size = std::min(output.size(), std::min(inputLeft.size(), inputRight.size()) * 2);
|
||||
const auto* lastAligned = prevAligned(output.begin() + size - TypeAlignment);
|
||||
|
||||
while (unaligned(out, rIn, lIn) && out < lastAligned)
|
||||
_internals::snippetWrite<float>(out, lIn, rIn);
|
||||
|
||||
while (out < lastAligned) {
|
||||
const auto lInRegister = _mm_load_ps(lIn);
|
||||
const auto rInRegister = _mm_load_ps(rIn);
|
||||
|
||||
const auto outRegister1 = _mm_unpacklo_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(out, outRegister1);
|
||||
out += TypeAlignment;
|
||||
|
||||
const auto outRegister2 = _mm_unpackhi_ps(lInRegister, rInRegister);
|
||||
_mm_store_ps(out, outRegister2);
|
||||
out += TypeAlignment;
|
||||
|
||||
lIn += TypeAlignment;
|
||||
rIn += TypeAlignment;
|
||||
}
|
||||
|
||||
while (out < output.end() - 1)
|
||||
_internals::snippetWrite<float>(out, lIn, rIn);
|
||||
}
|
||||
constexpr uintptr_t TypeAlignment = 4;
|
||||
|
||||
template <>
|
||||
void sfz::fill<float, true>(absl::Span<float> output, float value) noexcept
|
||||
|
|
|
|||
|
|
@ -122,7 +122,8 @@ TEST_CASE("[Helpers] Interleaved read")
|
|||
std::array<float, 16> expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 8> leftOutput;
|
||||
std::array<float, 8> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 16> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -139,7 +140,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end")
|
|||
std::array<float, 20> expected { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 10> leftOutput;
|
||||
std::array<float, 10> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 20> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -156,7 +158,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end")
|
|||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 3> leftOutput;
|
||||
std::array<float, 3> rightOutput;
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 6> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -173,7 +176,8 @@ TEST_CASE("[Helpers] Interleaved read -- SIMD")
|
|||
std::array<float, 16> expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 8> leftOutput;
|
||||
std::array<float, 8> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 16> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -190,7 +194,8 @@ TEST_CASE("[Helpers] Interleaved read unaligned end -- SIMD")
|
|||
std::array<float, 20> expected = { 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 10> leftOutput;
|
||||
std::array<float, 10> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 20> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -207,7 +212,8 @@ TEST_CASE("[Helpers] Small interleaved read unaligned end -- SIMD")
|
|||
std::array<float, 6> expected { 0.0f, 1.0f, 2.0f, 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 3> leftOutput;
|
||||
std::array<float, 3> rightOutput;
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutput), absl::MakeSpan(rightOutput));
|
||||
std::array<float, 6> real;
|
||||
|
||||
auto realIdx = 0;
|
||||
|
|
@ -226,8 +232,10 @@ TEST_CASE("[Helpers] Interleaved read SIMD vs Scalar")
|
|||
std::array<float, medBufferSize> leftOutputSIMD;
|
||||
std::array<float, medBufferSize> rightOutputSIMD;
|
||||
std::iota(input.begin(), input.end(), 0.0f);
|
||||
sfz::readInterleaved<float, false>(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar));
|
||||
sfz::readInterleaved<float, true>(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, false);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutputScalar), absl::MakeSpan(rightOutputScalar));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::readInterleaved, true);
|
||||
sfz::readInterleaved(input, absl::MakeSpan(leftOutputSIMD), absl::MakeSpan(rightOutputSIMD));
|
||||
REQUIRE(leftOutputScalar == leftOutputSIMD);
|
||||
REQUIRE(rightOutputScalar == rightOutputSIMD);
|
||||
}
|
||||
|
|
@ -247,7 +255,8 @@ TEST_CASE("[Helpers] Interleaved write")
|
|||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 16> output;
|
||||
std::array<float, 16> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f };
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -257,7 +266,8 @@ TEST_CASE("[Helpers] Interleaved write unaligned end")
|
|||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 20> output;
|
||||
std::array<float, 20> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f };
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +277,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end")
|
|||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +297,8 @@ TEST_CASE("[Helpers] Interleaved write -- SIMD")
|
|||
std::array<float, 8> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f };
|
||||
std::array<float, 16> output;
|
||||
std::array<float, 16> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f };
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -296,7 +308,7 @@ TEST_CASE("[Helpers] Interleaved write unaligned end -- SIMD")
|
|||
std::array<float, 10> rightInput { 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f };
|
||||
std::array<float, 20> output;
|
||||
std::array<float, 20> expected = { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f, 3.0f, 13.0f, 4.0f, 14.0f, 5.0f, 15.0f, 6.0f, 16.0f, 7.0f, 17.0f, 8.0f, 18.0f, 9.0f, 19.0f };
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +318,8 @@ TEST_CASE("[Helpers] Small interleaved write unaligned end -- SIMD")
|
|||
std::array<float, 3> rightInput { 10.0f, 11.0f, 12.0f };
|
||||
std::array<float, 6> output;
|
||||
std::array<float, 6> expected { 0.0f, 10.0f, 1.0f, 11.0f, 2.0f, 12.0f };
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(output));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(output));
|
||||
REQUIRE(output == expected);
|
||||
}
|
||||
|
||||
|
|
@ -318,8 +331,10 @@ TEST_CASE("[Helpers] Interleaved write SIMD vs Scalar")
|
|||
std::array<float, medBufferSize * 2> outputSIMD;
|
||||
std::iota(leftInput.begin(), leftInput.end(), 0.0f);
|
||||
std::iota(rightInput.begin(), rightInput.end(), static_cast<float>(medBufferSize));
|
||||
sfz::writeInterleaved<float, false>(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
||||
sfz::writeInterleaved<float, true>(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, false);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputScalar));
|
||||
sfz::setSIMDOpStatus(sfz::SIMDOps::writeInterleaved, true);
|
||||
sfz::writeInterleaved(leftInput, rightInput, absl::MakeSpan(outputSIMD));
|
||||
REQUIRE(outputScalar == outputSIMD);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue