Files
UnrealEngineUWP/Engine/Source/Runtime/SignalProcessing/Private/FFTAlgorithm.cpp
peter knepley 5d9de202ba Optional thread safety locks for modular features. Ensure when doing unsafe calls into modular feature enumeration functions.
Use thread safety locks when finding latency marker modular features from rhi thread

#rb Mike.Fricker

#ROBOMERGE-AUTHOR: peter.knepley
#ROBOMERGE-SOURCE: CL 19015311 via CL 19015708 via CL 19015763 via CL 19015857 via CL 19016025 via CL 19031920
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v917-18934589)

[CL 19032149 by peter knepley in ue5-main branch]
2022-02-17 03:41:20 -05:00

163 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "DSP/FFTAlgorithm.h"
#include "SignalProcessingModule.h"
#include "CoreMinimal.h"
#include "Features/IModularFeature.h"
#include "Features/IModularFeatures.h"
namespace Audio
{
// Return factories which support settings and factory name.
static const TArray<IFFTAlgorithmFactory*> GetPrioritizedSupportingFactories(const FFFTSettings& InSettings, const FName& InAlgorithmFactoryName)
{
// Get all IFFTAlgorithm factories.
IModularFeatures::Get().LockModularFeatureList();
TArray<IFFTAlgorithmFactory*> Factories = IModularFeatures::Get().GetModularFeatureImplementations<IFFTAlgorithmFactory>(IFFTAlgorithmFactory::GetModularFeatureName());
IModularFeatures::Get().UnlockModularFeatureList();
// Remove null factories
Factories = Factories.FilterByPredicate([InAlgorithmFactoryName](const IFFTAlgorithmFactory* Factory)
{
return (nullptr != Factory);
});
if (0 == Factories.Num())
{
UE_LOG(LogSignalProcessing, Warning, TEXT("No registered IFFTAlgorithmFactories exist."));
return Factories;
}
if (FFFTFactory::AnyAlgorithmFactory != InAlgorithmFactoryName)
{
// Filter factories if one has been specified.
Factories = Factories.FilterByPredicate([InAlgorithmFactoryName](const IFFTAlgorithmFactory* Factory)
{
return (InAlgorithmFactoryName == Factory->GetFactoryName());
});
if (0 == Factories.Num())
{
UE_LOG(LogSignalProcessing, Warning, TEXT("No IFFTAlgorithmFactories named \"%s\" found."), *InAlgorithmFactoryName.ToString());
return Factories;
}
}
if (!InSettings.bEnableHardwareAcceleration)
{
// Remove factories with hardware acceleration if it has been disabled.
Factories = Factories.FilterByPredicate([InAlgorithmFactoryName](const IFFTAlgorithmFactory* Factory)
{
return !Factory->IsHardwareAccelerated();
});
}
if (!InSettings.bArrays128BitAligned)
{
// Remove factories requiring aligned input/output arrays if it has been disabled.
Factories = Factories.FilterByPredicate([InAlgorithmFactoryName](const IFFTAlgorithmFactory* Factory)
{
return !Factory->Expects128BitAlignedArrays();
});
}
// Filter by whether factory supports settings.
Factories = Factories.FilterByPredicate([InSettings](const IFFTAlgorithmFactory* Factory)
{
return Factory->AreFFTSettingsSupported(InSettings);
});
// We have two software versions, but should prefer the vectorized version
// over the non-vectorized version.
static const TArray<FName> InternalFFTFActoryPriority = {
FName(TEXT("FVectorFFTFactory")),
FName(TEXT("OriginalFFT_Deprecated"))
};
// Sort factories by preference.
Factories.Sort([](const IFFTAlgorithmFactory& InFactoryA, const IFFTAlgorithmFactory& InFactoryB)
{
// If InFactoryA has hardware acceleration and InFactoryB does not, then InFactoryA goes earlier.
if (InFactoryA.IsHardwareAccelerated() && !InFactoryB.IsHardwareAccelerated())
{
return true;
}
// If InFactoryA uses aligned arrays and InFactoryB does not, then InFactoryA goes earlier.
if (InFactoryA.Expects128BitAlignedArrays() && !InFactoryB.Expects128BitAlignedArrays())
{
return true;
}
// Check internal priority of software implementations.
int32 PriorityIndexA = InternalFFTFActoryPriority.Find(InFactoryA.GetFactoryName());
int32 PriorityIndexB = InternalFFTFActoryPriority.Find(InFactoryB.GetFactoryName());
if ((PriorityIndexA != INDEX_NONE) && (PriorityIndexB != INDEX_NONE))
{
return PriorityIndexA < PriorityIndexB;
}
// InFactoryA does not need to be placed before InFactoryB
return false;
});
return Factories;
}
/** virtual destructor for inheritance. */
IFFTAlgorithm::~IFFTAlgorithm()
{
}
/** Name of modular feature for FFT factory. */
const FName IFFTAlgorithmFactory::GetModularFeatureName()
{
static const FName ModularFeatureName = FName(TEXT("AudioFFTAlgorithmFactory"));
return ModularFeatureName;
}
/** This denotes that no specific IFFTAlgorithmFactory is desired. */
const FName FFFTFactory::AnyAlgorithmFactory = FName(TEXT("AnyAlgorithmFactory"));
/** NewFFTAlgorithm
*
* Creates and returns a new FFTAlgorithm.
*
* @param InSettings - The settings used to create the FFT algorithm.
* @param InAlgorithmFactoryName - If not equal to FFFTFactory::AnyAlgorithmFactory, will only uses FFT algorithm facotry if IFFTAlgorithmFactory::GetFactoryName() equals InAlgorithmFactoryName.
* @return A TUniquePtr<IFFTAlgorithm> to the created FFT. This pointer can be invalid if an error occured or the fft algorithm could not be created.
*/
TUniquePtr<IFFTAlgorithm> FFFTFactory::NewFFTAlgorithm(const FFFTSettings& InSettings, const FName& InAlgorithmFactoryName)
{
TArray<IFFTAlgorithmFactory*> Factories = GetPrioritizedSupportingFactories(InSettings, InAlgorithmFactoryName);
// Find first algorithm which creates the an algorithm from the input settings.
for (IFFTAlgorithmFactory* Factory : Factories)
{
TUniquePtr<IFFTAlgorithm> FFTAlgorithm = Factory->NewFFTAlgorithm(InSettings);
if (!FFTAlgorithm.IsValid())
{
UE_LOG(LogSignalProcessing, Warning, TEXT("IFFTAlgorithmFactory \"%s\" failed to create IFFTAlgorithm despite supporting FFT Settings."));
}
else
{
return FFTAlgorithm;
}
}
UE_LOG(LogSignalProcessing, Warning, TEXT("No IFFTAlgorithmFactories can create IFFTAlgorithm for given settings."));
return TUniquePtr<IFFTAlgorithm>();
}
bool FFFTFactory::AreFFTSettingsSupported(const FFFTSettings& InSettings, const FName& InAlgorithmFactoryName)
{
TArray<IFFTAlgorithmFactory*> Factories = GetPrioritizedSupportingFactories(InSettings, InAlgorithmFactoryName);
return Factories.Num() > 0;
}
}