2022-05-23 18:41:30 +00:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "LyraSettingsLocal.h"
# include "Sound/SoundClass.h"
# include "AudioDeviceManager.h"
# include "AudioDevice.h"
# include "LyraLogChannels.h"
# include "AudioMixerBlueprintLibrary.h"
# include "CommonInputBaseTypes.h"
# include "CommonInputSubsystem.h"
# include "Player/LyraLocalPlayer.h"
# include "PlayerMappableInputConfig.h"
# include "EnhancedInputSubsystems.h"
# include "CommonInputBaseTypes.h"
# include "NativeGameplayTags.h"
# include "ICommonUIModule.h"
# include "CommonUISettings.h"
# include "Widgets/Layout/SSafeZone.h"
# include "ProfilingDebugging/CsvProfiler.h"
# include "Performance/LyraPerformanceSettings.h"
# include "DeviceProfiles/DeviceProfileManager.h"
# include "DeviceProfiles/DeviceProfile.h"
# include "HAL/PlatformFramePacer.h"
# include "Development/LyraPlatformEmulationSettings.h"
# include "SoundControlBus.h"
# include "AudioModulationStatics.h"
# include "Audio/LyraAudioSettings.h"
# include "Audio/LyraAudioMixEffectsSubsystem.h"
UE_DEFINE_GAMEPLAY_TAG_STATIC ( TAG_Platform_Trait_BinauralSettingControlledByOS , " Platform.Trait.BinauralSettingControlledByOS " ) ;
//////////////////////////////////////////////////////////////////////
# if WITH_EDITOR
static TAutoConsoleVariable < bool > CVarApplyFrameRateSettingsInPIE ( TEXT ( " Lyra.Settings.ApplyFrameRateSettingsInPIE " ) ,
false ,
TEXT ( " Should we apply frame rate settings in PIE? " ) ,
ECVF_Default ) ;
static TAutoConsoleVariable < bool > CVarApplyFrontEndPerformanceOptionsInPIE ( TEXT ( " Lyra.Settings.ApplyFrontEndPerformanceOptionsInPIE " ) ,
false ,
TEXT ( " Do we apply front-end specific performance options in PIE? " ) ,
ECVF_Default ) ;
static TAutoConsoleVariable < bool > CVarApplyDeviceProfilesInPIE ( TEXT ( " Lyra.Settings.ApplyDeviceProfilesInPIE " ) ,
false ,
TEXT ( " Should we apply experience/platform emulated device profiles in PIE? " ) ,
ECVF_Default ) ;
# endif
//////////////////////////////////////////////////////////////////////
// Console frame pacing
static TAutoConsoleVariable < int32 > CVarDeviceProfileDrivenTargetFps (
TEXT ( " Lyra.DeviceProfile.Console.TargetFPS " ) ,
- 1 ,
TEXT ( " Target FPS when being driven by device profile " ) ,
ECVF_Default | ECVF_Preview ) ;
static TAutoConsoleVariable < int32 > CVarDeviceProfileDrivenFrameSyncType (
TEXT ( " Lyra.DeviceProfile.Console.FrameSyncType " ) ,
- 1 ,
TEXT ( " Sync type when being driven by device profile. Corresponds to r.GTSyncType " ) ,
ECVF_Default | ECVF_Preview ) ;
//////////////////////////////////////////////////////////////////////
// Mobile frame pacing
static TAutoConsoleVariable < int32 > CVarDeviceProfileDrivenMobileDefaultFrameRate (
TEXT ( " Lyra.DeviceProfile.Mobile.DefaultFrameRate " ) ,
30 ,
TEXT ( " Default FPS when being driven by device profile " ) ,
ECVF_Default | ECVF_Preview ) ;
static TAutoConsoleVariable < int32 > CVarDeviceProfileDrivenMobileMaxFrameRate (
TEXT ( " Lyra.DeviceProfile.Mobile.MaxFrameRate " ) ,
30 ,
TEXT ( " Max FPS when being driven by device profile " ) ,
ECVF_Default | ECVF_Preview ) ;
//////////////////////////////////////////////////////////////////////
static TAutoConsoleVariable < FString > CVarMobileQualityLimits (
TEXT ( " Lyra.DeviceProfile.Mobile.OverallQualityLimits " ) ,
TEXT ( " " ) ,
TEXT ( " List of limits on resolution quality of the form \" FPS:MaxQuality,FPS2:MaxQuality2,... \" , kicking in when FPS is at or above the threshold " ) ,
ECVF_Default | ECVF_Preview ) ;
static TAutoConsoleVariable < FString > CVarMobileResolutionQualityLimits (
TEXT ( " Lyra.DeviceProfile.Mobile.ResolutionQualityLimits " ) ,
TEXT ( " " ) ,
TEXT ( " List of limits on resolution quality of the form \" FPS:MaxResQuality,FPS2:MaxResQuality2,... \" , kicking in when FPS is at or above the threshold " ) ,
ECVF_Default | ECVF_Preview ) ;
static TAutoConsoleVariable < FString > CVarMobileResolutionQualityRecommendation (
TEXT ( " Lyra.DeviceProfile.Mobile.ResolutionQualityRecommendation " ) ,
TEXT ( " 0:75 " ) ,
TEXT ( " List of limits on resolution quality of the form \" FPS:Recommendation,FPS2:Recommendation2,... \" , kicking in when FPS is at or above the threshold " ) ,
ECVF_Default | ECVF_Preview ) ;
//////////////////////////////////////////////////////////////////////
FLyraScalabilitySnapshot : : FLyraScalabilitySnapshot ( )
{
static_assert ( sizeof ( Scalability : : FQualityLevels ) = = 88 , " This function may need to be updated to account for new members " ) ;
Qualities . ResolutionQuality = - 1.0f ;
Qualities . ViewDistanceQuality = - 1 ;
Qualities . AntiAliasingQuality = - 1 ;
Qualities . ShadowQuality = - 1 ;
Qualities . GlobalIlluminationQuality = - 1 ;
Qualities . ReflectionQuality = - 1 ;
Qualities . PostProcessQuality = - 1 ;
Qualities . TextureQuality = - 1 ;
Qualities . EffectsQuality = - 1 ;
Qualities . FoliageQuality = - 1 ;
Qualities . ShadingQuality = - 1 ;
}
//////////////////////////////////////////////////////////////////////
template < typename T >
struct TMobileQualityWrapper
{
private :
T DefaultValue ;
TAutoConsoleVariable < FString > & WatchedVar ;
FString LastSeenCVarString ;
struct FLimitPair
{
int32 Limit = 0 ;
T Value = T ( 0 ) ;
} ;
TArray < FLimitPair > Thresholds ;
public :
TMobileQualityWrapper ( T InDefaultValue , TAutoConsoleVariable < FString > & InWatchedVar )
: DefaultValue ( InDefaultValue )
, WatchedVar ( InWatchedVar )
{
}
T Query ( int32 TestValue )
{
UpdateCache ( ) ;
for ( const FLimitPair & Pair : Thresholds )
{
if ( TestValue > = Pair . Limit )
{
return Pair . Value ;
}
}
return DefaultValue ;
}
// Returns the first threshold value or INDEX_NONE if there aren't any
int32 GetFirstThreshold ( )
{
UpdateCache ( ) ;
return ( Thresholds . Num ( ) > 0 ) ? Thresholds [ 0 ] . Limit : INDEX_NONE ;
}
// Returns the lowest value of all the pairs or DefaultIfNoPairs if there are no pairs
T GetLowestValue ( T DefaultIfNoPairs )
{
UpdateCache ( ) ;
T Result = DefaultIfNoPairs ;
bool bFirstValue = true ;
for ( const FLimitPair & Pair : Thresholds )
{
if ( bFirstValue )
{
Result = Pair . Value ;
bFirstValue = false ;
}
else
{
Result = FMath : : Min ( Result , Pair . Value ) ;
}
}
return Result ;
}
private :
void UpdateCache ( )
{
const FString CurrentValue = WatchedVar . GetValueOnGameThread ( ) ;
if ( ! CurrentValue . Equals ( LastSeenCVarString , ESearchCase : : CaseSensitive ) )
{
LastSeenCVarString = CurrentValue ;
Thresholds . Reset ( ) ;
// Parse the thresholds
int32 ScanIndex = 0 ;
while ( ScanIndex < LastSeenCVarString . Len ( ) )
{
const int32 ColonIndex = LastSeenCVarString . Find ( TEXT ( " : " ) , ESearchCase : : CaseSensitive , ESearchDir : : FromStart , ScanIndex ) ;
if ( ColonIndex > 0 )
{
const int32 CommaIndex = LastSeenCVarString . Find ( TEXT ( " , " ) , ESearchCase : : CaseSensitive , ESearchDir : : FromStart , ColonIndex ) ;
const int32 EndOfPairIndex = ( CommaIndex ! = INDEX_NONE ) ? CommaIndex : LastSeenCVarString . Len ( ) ;
FLimitPair Pair ;
LexFromString ( Pair . Limit , * LastSeenCVarString . Mid ( ScanIndex , ColonIndex - ScanIndex ) ) ;
LexFromString ( Pair . Value , * LastSeenCVarString . Mid ( ColonIndex + 1 , EndOfPairIndex - ColonIndex - 1 ) ) ;
Thresholds . Add ( Pair ) ;
ScanIndex = EndOfPairIndex + 1 ;
}
else
{
UE_LOG ( LogConsoleResponse , Error , TEXT ( " Malformed value for '%s'='%s', expecting a ':' " ) ,
* IConsoleManager : : Get ( ) . FindConsoleObjectName ( WatchedVar . AsVariable ( ) ) ,
* LastSeenCVarString ) ;
Thresholds . Reset ( ) ;
break ;
}
}
// Sort the pairs
Thresholds . Sort ( [ ] ( const FLimitPair A , const FLimitPair B ) { return A . Limit < B . Limit ; } ) ;
}
}
} ;
namespace LyraSettingsHelpers
{
bool HasPlatformTrait ( FGameplayTag Tag )
{
return ICommonUIModule : : GetSettings ( ) . GetPlatformTraits ( ) . HasTag ( Tag ) ;
}
// Returns the max level from the integer scalability settings (ignores ResolutionQuality)
int32 GetHighestLevelOfAnyScalabilityChannel ( const Scalability : : FQualityLevels & ScalabilityQuality )
{
static_assert ( sizeof ( Scalability : : FQualityLevels ) = = 88 , " This function may need to be updated to account for new members " ) ;
int32 MaxScalability = ScalabilityQuality . ViewDistanceQuality ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . AntiAliasingQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . ShadowQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . GlobalIlluminationQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . ReflectionQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . PostProcessQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . TextureQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . EffectsQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . FoliageQuality ) ;
MaxScalability = FMath : : Max ( MaxScalability , ScalabilityQuality . ShadingQuality ) ;
return ( MaxScalability > = 0 ) ? MaxScalability : - 1 ;
}
void FillScalabilitySettingsFromDeviceProfile ( FLyraScalabilitySnapshot & Mode , const FString & Suffix = FString ( ) )
{
static_assert ( sizeof ( Scalability : : FQualityLevels ) = = 88 , " This function may need to be updated to account for new members " ) ;
// Default out before filling so we can correctly mark non-overridden scalability values.
// It's technically possible to swap device profile when testing so safest to clear and refill
Mode = FLyraScalabilitySnapshot ( ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.ResolutionQuality%s " ) , * Suffix ) , Mode . Qualities . ResolutionQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.ViewDistanceQuality%s " ) , * Suffix ) , Mode . Qualities . ViewDistanceQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.AntiAliasingQuality%s " ) , * Suffix ) , Mode . Qualities . AntiAliasingQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.ShadowQuality%s " ) , * Suffix ) , Mode . Qualities . ShadowQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.GlobalIlluminationQuality%s " ) , * Suffix ) , Mode . Qualities . GlobalIlluminationQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.ReflectionQuality%s " ) , * Suffix ) , Mode . Qualities . ReflectionQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.PostProcessQuality%s " ) , * Suffix ) , Mode . Qualities . PostProcessQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.TextureQuality%s " ) , * Suffix ) , Mode . Qualities . TextureQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.EffectsQuality%s " ) , * Suffix ) , Mode . Qualities . EffectsQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.FoliageQuality%s " ) , * Suffix ) , Mode . Qualities . FoliageQuality ) ;
Mode . bHasOverrides | = UDeviceProfileManager : : GetScalabilityCVar ( FString : : Printf ( TEXT ( " sg.ShadingQuality%s " ) , * Suffix ) , Mode . Qualities . ShadingQuality ) ;
}
TMobileQualityWrapper < int32 > OverallQualityLimits ( - 1 , CVarMobileQualityLimits ) ;
TMobileQualityWrapper < float > ResolutionQualityLimits ( 100.0f , CVarMobileResolutionQualityLimits ) ;
TMobileQualityWrapper < float > ResolutionQualityRecommendations ( 75.0f , CVarMobileResolutionQualityRecommendation ) ;
int32 GetApplicableOverallQualityLimit ( int32 FrameRate )
{
return OverallQualityLimits . Query ( FrameRate ) ;
}
float GetApplicableResolutionQualityLimit ( int32 FrameRate )
{
return ResolutionQualityLimits . Query ( FrameRate ) ;
}
float GetApplicableResolutionQualityRecommendation ( int32 FrameRate )
{
return ResolutionQualityRecommendations . Query ( FrameRate ) ;
}
int32 ConstrainFrameRateToBeCompatibleWithOverallQuality ( int32 FrameRate , int32 OverallQuality )
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
const TArray < int32 > & PossibleRates = PlatformSettings - > MobileFrameRateLimits ;
// Choose the closest frame rate (without going over) to the user preferred one that is supported and compatible with the desired overall quality
int32 LimitIndex = PossibleRates . FindLastByPredicate ( [ = ] ( const int32 & TestRate )
{
const bool bAtOrBelowDesiredRate = ( TestRate < = FrameRate ) ;
const int32 LimitQuality = GetApplicableResolutionQualityLimit ( TestRate ) ;
const bool bQualityDoesntExceedLimit = ( LimitQuality < 0 ) | | ( OverallQuality < = LimitQuality ) ;
const bool bIsSupported = ULyraSettingsLocal : : IsSupportedMobileFramePace ( TestRate ) ;
return bAtOrBelowDesiredRate & & bQualityDoesntExceedLimit & & bIsSupported ;
} ) ;
return PossibleRates . IsValidIndex ( LimitIndex ) ? PossibleRates [ LimitIndex ] : ULyraSettingsLocal : : GetDefaultMobileFrameRate ( ) ;
}
// Returns the first frame rate at which overall quality is restricted/limited by the current device profile
int32 GetFirstFrameRateWithQualityLimit ( )
{
return OverallQualityLimits . GetFirstThreshold ( ) ;
}
// Returns the lowest quality at which there's a limit on the overall frame rate (or -1 if there is no limit)
int32 GetLowestQualityWithFrameRateLimit ( )
{
return OverallQualityLimits . GetLowestValue ( - 1 ) ;
}
}
//////////////////////////////////////////////////////////////////////
ULyraSettingsLocal : : ULyraSettingsLocal ( )
{
if ( ! HasAnyFlags ( RF_ClassDefaultObject ) & & FSlateApplication : : IsInitialized ( ) )
{
OnApplicationActivationStateChangedHandle = FSlateApplication : : Get ( ) . OnApplicationActivationStateChanged ( ) . AddUObject ( this , & ThisClass : : OnAppActivationStateChanged ) ;
}
SetToDefaults ( ) ;
}
void ULyraSettingsLocal : : SetToDefaults ( )
{
Super : : SetToDefaults ( ) ;
bUseHeadphoneMode = false ;
bUseHDRAudioMode = false ;
bSoundControlBusMixLoaded = false ;
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
UserChosenDeviceProfileSuffix = PlatformSettings - > DefaultDeviceProfileSuffix ;
DesiredUserChosenDeviceProfileSuffix = UserChosenDeviceProfileSuffix ;
FrameRateLimit_InMenu = 144.0f ;
FrameRateLimit_WhenBackgrounded = 30.0f ;
FrameRateLimit_OnBattery = 60.0f ;
MobileFrameRateLimit = GetDefaultMobileFrameRate ( ) ;
DesiredMobileFrameRateLimit = MobileFrameRateLimit ;
}
void ULyraSettingsLocal : : LoadSettings ( bool bForceReload )
{
Super : : LoadSettings ( bForceReload ) ;
// Console platforms use rhi.SyncInterval to limit framerate
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : ConsoleStyle )
{
FrameRateLimit = 0.0f ;
}
// Enable HRTF if needed
bDesiredHeadphoneMode = bUseHeadphoneMode ;
SetHeadphoneModeEnabled ( bUseHeadphoneMode ) ;
DesiredUserChosenDeviceProfileSuffix = UserChosenDeviceProfileSuffix ;
LyraSettingsHelpers : : FillScalabilitySettingsFromDeviceProfile ( DeviceDefaultScalabilitySettings ) ;
DesiredMobileFrameRateLimit = MobileFrameRateLimit ;
ClampMobileQuality ( ) ;
PerfStatSettingsChangedEvent . Broadcast ( ) ;
}
void ULyraSettingsLocal : : ResetToCurrentSettings ( )
{
Super : : ResetToCurrentSettings ( ) ;
bDesiredHeadphoneMode = bUseHeadphoneMode ;
UserChosenDeviceProfileSuffix = DesiredUserChosenDeviceProfileSuffix ;
MobileFrameRateLimit = DesiredMobileFrameRateLimit ;
}
void ULyraSettingsLocal : : BeginDestroy ( )
{
if ( FSlateApplication : : IsInitialized ( ) )
{
FSlateApplication : : Get ( ) . OnApplicationActivationStateChanged ( ) . Remove ( OnApplicationActivationStateChangedHandle ) ;
}
Super : : BeginDestroy ( ) ;
}
ULyraSettingsLocal * ULyraSettingsLocal : : Get ( )
{
return GEngine ? CastChecked < ULyraSettingsLocal > ( GEngine - > GetGameUserSettings ( ) ) : nullptr ;
}
void ULyraSettingsLocal : : ConfirmVideoMode ( )
{
Super : : ConfirmVideoMode ( ) ;
SetMobileFPSMode ( DesiredMobileFrameRateLimit ) ;
}
// Combines two limits, always taking the minimum of the two (with special handling for values of <= 0 meaning unlimited)
float CombineFrameRateLimits ( float Limit1 , float Limit2 )
{
if ( Limit1 < = 0.0f )
{
return Limit2 ;
}
else if ( Limit2 < = 0.0f )
{
return Limit1 ;
}
else
{
return FMath : : Min ( Limit1 , Limit2 ) ;
}
}
float ULyraSettingsLocal : : GetEffectiveFrameRateLimit ( )
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
# if WITH_EDITOR
if ( GIsEditor & & ! CVarApplyFrameRateSettingsInPIE . GetValueOnGameThread ( ) )
{
return Super : : GetEffectiveFrameRateLimit ( ) ;
}
# endif
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : ConsoleStyle )
{
return 0.0f ;
}
float EffectiveFrameRateLimit = Super : : GetEffectiveFrameRateLimit ( ) ;
if ( ShouldUseFrontendPerformanceSettings ( ) )
{
EffectiveFrameRateLimit = CombineFrameRateLimits ( EffectiveFrameRateLimit , FrameRateLimit_InMenu ) ;
}
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : DesktopStyle )
{
if ( FPlatformMisc : : IsRunningOnBattery ( ) )
{
EffectiveFrameRateLimit = CombineFrameRateLimits ( EffectiveFrameRateLimit , FrameRateLimit_OnBattery ) ;
}
if ( FSlateApplication : : IsInitialized ( ) & & ! FSlateApplication : : Get ( ) . IsActive ( ) )
{
EffectiveFrameRateLimit = CombineFrameRateLimits ( EffectiveFrameRateLimit , FrameRateLimit_WhenBackgrounded ) ;
}
}
return EffectiveFrameRateLimit ;
}
int32 ULyraSettingsLocal : : GetHighestLevelOfAnyScalabilityChannel ( ) const
{
return LyraSettingsHelpers : : GetHighestLevelOfAnyScalabilityChannel ( ScalabilityQuality ) ;
}
void ULyraSettingsLocal : : OverrideQualityLevelsToScalabilityMode ( const FLyraScalabilitySnapshot & InMode , Scalability : : FQualityLevels & InOutLevels )
{
static_assert ( sizeof ( Scalability : : FQualityLevels ) = = 88 , " This function may need to be updated to account for new members " ) ;
// Overrides any valid (non-negative) settings
InOutLevels . ResolutionQuality = ( InMode . Qualities . ResolutionQuality > = 0.f ) ? InMode . Qualities . ResolutionQuality : InOutLevels . ResolutionQuality ;
InOutLevels . ViewDistanceQuality = ( InMode . Qualities . ViewDistanceQuality > = 0 ) ? InMode . Qualities . ViewDistanceQuality : InOutLevels . ViewDistanceQuality ;
InOutLevels . AntiAliasingQuality = ( InMode . Qualities . AntiAliasingQuality > = 0 ) ? InMode . Qualities . AntiAliasingQuality : InOutLevels . AntiAliasingQuality ;
InOutLevels . ShadowQuality = ( InMode . Qualities . ShadowQuality > = 0 ) ? InMode . Qualities . ShadowQuality : InOutLevels . ShadowQuality ;
InOutLevels . GlobalIlluminationQuality = ( InMode . Qualities . GlobalIlluminationQuality > = 0 ) ? InMode . Qualities . GlobalIlluminationQuality : InOutLevels . GlobalIlluminationQuality ;
InOutLevels . ReflectionQuality = ( InMode . Qualities . ReflectionQuality > = 0 ) ? InMode . Qualities . ReflectionQuality : InOutLevels . ReflectionQuality ;
InOutLevels . PostProcessQuality = ( InMode . Qualities . PostProcessQuality > = 0 ) ? InMode . Qualities . PostProcessQuality : InOutLevels . PostProcessQuality ;
InOutLevels . TextureQuality = ( InMode . Qualities . TextureQuality > = 0 ) ? InMode . Qualities . TextureQuality : InOutLevels . TextureQuality ;
InOutLevels . EffectsQuality = ( InMode . Qualities . EffectsQuality > = 0 ) ? InMode . Qualities . EffectsQuality : InOutLevels . EffectsQuality ;
InOutLevels . FoliageQuality = ( InMode . Qualities . FoliageQuality > = 0 ) ? InMode . Qualities . FoliageQuality : InOutLevels . FoliageQuality ;
InOutLevels . ShadingQuality = ( InMode . Qualities . ShadingQuality > = 0 ) ? InMode . Qualities . ShadingQuality : InOutLevels . ShadingQuality ;
}
void ULyraSettingsLocal : : ClampQualityLevelsToDeviceProfile ( const Scalability : : FQualityLevels & ClampLevels , Scalability : : FQualityLevels & InOutLevels )
{
static_assert ( sizeof ( Scalability : : FQualityLevels ) = = 88 , " This function may need to be updated to account for new members " ) ;
// Clamps any valid (non-negative) settings
InOutLevels . ResolutionQuality = ( ClampLevels . ResolutionQuality > = 0.f ) ? FMath : : Min ( ClampLevels . ResolutionQuality , InOutLevels . ResolutionQuality ) : InOutLevels . ResolutionQuality ;
InOutLevels . ViewDistanceQuality = ( ClampLevels . ViewDistanceQuality > = 0 ) ? FMath : : Min ( ClampLevels . ViewDistanceQuality , InOutLevels . ViewDistanceQuality ) : InOutLevels . ViewDistanceQuality ;
InOutLevels . AntiAliasingQuality = ( ClampLevels . AntiAliasingQuality > = 0 ) ? FMath : : Min ( ClampLevels . AntiAliasingQuality , InOutLevels . AntiAliasingQuality ) : InOutLevels . AntiAliasingQuality ;
InOutLevels . ShadowQuality = ( ClampLevels . ShadowQuality > = 0 ) ? FMath : : Min ( ClampLevels . ShadowQuality , InOutLevels . ShadowQuality ) : InOutLevels . ShadowQuality ;
InOutLevels . GlobalIlluminationQuality = ( ClampLevels . GlobalIlluminationQuality > = 0 ) ? FMath : : Min ( ClampLevels . GlobalIlluminationQuality , InOutLevels . GlobalIlluminationQuality ) : InOutLevels . GlobalIlluminationQuality ;
InOutLevels . ReflectionQuality = ( ClampLevels . ReflectionQuality > = 0 ) ? FMath : : Min ( ClampLevels . ReflectionQuality , InOutLevels . ReflectionQuality ) : InOutLevels . ReflectionQuality ;
InOutLevels . PostProcessQuality = ( ClampLevels . PostProcessQuality > = 0 ) ? FMath : : Min ( ClampLevels . PostProcessQuality , InOutLevels . PostProcessQuality ) : InOutLevels . PostProcessQuality ;
InOutLevels . TextureQuality = ( ClampLevels . TextureQuality > = 0 ) ? FMath : : Min ( ClampLevels . TextureQuality , InOutLevels . TextureQuality ) : InOutLevels . TextureQuality ;
InOutLevels . EffectsQuality = ( ClampLevels . EffectsQuality > = 0 ) ? FMath : : Min ( ClampLevels . EffectsQuality , InOutLevels . EffectsQuality ) : InOutLevels . EffectsQuality ;
InOutLevels . FoliageQuality = ( ClampLevels . FoliageQuality > = 0 ) ? FMath : : Min ( ClampLevels . FoliageQuality , InOutLevels . FoliageQuality ) : InOutLevels . FoliageQuality ;
InOutLevels . ShadingQuality = ( ClampLevels . ShadingQuality > = 0 ) ? FMath : : Min ( ClampLevels . ShadingQuality , InOutLevels . ShadingQuality ) : InOutLevels . ShadingQuality ;
}
void ULyraSettingsLocal : : OnExperienceLoaded ( )
{
ReapplyThingsDueToPossibleDeviceProfileChange ( ) ;
}
void ULyraSettingsLocal : : OnHotfixDeviceProfileApplied ( )
{
ReapplyThingsDueToPossibleDeviceProfileChange ( ) ;
}
void ULyraSettingsLocal : : ReapplyThingsDueToPossibleDeviceProfileChange ( )
{
ApplyNonResolutionSettings ( ) ;
}
void ULyraSettingsLocal : : SetShouldUseFrontendPerformanceSettings ( bool bInFrontEnd )
{
bInFrontEndForPerformancePurposes = bInFrontEnd ;
UpdateEffectiveFrameRateLimit ( ) ;
}
bool ULyraSettingsLocal : : ShouldUseFrontendPerformanceSettings ( ) const
{
# if WITH_EDITOR
if ( GIsEditor & & ! CVarApplyFrontEndPerformanceOptionsInPIE . GetValueOnGameThread ( ) )
{
return false ;
}
# endif
return bInFrontEndForPerformancePurposes ;
}
ELyraStatDisplayMode ULyraSettingsLocal : : GetPerfStatDisplayState ( ELyraDisplayablePerformanceStat Stat ) const
{
if ( const ELyraStatDisplayMode * pMode = DisplayStatList . Find ( Stat ) )
{
return * pMode ;
}
else
{
return ELyraStatDisplayMode : : Hidden ;
}
}
void ULyraSettingsLocal : : SetPerfStatDisplayState ( ELyraDisplayablePerformanceStat Stat , ELyraStatDisplayMode DisplayMode )
{
if ( DisplayMode = = ELyraStatDisplayMode : : Hidden )
{
DisplayStatList . Remove ( Stat ) ;
}
else
{
DisplayStatList . FindOrAdd ( Stat ) = DisplayMode ;
}
PerfStatSettingsChangedEvent . Broadcast ( ) ;
}
float ULyraSettingsLocal : : GetDisplayGamma ( ) const
{
return DisplayGamma ;
}
void ULyraSettingsLocal : : SetDisplayGamma ( float InGamma )
{
DisplayGamma = InGamma ;
ApplyDisplayGamma ( ) ;
}
void ULyraSettingsLocal : : ApplyDisplayGamma ( )
{
if ( GEngine )
{
GEngine - > DisplayGamma = DisplayGamma ;
}
}
float ULyraSettingsLocal : : GetFrameRateLimit_OnBattery ( ) const
{
return FrameRateLimit_OnBattery ;
}
void ULyraSettingsLocal : : SetFrameRateLimit_OnBattery ( float NewLimitFPS )
{
FrameRateLimit_OnBattery = NewLimitFPS ;
UpdateEffectiveFrameRateLimit ( ) ;
}
float ULyraSettingsLocal : : GetFrameRateLimit_InMenu ( ) const
{
return FrameRateLimit_InMenu ;
}
void ULyraSettingsLocal : : SetFrameRateLimit_InMenu ( float NewLimitFPS )
{
FrameRateLimit_InMenu = NewLimitFPS ;
UpdateEffectiveFrameRateLimit ( ) ;
}
float ULyraSettingsLocal : : GetFrameRateLimit_WhenBackgrounded ( ) const
{
return FrameRateLimit_WhenBackgrounded ;
}
void ULyraSettingsLocal : : SetFrameRateLimit_WhenBackgrounded ( float NewLimitFPS )
{
FrameRateLimit_WhenBackgrounded = NewLimitFPS ;
UpdateEffectiveFrameRateLimit ( ) ;
}
float ULyraSettingsLocal : : GetFrameRateLimit_Always ( ) const
{
return GetFrameRateLimit ( ) ;
}
void ULyraSettingsLocal : : SetFrameRateLimit_Always ( float NewLimitFPS )
{
SetFrameRateLimit ( NewLimitFPS ) ;
UpdateEffectiveFrameRateLimit ( ) ;
}
void ULyraSettingsLocal : : UpdateEffectiveFrameRateLimit ( )
{
if ( ! IsRunningDedicatedServer ( ) )
{
SetFrameRateLimitCVar ( GetEffectiveFrameRateLimit ( ) ) ;
}
}
int32 ULyraSettingsLocal : : GetDefaultMobileFrameRate ( )
{
return CVarDeviceProfileDrivenMobileDefaultFrameRate . GetValueOnGameThread ( ) ;
}
int32 ULyraSettingsLocal : : GetMaxMobileFrameRate ( )
{
return CVarDeviceProfileDrivenMobileMaxFrameRate . GetValueOnGameThread ( ) ;
}
bool ULyraSettingsLocal : : IsSupportedMobileFramePace ( int32 TestFPS )
{
const bool bIsDefault = ( TestFPS = = GetDefaultMobileFrameRate ( ) ) ;
const bool bDoesNotExceedLimit = ( TestFPS < = GetMaxMobileFrameRate ( ) ) ;
// Allow all paces in the editor, as we'd only be doing this when simulating another platform
const bool bIsSupportedPace = FPlatformRHIFramePacer : : SupportsFramePace ( TestFPS ) | | GIsEditor ;
return bIsDefault | | ( bDoesNotExceedLimit & & bIsSupportedPace ) ;
}
int32 ULyraSettingsLocal : : GetFirstFrameRateWithQualityLimit ( ) const
{
return LyraSettingsHelpers : : GetFirstFrameRateWithQualityLimit ( ) ;
}
int32 ULyraSettingsLocal : : GetLowestQualityWithFrameRateLimit ( ) const
{
return LyraSettingsHelpers : : GetLowestQualityWithFrameRateLimit ( ) ;
}
void ULyraSettingsLocal : : ResetToMobileDeviceDefaults ( )
{
// Reset frame rate
DesiredMobileFrameRateLimit = GetDefaultMobileFrameRate ( ) ;
MobileFrameRateLimit = DesiredMobileFrameRateLimit ;
// Reset scalability
Scalability : : FQualityLevels DefaultLevels = Scalability : : GetQualityLevels ( ) ;
OverrideQualityLevelsToScalabilityMode ( DeviceDefaultScalabilitySettings , DefaultLevels ) ;
ScalabilityQuality = DefaultLevels ;
// Apply
UpdateGameModeDeviceProfileAndFps ( ) ;
}
int32 ULyraSettingsLocal : : GetMaxSupportedOverallQualityLevel ( ) const
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle ) & & DeviceDefaultScalabilitySettings . bHasOverrides )
{
return LyraSettingsHelpers : : GetHighestLevelOfAnyScalabilityChannel ( DeviceDefaultScalabilitySettings . Qualities ) ;
}
else
{
return 3 ;
}
}
void ULyraSettingsLocal : : SetMobileFPSMode ( int32 NewLimitFPS )
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle )
{
if ( MobileFrameRateLimit ! = NewLimitFPS )
{
MobileFrameRateLimit = NewLimitFPS ;
UpdateGameModeDeviceProfileAndFps ( ) ;
}
DesiredMobileFrameRateLimit = MobileFrameRateLimit ;
}
}
void ULyraSettingsLocal : : SetDesiredMobileFrameRateLimit ( int32 NewLimitFPS )
{
const int32 OldLimitFPS = DesiredMobileFrameRateLimit ;
RemapMobileResolutionQuality ( OldLimitFPS , NewLimitFPS ) ;
DesiredMobileFrameRateLimit = NewLimitFPS ;
ClampMobileFPSQualityLevels ( /*bWriteBack=*/ false ) ;
}
void ULyraSettingsLocal : : ClampMobileFPSQualityLevels ( bool bWriteBack )
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle )
{
const int32 QualityLimit = LyraSettingsHelpers : : GetApplicableOverallQualityLimit ( DesiredMobileFrameRateLimit ) ;
const int32 CurrentQualityLevel = GetHighestLevelOfAnyScalabilityChannel ( ) ;
if ( ( QualityLimit > = 0 ) & & ( CurrentQualityLevel > QualityLimit ) )
{
SetOverallScalabilityLevel ( QualityLimit ) ;
if ( bWriteBack )
{
Scalability : : SetQualityLevels ( ScalabilityQuality ) ;
}
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Mobile FPS clamped overall quality (%d -> %d). " ) , CurrentQualityLevel , QualityLimit ) ;
}
}
}
void ULyraSettingsLocal : : ClampMobileQuality ( )
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle )
{
// Clamp the resultant settings to the device default, it's known viable maximum.
// This is a clamp rather than override to preserve allowed user settings
Scalability : : FQualityLevels CurrentLevels = Scalability : : GetQualityLevels ( ) ;
/** On mobile, disables the 3D Resolution clamp that reverts the setting set by the user on boot.*/
bool bMobileDisableResolutionReset = true ;
if ( bMobileDisableResolutionReset )
{
DeviceDefaultScalabilitySettings . Qualities . ResolutionQuality = CurrentLevels . ResolutionQuality ;
}
ClampQualityLevelsToDeviceProfile ( DeviceDefaultScalabilitySettings . Qualities , /*inout*/ CurrentLevels ) ;
Scalability : : SetQualityLevels ( CurrentLevels ) ;
// Clamp quality levels if required at the current frame rate
ClampMobileFPSQualityLevels ( /*bWriteBack=*/ true ) ;
const int32 MaxMobileFrameRate = GetMaxMobileFrameRate ( ) ;
const int32 DefaultMobileFrameRate = GetDefaultMobileFrameRate ( ) ;
ensureMsgf ( DefaultMobileFrameRate < = MaxMobileFrameRate , TEXT ( " Default mobile frame rate (%d) is higher than the maximum mobile frame rate (%d)! " ) , DefaultMobileFrameRate , MaxMobileFrameRate ) ;
// Choose the closest supported frame rate to the user desired setting without going over the device imposed limit
const TArray < int32 > & PossibleRates = PlatformSettings - > MobileFrameRateLimits ;
const int32 LimitIndex = PossibleRates . FindLastByPredicate ( [ = ] ( const int32 & TestRate ) { return ( TestRate < = DesiredMobileFrameRateLimit ) & & IsSupportedMobileFramePace ( TestRate ) ; } ) ;
const int32 ActualLimitFPS = PossibleRates . IsValidIndex ( LimitIndex ) ? PossibleRates [ LimitIndex ] : GetDefaultMobileFrameRate ( ) ;
ClampMobileResolutionQuality ( ActualLimitFPS ) ;
}
}
void ULyraSettingsLocal : : ClampMobileResolutionQuality ( int32 TargetFPS )
{
// Clamp mobile resolution quality
float MaxMobileResQuality = LyraSettingsHelpers : : GetApplicableResolutionQualityLimit ( TargetFPS ) ;
float CurrentScaleNormalized = 0.0f ;
float CurrentScaleValue = 0.0f ;
float MinScaleValue = 0.0f ;
float MaxScaleValue = 0.0f ;
GetResolutionScaleInformationEx ( CurrentScaleNormalized , CurrentScaleValue , MinScaleValue , MaxScaleValue ) ;
if ( CurrentScaleValue > MaxMobileResQuality )
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " clamping mobile resolution quality max res: %f, %f, %f, %f, %f " ) , CurrentScaleNormalized , CurrentScaleValue , MinScaleValue , MaxScaleValue , MaxMobileResQuality ) ;
SetResolutionScaleValueEx ( MaxMobileResQuality ) ;
}
}
void ULyraSettingsLocal : : RemapMobileResolutionQuality ( int32 FromFPS , int32 ToFPS )
{
// Mobile resolution quality slider is a normalized value that is lerped between min quality, max quality.
// max quality can change depending on FPS mode. This code remaps the quality when FPS mode changes so that the normalized
// value remains the same within the new range.
float CurrentScaleNormalized = 0.0f ;
float CurrentScaleValue = 0.0f ;
float MinScaleValue = 0.0f ;
float MaxScaleValue = 0.0f ;
GetResolutionScaleInformationEx ( CurrentScaleNormalized , CurrentScaleValue , MinScaleValue , MaxScaleValue ) ;
float FromMaxMobileResQuality = LyraSettingsHelpers : : GetApplicableResolutionQualityLimit ( FromFPS ) ;
float ToMaxMobileResQuality = LyraSettingsHelpers : : GetApplicableResolutionQualityLimit ( ToFPS ) ;
float FromMobileScaledNormalizedValue = ( CurrentScaleValue - MinScaleValue ) / ( FromMaxMobileResQuality - MinScaleValue ) ;
float ToResQuality = FMath : : Lerp ( MinScaleValue , ToMaxMobileResQuality , FromMobileScaledNormalizedValue ) ;
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Remap mobile resolution quality %f, %f, (%d,%d) " ) , CurrentScaleValue , ToResQuality , FromFPS , ToFPS ) ;
SetResolutionScaleValueEx ( ToResQuality ) ;
}
FString ULyraSettingsLocal : : GetDesiredDeviceProfileQualitySuffix ( ) const
{
return DesiredUserChosenDeviceProfileSuffix ;
}
void ULyraSettingsLocal : : SetDesiredDeviceProfileQualitySuffix ( const FString & InDesiredSuffix )
{
DesiredUserChosenDeviceProfileSuffix = InDesiredSuffix ;
}
void ULyraSettingsLocal : : SetHeadphoneModeEnabled ( bool bEnabled )
{
if ( CanModifyHeadphoneModeEnabled ( ) )
{
static IConsoleVariable * BinauralSpatializationDisabledCVar = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " au.DisableBinauralSpatialization " ) ) ;
if ( BinauralSpatializationDisabledCVar )
{
BinauralSpatializationDisabledCVar - > Set ( ! bEnabled , ECVF_SetByGameSetting ) ;
// Only save settings if the setting actually changed
if ( bUseHeadphoneMode ! = bEnabled )
{
bUseHeadphoneMode = bEnabled ;
SaveSettings ( ) ;
}
}
}
}
bool ULyraSettingsLocal : : IsHeadphoneModeEnabled ( ) const
{
return bUseHeadphoneMode ;
}
bool ULyraSettingsLocal : : CanModifyHeadphoneModeEnabled ( ) const
{
static IConsoleVariable * BinauralSpatializationDisabledCVar = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " au.DisableBinauralSpatialization " ) ) ;
const bool bHRTFOptionAvailable = BinauralSpatializationDisabledCVar & & ( ( BinauralSpatializationDisabledCVar - > GetFlags ( ) & EConsoleVariableFlags : : ECVF_SetByMask ) < = EConsoleVariableFlags : : ECVF_SetByGameSetting ) ;
const bool bBinauralSettingControlledByOS = LyraSettingsHelpers : : HasPlatformTrait ( TAG_Platform_Trait_BinauralSettingControlledByOS ) ;
return bHRTFOptionAvailable & & ! bBinauralSettingControlledByOS ;
}
bool ULyraSettingsLocal : : IsHDRAudioModeEnabled ( ) const
{
return bUseHDRAudioMode ;
}
void ULyraSettingsLocal : : SetHDRAudioModeEnabled ( bool bEnabled )
{
bUseHDRAudioMode = bEnabled ;
if ( GEngine )
{
if ( const UWorld * World = GEngine - > GetCurrentPlayWorld ( ) )
{
if ( ULyraAudioMixEffectsSubsystem * LyraAudioMixEffectsSubsystem = World - > GetSubsystem < ULyraAudioMixEffectsSubsystem > ( ) )
{
LyraAudioMixEffectsSubsystem - > ApplyDynamicRangeEffectsChains ( bEnabled ) ;
}
}
}
}
bool ULyraSettingsLocal : : CanRunAutoBenchmark ( ) const
{
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
return PlatformSettings - > bSupportsAutomaticVideoQualityBenchmark ;
}
bool ULyraSettingsLocal : : ShouldRunAutoBenchmarkAtStartup ( ) const
{
if ( ! CanRunAutoBenchmark ( ) )
{
return false ;
}
if ( LastCPUBenchmarkResult ! = - 1 )
{
// Already run and loaded
return false ;
}
return true ;
}
void ULyraSettingsLocal : : RunAutoBenchmark ( bool bSaveImmediately )
{
RunHardwareBenchmark ( ) ;
// Always apply, optionally save
ApplyScalabilitySettings ( ) ;
if ( bSaveImmediately )
{
SaveSettings ( ) ;
}
}
void ULyraSettingsLocal : : ApplyScalabilitySettings ( )
{
Scalability : : SetQualityLevels ( ScalabilityQuality ) ;
}
float ULyraSettingsLocal : : GetOverallVolume ( ) const
{
return OverallVolume ;
}
void ULyraSettingsLocal : : SetOverallVolume ( float InVolume )
{
// Cache the incoming volume value
OverallVolume = InVolume ;
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called from the UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Locate the locally cached bus and set the volume on it
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Overall " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , OverallVolume ) ;
}
}
}
float ULyraSettingsLocal : : GetMusicVolume ( ) const
{
return MusicVolume ;
}
void ULyraSettingsLocal : : SetMusicVolume ( float InVolume )
{
// Cache the incoming volume value
MusicVolume = InVolume ;
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called from the UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Locate the locally cached bus and set the volume on it
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Music " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , MusicVolume ) ;
}
}
}
float ULyraSettingsLocal : : GetSoundFXVolume ( ) const
{
return SoundFXVolume ;
}
void ULyraSettingsLocal : : SetSoundFXVolume ( float InVolume )
{
// Cache the incoming volume value
SoundFXVolume = InVolume ;
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called from the UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Locate the locally cached bus and set the volume on it
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " SoundFX " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , SoundFXVolume ) ;
}
}
}
float ULyraSettingsLocal : : GetDialogueVolume ( ) const
{
return DialogueVolume ;
}
void ULyraSettingsLocal : : SetDialogueVolume ( float InVolume )
{
// Cache the incoming volume value
DialogueVolume = InVolume ;
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called from the UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Locate the locally cached bus and set the volume on it
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Dialogue " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , DialogueVolume ) ;
}
}
}
float ULyraSettingsLocal : : GetVoiceChatVolume ( ) const
{
return VoiceChatVolume ;
}
void ULyraSettingsLocal : : SetVoiceChatVolume ( float InVolume )
{
// Cache the incoming volume value
VoiceChatVolume = InVolume ;
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called from the UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Locate the locally cached bus and set the volume on it
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " VoiceChat " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , VoiceChatVolume ) ;
}
}
}
void ULyraSettingsLocal : : SetVolumeForControlBus ( USoundControlBus * InSoundControlBus , float InVolume )
{
// Check to see if references to the control buses and control bus mixes have been loaded yet
// Will likely need to be loaded if this function is the first time a setter has been called
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// Ensure it's been loaded before continuing
ensureMsgf ( bSoundControlBusMixLoaded , TEXT ( " UserControlBusMix Settings Failed to Load. " ) ) ;
// Assuming everything has been loaded correctly, we retrieve the world and use AudioModulationStatics to update the Control Bus Volume values and
// apply the settings to the cached User Control Bus Mix
if ( GEngine & & InSoundControlBus & & bSoundControlBusMixLoaded )
{
if ( const UWorld * AudioWorld = GEngine - > GetCurrentPlayWorld ( ) )
{
ensureMsgf ( ControlBusMix , TEXT ( " Control Bus Mix failed to load. " ) ) ;
// Create and set the Control Bus Mix Stage Parameters
FSoundControlBusMixStage UpdatedControlBusMixStage ;
UpdatedControlBusMixStage . Bus = InSoundControlBus ;
UpdatedControlBusMixStage . Value . TargetValue = InVolume ;
UpdatedControlBusMixStage . Value . AttackTime = 0.01f ;
UpdatedControlBusMixStage . Value . ReleaseTime = 0.01f ;
// Add the Control Bus Mix Stage to an Array as the UpdateMix function requires
TArray < FSoundControlBusMixStage > UpdatedMixStageArray ;
UpdatedMixStageArray . Add ( UpdatedControlBusMixStage ) ;
// Modify the matching bus Mix Stage parameters on the User Control Bus Mix
UAudioModulationStatics : : UpdateMix ( AudioWorld , ControlBusMix , UpdatedMixStageArray ) ;
}
}
}
void ULyraSettingsLocal : : SetAudioOutputDeviceId ( const FString & InAudioOutputDeviceId )
{
AudioOutputDeviceId = InAudioOutputDeviceId ;
OnAudioOutputDeviceChanged . Broadcast ( InAudioOutputDeviceId ) ;
}
void ULyraSettingsLocal : : ApplySafeZoneScale ( )
{
SSafeZone : : SetGlobalSafeZoneScale ( GetSafeZone ( ) ) ;
}
void ULyraSettingsLocal : : ApplyNonResolutionSettings ( )
{
Super : : ApplyNonResolutionSettings ( ) ;
// Check if Control Bus Mix references have been loaded,
// Might be false if applying non resolution settings without touching any of the setters from UI
if ( ! bSoundControlBusMixLoaded )
{
LoadUserControlBusMix ( ) ;
}
// In this section, update each Control Bus to the currently cached UI settings
{
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Overall " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , OverallVolume ) ;
}
}
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Music " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , MusicVolume ) ;
}
}
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " SoundFX " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , SoundFXVolume ) ;
}
}
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " Dialogue " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , DialogueVolume ) ;
}
}
2022-09-13 07:18:28 +00:00
if ( TObjectPtr < USoundControlBus > * ControlBusDblPtr = ControlBusMap . Find ( TEXT ( " VoiceChat " ) ) )
2022-05-23 18:41:30 +00:00
{
if ( USoundControlBus * ControlBusPtr = * ControlBusDblPtr )
{
SetVolumeForControlBus ( ControlBusPtr , VoiceChatVolume ) ;
}
}
}
if ( UCommonInputSubsystem * InputSubsystem = UCommonInputSubsystem : : Get ( GetTypedOuter < ULocalPlayer > ( ) ) )
{
InputSubsystem - > SetGamepadInputType ( ControllerPlatform ) ;
}
if ( bUseHeadphoneMode ! = bDesiredHeadphoneMode )
{
SetHeadphoneModeEnabled ( bDesiredHeadphoneMode ) ;
}
if ( DesiredUserChosenDeviceProfileSuffix ! = UserChosenDeviceProfileSuffix )
{
UserChosenDeviceProfileSuffix = DesiredUserChosenDeviceProfileSuffix ;
}
if ( FApp : : CanEverRender ( ) )
{
ApplyDisplayGamma ( ) ;
ApplySafeZoneScale ( ) ;
UpdateGameModeDeviceProfileAndFps ( ) ;
}
PerfStatSettingsChangedEvent . Broadcast ( ) ;
}
int32 ULyraSettingsLocal : : GetOverallScalabilityLevel ( ) const
{
int32 Result = Super : : GetOverallScalabilityLevel ( ) ;
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle )
{
Result = GetHighestLevelOfAnyScalabilityChannel ( ) ;
}
return Result ;
}
void ULyraSettingsLocal : : SetOverallScalabilityLevel ( int32 Value )
{
TGuardValue Guard ( bSettingOverallQualityGuard , true ) ;
Value = FMath : : Clamp ( Value , 0 , 3 ) ;
float CurrentMobileResolutionQuality = ScalabilityQuality . ResolutionQuality ;
Super : : SetOverallScalabilityLevel ( Value ) ;
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
if ( PlatformSettings - > FramePacingMode = = ELyraFramePacingMode : : MobileStyle )
{
// Restore the resolution quality, mobile decouples this from overall quality
ScalabilityQuality . ResolutionQuality = CurrentMobileResolutionQuality ;
// Changing the overall quality can end up adjusting the frame rate on mobile since there are limits
const int32 ConstrainedFrameRateLimit = LyraSettingsHelpers : : ConstrainFrameRateToBeCompatibleWithOverallQuality ( DesiredMobileFrameRateLimit , Value ) ;
if ( ConstrainedFrameRateLimit ! = DesiredMobileFrameRateLimit )
{
SetDesiredMobileFrameRateLimit ( ConstrainedFrameRateLimit ) ;
}
}
}
void ULyraSettingsLocal : : SetControllerPlatform ( const FName InControllerPlatform )
{
if ( ControllerPlatform ! = InControllerPlatform )
{
ControllerPlatform = InControllerPlatform ;
// Apply the change to the common input subsystem so that we refresh any input icons we're using.
if ( UCommonInputSubsystem * InputSubsystem = UCommonInputSubsystem : : Get ( GetTypedOuter < ULocalPlayer > ( ) ) )
{
InputSubsystem - > SetGamepadInputType ( ControllerPlatform ) ;
}
}
}
FName ULyraSettingsLocal : : GetControllerPlatform ( ) const
{
return ControllerPlatform ;
}
void ULyraSettingsLocal : : RegisterInputConfig ( ECommonInputType Type , const UPlayerMappableInputConfig * NewConfig , const bool bIsActive )
{
if ( NewConfig )
{
const int32 ExistingConfigIdx = RegisteredInputConfigs . IndexOfByPredicate ( [ & NewConfig ] ( const FLoadedMappableConfigPair & Pair ) { return Pair . Config = = NewConfig ; } ) ;
if ( ExistingConfigIdx = = INDEX_NONE )
{
const int32 NumAdded = RegisteredInputConfigs . Add ( FLoadedMappableConfigPair ( NewConfig , Type , bIsActive ) ) ;
if ( NumAdded ! = INDEX_NONE )
{
OnInputConfigRegistered . Broadcast ( RegisteredInputConfigs [ NumAdded ] ) ;
}
}
}
}
int32 ULyraSettingsLocal : : UnregisterInputConfig ( const UPlayerMappableInputConfig * ConfigToRemove )
{
if ( ConfigToRemove )
{
const int32 Index = RegisteredInputConfigs . IndexOfByPredicate ( [ & ConfigToRemove ] ( const FLoadedMappableConfigPair & Pair ) { return Pair . Config = = ConfigToRemove ; } ) ;
if ( Index ! = INDEX_NONE )
{
RegisteredInputConfigs . RemoveAt ( Index ) ;
return 1 ;
}
}
return INDEX_NONE ;
}
const UPlayerMappableInputConfig * ULyraSettingsLocal : : GetInputConfigByName ( FName ConfigName ) const
{
for ( const FLoadedMappableConfigPair & Pair : RegisteredInputConfigs )
{
if ( Pair . Config - > GetConfigName ( ) = = ConfigName )
{
return Pair . Config ;
}
}
return nullptr ;
}
void ULyraSettingsLocal : : GetRegisteredInputConfigsOfType ( ECommonInputType Type , TArray < FLoadedMappableConfigPair > & OutArray ) const
{
OutArray . Empty ( ) ;
// If "Count" is passed in then
if ( Type = = ECommonInputType : : Count )
{
OutArray = RegisteredInputConfigs ;
return ;
}
for ( const FLoadedMappableConfigPair & Pair : RegisteredInputConfigs )
{
if ( Pair . Type = = Type )
{
OutArray . Emplace ( Pair ) ;
}
}
}
2022-09-13 07:18:28 +00:00
void ULyraSettingsLocal : : GetAllMappingNamesFromKey ( const FKey InKey , TArray < FName > & OutActionNames )
{
if ( InKey = = EKeys : : Invalid )
{
return ;
}
// adding any names of actions that are bound to that key
for ( const FLoadedMappableConfigPair & Pair : RegisteredInputConfigs )
{
if ( Pair . Type = = ECommonInputType : : MouseAndKeyboard )
{
for ( const FEnhancedActionKeyMapping & Mapping : Pair . Config - > GetPlayerMappableKeys ( ) )
{
FName MappingName ( Mapping . PlayerMappableOptions . DisplayName . ToString ( ) ) ;
FName ActionName = Mapping . PlayerMappableOptions . Name ;
// make sure it isn't custom bound as well
if ( const FKey * MappingKey = CustomKeyboardConfig . Find ( ActionName ) )
{
if ( * MappingKey = = InKey )
{
OutActionNames . Add ( MappingName ) ;
}
}
else
{
if ( Mapping . Key = = InKey )
{
OutActionNames . Add ( MappingName ) ;
}
}
}
}
}
}
2022-05-23 18:41:30 +00:00
void ULyraSettingsLocal : : AddOrUpdateCustomKeyboardBindings ( const FName MappingName , const FKey NewKey , ULyraLocalPlayer * LocalPlayer )
{
if ( MappingName = = NAME_None )
{
return ;
}
if ( InputConfigName ! = TEXT ( " Custom " ) )
{
// Copy Presets.
if ( const UPlayerMappableInputConfig * DefaultConfig = GetInputConfigByName ( TEXT ( " Default " ) ) )
{
for ( const FEnhancedActionKeyMapping & Mapping : DefaultConfig - > GetPlayerMappableKeys ( ) )
{
// Make sure that the mapping has a valid name, its possible to have an empty name
2022-09-13 07:18:28 +00:00
// if someone has marked a mapping as "Player Mappable" but deleted the default field value
2022-05-23 18:41:30 +00:00
if ( Mapping . PlayerMappableOptions . Name ! = NAME_None )
{
CustomKeyboardConfig . Add ( Mapping . PlayerMappableOptions . Name , Mapping . Key ) ;
}
}
}
InputConfigName = TEXT ( " Custom " ) ;
}
if ( FKey * ExistingMapping = CustomKeyboardConfig . Find ( MappingName ) )
{
// Change the key to the new one
CustomKeyboardConfig [ MappingName ] = NewKey ;
}
else
{
CustomKeyboardConfig . Add ( MappingName , NewKey ) ;
}
// Tell the enhanced input subsystem for this local player that we should remap some input! Woo
if ( UEnhancedInputLocalPlayerSubsystem * Subsystem = ULocalPlayer : : GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( LocalPlayer ) )
{
Subsystem - > AddPlayerMappedKey ( MappingName , NewKey ) ;
}
}
2022-09-13 07:18:28 +00:00
void ULyraSettingsLocal : : ResetKeybindingToDefault ( const FName MappingName , ULyraLocalPlayer * LocalPlayer )
{
if ( UEnhancedInputLocalPlayerSubsystem * Subsystem = ULocalPlayer : : GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( LocalPlayer ) )
{
Subsystem - > RemovePlayerMappedKey ( MappingName ) ;
}
}
void ULyraSettingsLocal : : ResetKeybindingsToDefault ( ULyraLocalPlayer * LocalPlayer )
{
if ( UEnhancedInputLocalPlayerSubsystem * Subsystem = ULocalPlayer : : GetSubsystem < UEnhancedInputLocalPlayerSubsystem > ( LocalPlayer ) )
{
Subsystem - > RemoveAllPlayerMappedKeys ( ) ;
}
}
2022-05-23 18:41:30 +00:00
void ULyraSettingsLocal : : LoadUserControlBusMix ( )
{
if ( GEngine )
{
if ( const UWorld * World = GEngine - > GetCurrentPlayWorld ( ) )
{
if ( const ULyraAudioSettings * LyraAudioSettings = GetDefault < ULyraAudioSettings > ( ) )
{
USoundControlBus * OverallControlBus = nullptr ;
USoundControlBus * MusicControlBus = nullptr ;
USoundControlBus * SoundFXControlBus = nullptr ;
USoundControlBus * DialogueControlBus = nullptr ;
USoundControlBus * VoiceChatControlBus = nullptr ;
ControlBusMap . Empty ( ) ;
if ( UObject * ObjPath = LyraAudioSettings - > OverallVolumeControlBus . TryLoad ( ) )
{
if ( USoundControlBus * SoundControlBus = Cast < USoundControlBus > ( ObjPath ) )
{
OverallControlBus = SoundControlBus ;
ControlBusMap . Add ( TEXT ( " Overall " ) , OverallControlBus ) ;
}
else
{
ensureMsgf ( SoundControlBus , TEXT ( " Overall Control Bus reference missing from Lyra Audio Settings. " ) ) ;
}
}
if ( UObject * ObjPath = LyraAudioSettings - > MusicVolumeControlBus . TryLoad ( ) )
{
if ( USoundControlBus * SoundControlBus = Cast < USoundControlBus > ( ObjPath ) )
{
MusicControlBus = SoundControlBus ;
ControlBusMap . Add ( TEXT ( " Music " ) , MusicControlBus ) ;
}
else
{
ensureMsgf ( SoundControlBus , TEXT ( " Music Control Bus reference missing from Lyra Audio Settings. " ) ) ;
}
}
if ( UObject * ObjPath = LyraAudioSettings - > SoundFXVolumeControlBus . TryLoad ( ) )
{
if ( USoundControlBus * SoundControlBus = Cast < USoundControlBus > ( ObjPath ) )
{
SoundFXControlBus = SoundControlBus ;
ControlBusMap . Add ( TEXT ( " SoundFX " ) , SoundFXControlBus ) ;
}
else
{
ensureMsgf ( SoundControlBus , TEXT ( " SoundFX Control Bus reference missing from Lyra Audio Settings. " ) ) ;
}
}
if ( UObject * ObjPath = LyraAudioSettings - > DialogueVolumeControlBus . TryLoad ( ) )
{
if ( USoundControlBus * SoundControlBus = Cast < USoundControlBus > ( ObjPath ) )
{
DialogueControlBus = SoundControlBus ;
ControlBusMap . Add ( TEXT ( " Dialogue " ) , DialogueControlBus ) ;
}
else
{
ensureMsgf ( SoundControlBus , TEXT ( " Dialogue Control Bus reference missing from Lyra Audio Settings. " ) ) ;
}
}
if ( UObject * ObjPath = LyraAudioSettings - > VoiceChatVolumeControlBus . TryLoad ( ) )
{
if ( USoundControlBus * SoundControlBus = Cast < USoundControlBus > ( ObjPath ) )
{
VoiceChatControlBus = SoundControlBus ;
ControlBusMap . Add ( TEXT ( " VoiceChat " ) , VoiceChatControlBus ) ;
}
else
{
ensureMsgf ( SoundControlBus , TEXT ( " VoiceChat Control Bus reference missing from Lyra Audio Settings. " ) ) ;
}
}
if ( UObject * ObjPath = LyraAudioSettings - > UserSettingsControlBusMix . TryLoad ( ) )
{
if ( USoundControlBusMix * SoundControlBusMix = Cast < USoundControlBusMix > ( ObjPath ) )
{
ControlBusMix = SoundControlBusMix ;
const FSoundControlBusMixStage OverallControlBusMixStage = UAudioModulationStatics : : CreateBusMixStage ( World , OverallControlBus , OverallVolume ) ;
const FSoundControlBusMixStage MusicControlBusMixStage = UAudioModulationStatics : : CreateBusMixStage ( World , MusicControlBus , MusicVolume ) ;
const FSoundControlBusMixStage SoundFXControlBusMixStage = UAudioModulationStatics : : CreateBusMixStage ( World , SoundFXControlBus , SoundFXVolume ) ;
const FSoundControlBusMixStage DialogueControlBusMixStage = UAudioModulationStatics : : CreateBusMixStage ( World , DialogueControlBus , DialogueVolume ) ;
const FSoundControlBusMixStage VoiceChatControlBusMixStage = UAudioModulationStatics : : CreateBusMixStage ( World , VoiceChatControlBus , VoiceChatVolume ) ;
TArray < FSoundControlBusMixStage > ControlBusMixStageArray ;
ControlBusMixStageArray . Add ( OverallControlBusMixStage ) ;
ControlBusMixStageArray . Add ( MusicControlBusMixStage ) ;
ControlBusMixStageArray . Add ( SoundFXControlBusMixStage ) ;
ControlBusMixStageArray . Add ( DialogueControlBusMixStage ) ;
ControlBusMixStageArray . Add ( VoiceChatControlBusMixStage ) ;
UAudioModulationStatics : : UpdateMix ( World , ControlBusMix , ControlBusMixStageArray ) ;
bSoundControlBusMixLoaded = true ;
}
else
{
ensureMsgf ( SoundControlBusMix , TEXT ( " User Settings Control Bus Mix reference missing from Lyra Audio Settings. " ) ) ;
}
}
}
}
}
}
void ULyraSettingsLocal : : OnAppActivationStateChanged ( bool bIsActive )
{
// We might want to adjust the frame rate when the app loses/gains focus on multi-window platforms
UpdateEffectiveFrameRateLimit ( ) ;
}
void ULyraSettingsLocal : : UpdateGameModeDeviceProfileAndFps ( )
{
# if WITH_EDITOR
if ( GIsEditor & & ! CVarApplyDeviceProfilesInPIE . GetValueOnGameThread ( ) )
{
return ;
}
# endif
UDeviceProfileManager & Manager = UDeviceProfileManager : : Get ( ) ;
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
const TArray < FLyraQualityDeviceProfileVariant > & UserFacingVariants = PlatformSettings - > UserFacingDeviceProfileOptions ;
//@TODO: Might want to allow specific experiences to specify a suffix to attempt to use as well
// The code below will handle searching with this suffix (alone or in conjunction with the frame rate), but nothing sets it right now
FString ExperienceSuffix ;
// Make sure the chosen setting is supported for the current display, walking down the list to try fallbacks
const int32 PlatformMaxRefreshRate = FPlatformMisc : : GetMaxRefreshRate ( ) ;
int32 SuffixIndex = UserFacingVariants . IndexOfByPredicate ( [ & ] ( const FLyraQualityDeviceProfileVariant & Data ) { return Data . DeviceProfileSuffix = = UserChosenDeviceProfileSuffix ; } ) ;
while ( UserFacingVariants . IsValidIndex ( SuffixIndex ) )
{
if ( PlatformMaxRefreshRate > = UserFacingVariants [ SuffixIndex ] . MinRefreshRate )
{
break ;
}
else
{
- - SuffixIndex ;
}
}
const FString EffectiveUserSuffix = UserFacingVariants . IsValidIndex ( SuffixIndex ) ? UserFacingVariants [ SuffixIndex ] . DeviceProfileSuffix : PlatformSettings - > DefaultDeviceProfileSuffix ;
// Build up a list of names to try
const bool bHadUserSuffix = ! EffectiveUserSuffix . IsEmpty ( ) ;
const bool bHadExperienceSuffix = ! ExperienceSuffix . IsEmpty ( ) ;
FString BasePlatformName = UDeviceProfileManager : : GetPlatformDeviceProfileName ( ) ;
FName PlatformName ; // Default unless in editor
# if WITH_EDITOR
if ( GIsEditor )
{
const ULyraPlatformEmulationSettings * Settings = GetDefault < ULyraPlatformEmulationSettings > ( ) ;
const FName PretendBaseDeviceProfile = Settings - > GetPretendBaseDeviceProfile ( ) ;
if ( PretendBaseDeviceProfile ! = NAME_None )
{
BasePlatformName = PretendBaseDeviceProfile . ToString ( ) ;
}
PlatformName = Settings - > GetPretendPlatformName ( ) ;
}
# endif
TArray < FString > ComposedNamesToFind ;
if ( bHadExperienceSuffix & & bHadUserSuffix )
{
ComposedNamesToFind . Add ( BasePlatformName + TEXT ( " _ " ) + ExperienceSuffix + TEXT ( " _ " ) + EffectiveUserSuffix ) ;
}
if ( bHadUserSuffix )
{
ComposedNamesToFind . Add ( BasePlatformName + TEXT ( " _ " ) + EffectiveUserSuffix ) ;
}
if ( bHadExperienceSuffix )
{
ComposedNamesToFind . Add ( BasePlatformName + TEXT ( " _ " ) + ExperienceSuffix ) ;
}
if ( GIsEditor )
{
ComposedNamesToFind . Add ( BasePlatformName ) ;
}
// See if any of the potential device profiles actually exists
FString ActualProfileToApply ;
for ( const FString & TestProfileName : ComposedNamesToFind )
{
if ( Manager . HasLoadableProfileName ( TestProfileName , PlatformName ) )
{
ActualProfileToApply = TestProfileName ;
UDeviceProfile * Profile = Manager . FindProfile ( TestProfileName , /*bCreateOnFail=*/ false ) ;
if ( Profile = = nullptr )
{
Profile = Manager . CreateProfile ( TestProfileName , TEXT ( " " ) , TestProfileName , * PlatformName . ToString ( ) ) ;
}
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Profile %s exists " ) , * Profile - > GetName ( ) ) ;
break ;
}
}
UE_LOG ( LogConsoleResponse , Log , TEXT ( " UpdateGameModeDeviceProfileAndFps MaxRefreshRate=%d, ExperienceSuffix='%s', UserPicked='%s'->'%s', PlatformBase='%s', AppliedActual='%s' " ) ,
PlatformMaxRefreshRate , * ExperienceSuffix , * UserChosenDeviceProfileSuffix , * EffectiveUserSuffix , * BasePlatformName , * ActualProfileToApply ) ;
// Apply the device profile if it's different to what we currently have
if ( ActualProfileToApply ! = CurrentAppliedDeviceProfileOverrideSuffix )
{
if ( Manager . GetActiveDeviceProfileName ( ) ! = ActualProfileToApply )
{
// Restore the default first
if ( GIsEditor )
{
# if ALLOW_OTHER_PLATFORM_CONFIG
Manager . RestorePreviewDeviceProfile ( ) ;
# endif
}
else
{
Manager . RestoreDefaultDeviceProfile ( ) ;
}
// Apply the new one (if it wasn't the default)
if ( Manager . GetActiveDeviceProfileName ( ) ! = ActualProfileToApply )
{
UDeviceProfile * NewDeviceProfile = Manager . FindProfile ( ActualProfileToApply ) ;
ensureMsgf ( NewDeviceProfile ! = nullptr , TEXT ( " DeviceProfile %s not found " ) , * ActualProfileToApply ) ;
if ( NewDeviceProfile )
{
if ( GIsEditor )
{
# if ALLOW_OTHER_PLATFORM_CONFIG
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Overriding *preview* device profile to %s " ) , * ActualProfileToApply ) ;
Manager . SetPreviewDeviceProfile ( NewDeviceProfile ) ;
// Reload the default settings from the pretend profile
LyraSettingsHelpers : : FillScalabilitySettingsFromDeviceProfile ( DeviceDefaultScalabilitySettings ) ;
# endif
}
else
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Overriding device profile to %s " ) , * ActualProfileToApply ) ;
Manager . SetOverrideDeviceProfile ( NewDeviceProfile ) ;
}
}
}
}
CurrentAppliedDeviceProfileOverrideSuffix = ActualProfileToApply ;
}
switch ( PlatformSettings - > FramePacingMode )
{
case ELyraFramePacingMode : : MobileStyle :
UpdateMobileFramePacing ( ) ;
break ;
case ELyraFramePacingMode : : ConsoleStyle :
UpdateConsoleFramePacing ( ) ;
break ;
case ELyraFramePacingMode : : DesktopStyle :
UpdateDesktopFramePacing ( ) ;
break ;
}
}
void ULyraSettingsLocal : : UpdateConsoleFramePacing ( )
{
// Apply device-profile-driven frame sync and frame pace
const int32 FrameSyncType = CVarDeviceProfileDrivenFrameSyncType . GetValueOnGameThread ( ) ;
if ( FrameSyncType ! = - 1 )
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Setting frame sync mode to %d. " ) , FrameSyncType ) ;
SetSyncTypeCVar ( FrameSyncType ) ;
}
const int32 TargetFPS = CVarDeviceProfileDrivenTargetFps . GetValueOnGameThread ( ) ;
if ( TargetFPS ! = - 1 )
{
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Setting frame pace to %d Hz. " ) , TargetFPS ) ;
FPlatformRHIFramePacer : : SetFramePace ( TargetFPS ) ;
// Set the CSV metadata and analytics Fps mode strings
# if CSV_PROFILER
const FString TargetFramerateString = FString : : Printf ( TEXT ( " %d " ) , TargetFPS ) ;
CSV_METADATA ( TEXT ( " TargetFramerate " ) , * TargetFramerateString ) ;
# endif
}
}
void ULyraSettingsLocal : : UpdateDesktopFramePacing ( )
{
// For desktop the frame rate limit is handled by the parent class based on the value already
// applied via UpdateEffectiveFrameRateLimit()
// So this function is only doing 'second order' effects of desktop frame pacing preferences
const float TargetFPS = GetEffectiveFrameRateLimit ( ) ;
const float ClampedFPS = ( TargetFPS < = 0.0f ) ? 60.0f : FMath : : Clamp ( TargetFPS , 30.0f , 60.0f ) ;
UpdateDynamicResFrameTime ( ClampedFPS ) ;
}
void ULyraSettingsLocal : : UpdateMobileFramePacing ( )
{
//@TODO: Handle different limits for in-front-end or low-battery mode on mobile
// Choose the closest supported frame rate to the user desired setting without going over the device imposed limit
const ULyraPlatformSpecificRenderingSettings * PlatformSettings = ULyraPlatformSpecificRenderingSettings : : Get ( ) ;
const TArray < int32 > & PossibleRates = PlatformSettings - > MobileFrameRateLimits ;
const int32 LimitIndex = PossibleRates . FindLastByPredicate ( [ = ] ( const int32 & TestRate ) { return ( TestRate < = MobileFrameRateLimit ) & & IsSupportedMobileFramePace ( TestRate ) ; } ) ;
const int32 TargetFPS = PossibleRates . IsValidIndex ( LimitIndex ) ? PossibleRates [ LimitIndex ] : GetDefaultMobileFrameRate ( ) ;
UE_LOG ( LogConsoleResponse , Log , TEXT ( " Setting frame pace to %d Hz. " ) , TargetFPS ) ;
FPlatformRHIFramePacer : : SetFramePace ( TargetFPS ) ;
ClampMobileQuality ( ) ;
UpdateDynamicResFrameTime ( ( float ) TargetFPS ) ;
}
void ULyraSettingsLocal : : UpdateDynamicResFrameTime ( float TargetFPS )
{
static IConsoleVariable * CVarDyResFrameTimeBudget = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " r.DynamicRes.FrameTimeBudget " ) ) ;
if ( CVarDyResFrameTimeBudget )
{
if ( ensure ( TargetFPS > 0.0f ) )
{
const float DyResFrameTimeBudget = 1000.0f / TargetFPS ;
CVarDyResFrameTimeBudget - > Set ( DyResFrameTimeBudget , ECVF_SetByGameSetting ) ;
}
}
}