2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2018-12-14 11:21:22 -05:00
2018-09-25 10:11:35 -04:00
# include "PreLoadScreenManager.h"
# include "Engine/GameEngine.h"
2020-06-23 18:40:00 -04:00
# include "Framework/Application/SlateApplication.h"
2018-09-25 10:11:35 -04:00
# include "GlobalShader.h"
# include "ShaderCompiler.h"
# include "PreLoadScreen.h"
# include "PreLoadSettingsContainer.h"
# include "HAL/ThreadManager.h"
2019-01-28 16:31:01 -05:00
# include "Modules/ModuleManager.h"
2018-09-25 10:11:35 -04:00
2019-02-27 11:57:17 -05:00
# if BUILD_EMBEDDED_APP
# include "Misc/EmbeddedCommunication.h"
# endif
2018-09-25 10:11:35 -04:00
# if PLATFORM_ANDROID
# if USE_ANDROID_EVENTS
# include "Android/AndroidEventManager.h"
# endif
# endif
2019-01-28 16:31:01 -05:00
IMPLEMENT_MODULE ( FDefaultModuleImpl , PreLoadScreen ) ;
2018-09-25 10:11:35 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogPreLoadScreenManager , Log , All ) ;
2020-06-23 18:40:00 -04:00
TUniquePtr < FPreLoadScreenManager , FPreLoadScreenManager : : FPreLoadScreenManagerDelete > FPreLoadScreenManager : : Instance ;
2023-10-25 21:39:35 -04:00
std : : atomic < bool > FPreLoadScreenManager : : bRenderingEnabled ( true ) ;
FCriticalSection FPreLoadScreenManager : : ActivePreloadScreenCriticalSection ;
TWeakPtr < IPreLoadScreen > FPreLoadScreenManager : : ActivePreloadScreen ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
FPreLoadScreenManager * FPreLoadScreenManager : : Get ( )
{
return Instance . Get ( ) ;
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : Create ( )
{
check ( IsInGameThread ( ) ) ;
if ( ! Instance . IsValid ( ) & & ArePreLoadScreensEnabled ( ) )
{
Instance = TUniquePtr < FPreLoadScreenManager , FPreLoadScreenManager : : FPreLoadScreenManagerDelete > ( new FPreLoadScreenManager ) ;
}
}
void FPreLoadScreenManager : : Destroy ( )
{
check ( IsInGameThread ( ) ) ;
if ( Instance . IsValid ( ) )
{
Instance - > CleanUpResources ( ) ;
Instance . Reset ( ) ;
}
}
FPreLoadScreenManager : : FPreLoadScreenManager ( )
: ActivePreLoadScreenIndex ( - 1 )
, LastTickTime ( 0.0 )
, bInitialized ( false )
, SyncMechanism ( nullptr )
, bIsResponsibleForRendering ( false )
2020-08-11 01:36:57 -04:00
, bHasRenderPreLoadScreenFrame_RenderThread ( false )
2020-06-23 18:40:00 -04:00
, LastRenderTickTime ( 0.0 )
, OriginalSlateSleepVariableValue ( 0.f )
, bIsEngineLoadingComplete ( false )
{ }
2019-07-22 11:49:15 -04:00
2018-09-25 10:11:35 -04:00
void FPreLoadScreenManager : : Initialize ( FSlateRenderer & InSlateRenderer )
{
2020-06-23 18:40:00 -04:00
check ( IsInGameThread ( ) ) ;
if ( bInitialized | | ! ArePreLoadScreensEnabled ( ) )
{
return ;
}
2018-09-25 10:11:35 -04:00
bInitialized = true ;
2020-06-23 18:40:00 -04:00
// Initialize shaders, because otherwise they might not be guaranteed to exist at this point
2021-06-22 00:27:54 -04:00
if ( ! FPlatformProperties : : RequiresCookedData ( ) & & GShaderCompilingManager )
2020-06-23 18:40:00 -04:00
{
TArray < int32 > ShaderMapIds ;
ShaderMapIds . Add ( GlobalShaderMapId ) ;
GShaderCompilingManager - > FinishCompilation ( TEXT ( " Global " ) , ShaderMapIds ) ;
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( FApp : : CanEverRender ( ) )
{
// Make sure we haven't created a game window already, if so use that. If not make a new one
UGameEngine * GameEngine = Cast < UGameEngine > ( GEngine ) ;
TSharedRef < SWindow > GameWindow = ( GameEngine & & GameEngine - > GameViewportWindow . IsValid ( ) ) ? GameEngine - > GameViewportWindow . Pin ( ) . ToSharedRef ( ) : UGameEngine : : CreateGameWindow ( ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
VirtualRenderWindow =
SNew ( SVirtualWindow )
. Size ( GameWindow - > GetClientSizeInScreen ( ) ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
MainWindow = GameWindow ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
WidgetRenderer = MakeShared < FPreLoadSlateWidgetRenderer , ESPMode : : ThreadSafe > ( GameWindow , VirtualRenderWindow , & InSlateRenderer ) ;
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
LastRenderTickTime = FPlatformTime : : Seconds ( ) ;
LastTickTime = FPlatformTime : : Seconds ( ) ;
2018-09-25 10:11:35 -04:00
}
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : RegisterPreLoadScreen ( const TSharedPtr < IPreLoadScreen > & PreLoadScreen )
2018-09-25 10:11:35 -04:00
{
2020-06-23 18:40:00 -04:00
check ( IsInGameThread ( ) ) ;
2018-09-25 10:11:35 -04:00
PreLoadScreens . Add ( PreLoadScreen ) ;
}
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : UnRegisterPreLoadScreen ( const TSharedPtr < IPreLoadScreen > & PreLoadScreen )
2018-09-25 10:11:35 -04:00
{
2020-06-23 18:40:00 -04:00
check ( IsInGameThread ( ) ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( PreLoadScreen . IsValid ( ) )
{
const int32 IndexOf = PreLoadScreens . IndexOfByKey ( PreLoadScreen ) ;
if ( PreLoadScreens . IsValidIndex ( IndexOf ) )
{
if ( IndexOf = = ActivePreLoadScreenIndex )
2019-10-03 08:46:18 -04:00
{
2020-06-23 18:40:00 -04:00
ensureMsgf ( false , TEXT ( " Can't remove an active preloadscreen. " ) ) ;
return ;
2019-10-03 08:46:18 -04:00
}
2020-06-23 18:40:00 -04:00
TSharedPtr < IPreLoadScreen > PreviousActivePreLoadScreen = PreLoadScreens . IsValidIndex ( ActivePreLoadScreenIndex )
? PreLoadScreens [ ActivePreLoadScreenIndex ] : nullptr ;
PreLoadScreen - > CleanUp ( ) ;
PreLoadScreens . RemoveAtSwap ( IndexOf ) ;
if ( PreviousActivePreLoadScreen )
{
ActivePreLoadScreenIndex = PreLoadScreens . IndexOfByKey ( PreviousActivePreLoadScreen ) ;
}
}
}
}
bool FPreLoadScreenManager : : PlayFirstPreLoadScreen ( EPreLoadScreenTypes PreLoadScreenTypeToPlay )
{
for ( int32 PreLoadScreenIndex = 0 ; PreLoadScreenIndex < PreLoadScreens . Num ( ) ; + + PreLoadScreenIndex )
{
if ( PreLoadScreens [ PreLoadScreenIndex ] - > GetPreLoadScreenType ( ) = = PreLoadScreenTypeToPlay )
{
PlayPreLoadScreenAtIndex ( PreLoadScreenIndex ) ;
return true ;
}
}
return false ;
}
void FPreLoadScreenManager : : PlayPreLoadScreenAtIndex ( int32 Index )
{
check ( IsInGameThread ( ) ) ;
if ( ArePreLoadScreensEnabled ( ) )
{
if ( ensureAlwaysMsgf ( ! HasValidActivePreLoadScreen ( ) , TEXT ( " Call to FPreLoadScreenManager::PlayPreLoadScreenAtIndex when something is already playing. " ) ) )
{
ActivePreLoadScreenIndex = Index ;
2023-10-25 21:39:35 -04:00
if ( HasValidActivePreLoadScreen ( ) )
{
FScopeLock PreloadScreenLock ( & ActivePreloadScreenCriticalSection ) ;
FPreLoadScreenManager : : ActivePreloadScreen = PreLoadScreens [ ActivePreLoadScreenIndex ] ;
}
2020-06-23 18:40:00 -04:00
if ( ensureAlwaysMsgf ( HasValidActivePreLoadScreen ( ) , TEXT ( " Call to FPreLoadScreenManager::PlayPreLoadScreenAtIndex with an invalid index! Nothing will play! " ) ) )
{
IPreLoadScreen * ActiveScreen = GetActivePreLoadScreen ( ) ;
if ( ActiveScreen - > GetPreLoadScreenType ( ) = = EPreLoadScreenTypes : : EarlyStartupScreen )
{
HandleEarlyStartupPlay ( ) ;
}
else if ( ActiveScreen - > GetPreLoadScreenType ( ) = = EPreLoadScreenTypes : : EngineLoadingScreen )
{
HandleEngineLoadingPlay ( ) ;
}
else if ( ActiveScreen - > GetPreLoadScreenType ( ) = = EPreLoadScreenTypes : : CustomSplashScreen )
{
HandleCustomSplashScreenPlay ( ) ;
}
else
{
UE_LOG ( LogPreLoadScreenManager , Fatal , TEXT ( " Attempting to play an Active PreLoadScreen type that hasn't been implemented inside of PreLoadScreenmanager! " ) ) ;
}
}
else
{
2023-10-25 21:39:35 -04:00
{
FScopeLock PreloadScreenLock ( & ActivePreloadScreenCriticalSection ) ;
FPreLoadScreenManager : : ActivePreloadScreen . Reset ( ) ;
}
2020-06-23 18:40:00 -04:00
ActivePreLoadScreenIndex = INDEX_NONE ;
}
}
2018-09-25 10:11:35 -04:00
}
}
bool FPreLoadScreenManager : : PlayPreLoadScreenWithTag ( FName InTag )
{
2020-06-23 18:40:00 -04:00
for ( int32 PreLoadScreenIndex = 0 ; PreLoadScreenIndex < PreLoadScreens . Num ( ) ; + + PreLoadScreenIndex )
2018-09-25 10:11:35 -04:00
{
if ( PreLoadScreens [ PreLoadScreenIndex ] - > GetPreLoadScreenTag ( ) = = InTag )
{
PlayPreLoadScreenAtIndex ( PreLoadScreenIndex ) ;
return true ;
}
}
return false ;
}
void FPreLoadScreenManager : : HandleEarlyStartupPlay ( )
{
2020-06-23 18:40:00 -04:00
if ( ensureAlwaysMsgf ( HasActivePreLoadScreenType ( EPreLoadScreenTypes : : EarlyStartupScreen ) , TEXT ( " Invalid Active PreLoadScreen! " ) ) )
{
IPreLoadScreen * PreLoadScreen = GetActivePreLoadScreen ( ) ;
if ( PreLoadScreen )
{
2019-02-27 11:57:17 -05:00
SCOPED_BOOT_TIMING ( " FPreLoadScreenManager::HandleEarlyStartupPlay() " ) ;
2020-05-05 03:44:38 -04:00
PreLoadScreen - > OnPlay ( MainWindow ) ;
2018-09-25 10:11:35 -04:00
2020-05-05 03:44:38 -04:00
{
2020-06-23 18:40:00 -04:00
TSharedPtr < SWindow > MainWindowPtr = MainWindow . Pin ( ) ;
2020-05-05 03:44:38 -04:00
if ( MainWindowPtr . IsValid ( ) & & PreLoadScreen - > GetWidget ( ) . IsValid ( ) )
{
MainWindowPtr - > SetContent ( PreLoadScreen - > GetWidget ( ) . ToSharedRef ( ) ) ;
}
}
2018-09-25 10:11:35 -04:00
bool bDidDisableScreensaver = false ;
if ( FPlatformApplicationMisc : : IsScreensaverEnabled ( ) )
{
bDidDisableScreensaver = FPlatformApplicationMisc : : ControlScreensaver ( FGenericPlatformApplicationMisc : : EScreenSaverAction : : Disable ) ;
}
2019-09-16 05:24:25 -04:00
FPlatformMisc : : HidePlatformStartupScreen ( ) ;
2019-09-12 14:34:11 -04:00
2019-02-27 11:57:17 -05:00
{
SCOPED_BOOT_TIMING ( " FPreLoadScreenManager::EarlyPlayFrameTick() " ) ;
//We run this PreLoadScreen until its finished or we lose the MainWindow as EarlyPreLoadPlay is synchronous
while ( ! PreLoadScreen - > IsDone ( ) )
{
EarlyPlayFrameTick ( ) ;
}
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( bDidDisableScreensaver )
{
FPlatformApplicationMisc : : ControlScreensaver ( FGenericPlatformApplicationMisc : : EScreenSaverAction : : Enable ) ;
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
StopPreLoadScreen ( ) ;
}
}
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : HandleEngineLoadingPlay ( )
{
2020-06-23 18:40:00 -04:00
if ( ensureAlwaysMsgf ( HasActivePreLoadScreenType ( EPreLoadScreenTypes : : EngineLoadingScreen ) , TEXT ( " Invalid Active PreLoadScreen! " ) ) )
{
IPreLoadScreen * PreLoadScreen = GetActivePreLoadScreen ( ) ;
if ( PreLoadScreen )
{
2024-08-01 11:52:04 -04:00
TSharedPtr < SWindow > MainWindowPtr = MainWindow . Pin ( ) ;
PreLoadScreen - > OnPlay ( MainWindowPtr ) ;
2018-09-25 10:11:35 -04:00
2024-06-27 08:50:09 -04:00
// The screen size may have changed between the VirtualRenderWindow creation and now
TOptional < UE : : Slate : : FDeprecateVector2DResult > NewScreenSize ;
2020-06-23 18:40:00 -04:00
if ( PreLoadScreen - > GetWidget ( ) . IsValid ( ) & & VirtualRenderWindow . IsValid ( ) )
{
VirtualRenderWindow - > SetContent ( PreLoadScreen - > GetWidget ( ) . ToSharedRef ( ) ) ;
2024-06-27 08:50:09 -04:00
2024-08-01 11:52:04 -04:00
if ( MainWindowPtr . IsValid ( ) )
2024-06-27 08:50:09 -04:00
{
2024-08-01 11:52:04 -04:00
const UE : : Slate : : FDeprecateVector2DResult CurrentScreenSize = MainWindowPtr - > GetClientSizeInScreen ( ) ;
if ( VirtualRenderWindow - > GetClientSizeInScreen ( ) ! = CurrentScreenSize )
{
NewScreenSize . Emplace ( CurrentScreenSize ) ;
VirtualRenderWindow - > SetCachedSize ( CurrentScreenSize ) ;
}
2024-06-27 08:50:09 -04:00
}
2020-06-23 18:40:00 -04:00
}
2021-11-18 14:37:34 -05:00
//Need to update bIsResponsibleForRendering as a PreLoadScreen may not have updated it before this point
if ( ! bIsResponsibleForRendering & & PreLoadScreen - > ShouldRender ( ) )
{
bIsResponsibleForRendering = true ;
IsResponsibleForRenderingDelegate . Broadcast ( bIsResponsibleForRendering ) ;
2024-06-27 08:50:09 -04:00
2024-08-01 11:52:04 -04:00
if ( NewScreenSize . IsSet ( ) & & FSlateApplication : : IsInitialized ( ) & & MainWindowPtr . IsValid ( ) ) //MainWindowPtr should be valid if we get there, but... better safe than sorry.
2024-06-27 08:50:09 -04:00
{
// Force the viewport to resize before rendering
2024-08-01 11:52:04 -04:00
FSlateApplication : : Get ( ) . GetRenderer ( ) - > UpdateFullscreenState ( MainWindowPtr . ToSharedRef ( ) , ( uint32 ) NewScreenSize . GetValue ( ) . X , ( uint32 ) NewScreenSize . GetValue ( ) . Y ) ;
2024-06-27 08:50:09 -04:00
}
2021-11-18 14:37:34 -05:00
}
2020-06-23 18:40:00 -04:00
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( WidgetRenderer . IsValid ( ) )
{
2023-10-25 21:39:35 -04:00
if ( SyncMechanism = = nullptr )
2020-06-23 18:40:00 -04:00
{
SyncMechanism = new FPreLoadScreenSlateSynchMechanism ( WidgetRenderer ) ;
SyncMechanism - > Initialize ( ) ;
}
}
}
2018-09-25 10:11:35 -04:00
}
2019-10-03 08:46:18 -04:00
void FPreLoadScreenManager : : HandleCustomSplashScreenPlay ( )
{
if ( ensureAlwaysMsgf ( HasActivePreLoadScreenType ( EPreLoadScreenTypes : : CustomSplashScreen ) , TEXT ( " Invalid Active PreLoadScreen! " ) ) )
{
IPreLoadScreen * PreLoadScreen = GetActivePreLoadScreen ( ) ;
if ( PreLoadScreen & & MainWindow . IsValid ( ) )
{
SCOPED_BOOT_TIMING ( " FPreLoadScreenManager::HandleCustomSplashScreenPlay() " ) ;
PreLoadScreen - > OnPlay ( MainWindow . Pin ( ) ) ;
if ( PreLoadScreen - > GetWidget ( ) . IsValid ( ) )
{
MainWindow . Pin ( ) - > SetContent ( PreLoadScreen - > GetWidget ( ) . ToSharedRef ( ) ) ;
}
bool bDidDisableScreensaver = false ;
if ( FPlatformApplicationMisc : : IsScreensaverEnabled ( ) )
{
bDidDisableScreensaver = FPlatformApplicationMisc : : ControlScreensaver ( FGenericPlatformApplicationMisc : : EScreenSaverAction : : Disable ) ;
}
FPlatformMisc : : HidePlatformStartupScreen ( ) ;
FPlatformMisc : : PlatformHandleSplashScreen ( false ) ;
while ( ! PreLoadScreen - > IsDone ( ) )
{
EarlyPlayFrameTick ( ) ;
}
if ( bDidDisableScreensaver )
{
FPlatformApplicationMisc : : ControlScreensaver ( FGenericPlatformApplicationMisc : : EScreenSaverAction : : Enable ) ;
}
StopPreLoadScreen ( ) ;
}
}
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : StaticRenderTick_RenderThread ( )
2018-09-25 10:11:35 -04:00
{
2023-09-04 05:49:26 -04:00
LLM_SCOPE ( ELLMTag : : RenderingThreadMemory ) ;
2020-06-23 18:40:00 -04:00
check ( IsInRenderingThread ( ) ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( ensure ( FPreLoadScreenManager : : Get ( ) ) ) // The manager should clear the slate render thread before closing
{
FPreLoadScreenManager : : Get ( ) - > RenderTick_RenderThread ( ) ;
}
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : RenderTick_RenderThread ( )
{
//Calculate tick time
const double CurrentTime = FPlatformTime : : Seconds ( ) ;
2024-01-16 11:15:58 -05:00
float DeltaTime = static_cast < float > ( CurrentTime - LastRenderTickTime ) ;
2020-06-23 18:40:00 -04:00
LastRenderTickTime = CurrentTime ;
2023-10-25 21:39:35 -04:00
FScopeLock PreloadScreenLock ( & ActivePreloadScreenCriticalSection ) ;
TSharedPtr < IPreLoadScreen > PinnedActivePreloadScreen = FPreLoadScreenManager : : ActivePreloadScreen . Pin ( ) ;
2020-06-23 18:40:00 -04:00
2023-10-25 21:39:35 -04:00
//Check if we have an active index before doing any work
if ( PinnedActivePreloadScreen & & bRenderingEnabled )
{
if ( MainWindow . IsValid ( ) & & VirtualRenderWindow . IsValid ( ) & & ! PinnedActivePreloadScreen - > IsDone ( ) )
2020-06-23 18:40:00 -04:00
{
GFrameNumberRenderThread + + ;
2023-10-25 21:39:35 -04:00
PinnedActivePreloadScreen - > RenderTick ( DeltaTime ) ;
2020-06-23 18:40:00 -04:00
GRHICommandList . GetImmediateCommandList ( ) . EndFrame ( ) ;
GRHICommandList . GetImmediateCommandList ( ) . ImmediateFlush ( EImmediateFlushType : : FlushRHIThreadFlushResources ) ;
}
}
2018-09-25 10:11:35 -04:00
}
bool FPreLoadScreenManager : : HasRegisteredPreLoadScreenType ( EPreLoadScreenTypes PreLoadScreenTypeToCheck ) const
{
bool HasMatchingRegisteredScreen = false ;
for ( const TSharedPtr < IPreLoadScreen > & Screen : PreLoadScreens )
{
if ( Screen . IsValid ( ) & & ( Screen - > GetPreLoadScreenType ( ) = = PreLoadScreenTypeToCheck ) )
{
HasMatchingRegisteredScreen = true ;
}
}
return HasMatchingRegisteredScreen ;
}
bool FPreLoadScreenManager : : HasActivePreLoadScreenType ( EPreLoadScreenTypes PreLoadScreenTypeToCheck ) const
{
return ( HasValidActivePreLoadScreen ( ) & & ( GetActivePreLoadScreen ( ) - > GetPreLoadScreenType ( ) = = PreLoadScreenTypeToCheck ) ) ;
}
bool FPreLoadScreenManager : : HasValidActivePreLoadScreen ( ) const
{
IPreLoadScreen * PreLoadScreen = nullptr ;
return ( PreLoadScreens . IsValidIndex ( ActivePreLoadScreenIndex ) & & PreLoadScreens [ ActivePreLoadScreenIndex ] . IsValid ( ) ) ;
}
IPreLoadScreen * FPreLoadScreenManager : : GetActivePreLoadScreen ( )
{
return HasValidActivePreLoadScreen ( ) ? PreLoadScreens [ ActivePreLoadScreenIndex ] . Get ( ) : nullptr ;
}
const IPreLoadScreen * FPreLoadScreenManager : : GetActivePreLoadScreen ( ) const
{
return HasValidActivePreLoadScreen ( ) ? PreLoadScreens [ ActivePreLoadScreenIndex ] . Get ( ) : nullptr ;
}
2020-06-23 18:40:00 -04:00
bool FPreLoadScreenManager : : HasActivePreLoadScreenTypeForEarlyStartup ( ) const
{
return HasActivePreLoadScreenType ( EPreLoadScreenTypes : : EarlyStartupScreen ) | | HasActivePreLoadScreenType ( EPreLoadScreenTypes : : CustomSplashScreen ) ;
}
2018-09-25 10:11:35 -04:00
void FPreLoadScreenManager : : EarlyPlayFrameTick ( )
{
2020-06-23 18:40:00 -04:00
if ( ensureAlwaysMsgf ( HasActivePreLoadScreenTypeForEarlyStartup ( ) , TEXT ( " EarlyPlayFrameTick called without a valid EarlyPreLoadScreen! " ) ) )
2018-09-25 10:11:35 -04:00
{
GameLogicFrameTick ( ) ;
EarlyPlayRenderFrameTick ( ) ;
}
}
void FPreLoadScreenManager : : GameLogicFrameTick ( )
{
IPreLoadScreen * ActivePreLoadScreen = GetActivePreLoadScreen ( ) ;
if ( ensureAlwaysMsgf ( ActivePreLoadScreen , TEXT ( " Invalid Active PreLoadScreen during GameLogicFameTick! " ) ) )
{
//First spin the platform by having it sleep a bit
const float SleepTime = ActivePreLoadScreen ? ActivePreLoadScreen - > GetAddedTickDelay ( ) : 0.f ;
if ( SleepTime > 0 )
{
FPlatformProcess : : Sleep ( SleepTime ) ;
}
double CurrentTime = FPlatformTime : : Seconds ( ) ;
2024-01-16 11:15:58 -05:00
float DeltaTime = static_cast < float > ( CurrentTime - LastTickTime ) ;
2018-09-25 10:11:35 -04:00
LastTickTime = CurrentTime ;
2019-04-16 19:58:10 -04:00
//Clamp to what should be more then any max reasonable time. This is to help with cases of
//backgrounding or setting breakpoints to trigger huge ticks
2024-01-16 11:15:58 -05:00
const float MaxTickTime = 5.0 ;
2019-04-16 19:58:10 -04:00
DeltaTime = FMath : : Min ( DeltaTime , MaxTickTime ) ;
2018-09-25 10:11:35 -04:00
//We have to manually tick everything as we are looping the main thread here
2020-01-13 13:19:16 -05:00
FTaskGraphInterface : : Get ( ) . ProcessThreadUntilIdle ( ENamedThreads : : GameThread ) ;
2021-08-16 11:09:22 -04:00
FTSTicker : : GetCoreTicker ( ) . Tick ( DeltaTime ) ;
2018-09-25 10:11:35 -04:00
FThreadManager : : Get ( ) . Tick ( ) ;
2019-04-17 22:56:58 -04:00
//Tick any platform specific things we need here
PlatformSpecificGameLogicFrameTick ( ) ;
2018-09-25 10:11:35 -04:00
//Tick the Active Screen
ActivePreLoadScreen - > Tick ( DeltaTime ) ;
// Pump messages to handle input , etc from system
FPlatformApplicationMisc : : PumpMessages ( true ) ;
FSlateApplication : : Get ( ) . PollGameDeviceState ( ) ;
// Gives widgets a chance to process any accumulated input
FSlateApplication : : Get ( ) . FinishedInputThisFrame ( ) ;
2020-01-29 15:33:37 -05:00
FSlateApplication : : Get ( ) . GetPlatformApplication ( ) - > Tick ( DeltaTime ) ;
2018-09-25 10:11:35 -04:00
//Needed as this won't be incrementing on its own and some other tick functions rely on this (like analytics)
GFrameCounter + + ;
}
}
2019-04-17 22:56:58 -04:00
void FPreLoadScreenManager : : PlatformSpecificGameLogicFrameTick ( )
{
# if PLATFORM_ANDROID
Android_PlatformSpecificGameLogicFrameTick ( ) ;
# endif //PLATFORM_ANDROID
# if PLATFORM_IOS
IOS_PlatformSpecificGameLogicFrameTick ( ) ;
# endif //PLATFORM_IOS
2018-09-25 10:11:35 -04:00
}
2019-01-08 11:38:48 -05:00
void FPreLoadScreenManager : : EnableRendering ( bool bEnabled )
2018-09-25 10:11:35 -04:00
{
2019-01-08 11:38:48 -05:00
bRenderingEnabled = bEnabled ;
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : EarlyPlayRenderFrameTick ( )
{
2023-10-25 03:22:47 -04:00
if ( ! bRenderingEnabled | | ! FSlateApplication : : IsInitialized ( ) )
{
// If rendering disabled, FPreLoadScreenManager is responsible for rendering but choosing not to, probably because the
// app is not in the foreground.
2023-10-25 21:39:35 -04:00
FPlatformProcess : : Sleep ( 0 ) ;
2023-10-25 03:22:47 -04:00
return ;
}
2019-07-22 11:49:15 -04:00
IPreLoadScreen * ActivePreLoadScreen = PreLoadScreens [ ActivePreLoadScreenIndex ] . Get ( ) ;
if ( ensureAlwaysMsgf ( ActivePreLoadScreen , TEXT ( " Invalid Active PreLoadScreen during EarlyPlayRenderFrameTick! " ) ) )
{
2023-10-25 21:39:35 -04:00
bool bIsResponsibleForRendering_Local = true ;
2019-07-22 11:49:15 -04:00
if ( ! ActivePreLoadScreen - > ShouldRender ( ) )
{
bIsResponsibleForRendering_Local = false ;
}
2018-09-25 10:11:35 -04:00
2019-07-22 11:49:15 -04:00
if ( bIsResponsibleForRendering_Local ! = bIsResponsibleForRendering )
{
bIsResponsibleForRendering = bIsResponsibleForRendering_Local ;
IsResponsibleForRenderingDelegate . Broadcast ( bIsResponsibleForRendering ) ;
}
2018-09-25 10:11:35 -04:00
2019-07-22 11:49:15 -04:00
if ( bIsResponsibleForRendering_Local )
{
FSlateApplication & SlateApp = FSlateApplication : : Get ( ) ;
2023-10-25 03:22:47 -04:00
float SlateDeltaTime = SlateApp . GetDeltaTime ( ) ;
2023-10-09 17:06:43 -04:00
2023-10-25 21:39:35 -04:00
//Setup Slate Render Command
ENQUEUE_RENDER_COMMAND ( BeginPreLoadScreenFrame ) (
[ this , SlateDeltaTime ] ( FRHICommandListImmediate & RHICmdList )
{
FScopeLock PreloadScreenLock ( & ActivePreloadScreenCriticalSection ) ;
TSharedPtr < IPreLoadScreen > PinnedActivePreloadScreen = FPreLoadScreenManager : : ActivePreloadScreen . Pin ( ) ;
2023-10-25 03:22:47 -04:00
2023-10-25 21:39:35 -04:00
// this is still valid because we do a FlushRenderingCommands in StopPreLoadScreen
if ( FPreLoadScreenManager : : bRenderingEnabled & & PinnedActivePreloadScreen & & ! bHasRenderPreLoadScreenFrame_RenderThread )
2023-10-25 03:22:47 -04:00
{
2023-10-25 21:39:35 -04:00
GFrameNumberRenderThread + + ;
2023-10-25 03:22:47 -04:00
2023-10-25 21:39:35 -04:00
bHasRenderPreLoadScreenFrame_RenderThread = true ;
PinnedActivePreloadScreen - > RenderTick ( SlateDeltaTime ) ;
}
} ) ;
2023-10-25 03:22:47 -04:00
2023-10-25 21:39:35 -04:00
SlateApp . Tick ( ) ;
2023-10-25 03:22:47 -04:00
2023-10-25 21:39:35 -04:00
// Synchronize the game thread and the render thread so that the render thread doesn't get too far behind.
SlateApp . GetRenderer ( ) - > Sync ( ) ;
2023-10-25 03:23:02 -04:00
2023-10-25 21:39:35 -04:00
ENQUEUE_RENDER_COMMAND ( FinishPreLoadScreenFrame ) (
[ this ] ( FRHICommandListImmediate & RHICmdList )
{
// this is still valid because we do a FlushRenderingCommands in StopPreLoadScreen
bHasRenderPreLoadScreenFrame_RenderThread = false ;
GRHICommandList . GetImmediateCommandList ( ) . EndFrame ( ) ;
GRHICommandList . GetImmediateCommandList ( ) . ImmediateFlush ( EImmediateFlushType : : FlushRHIThreadFlushResources ) ;
} ) ;
2019-07-22 11:49:15 -04:00
}
}
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : StopPreLoadScreen ( )
{
2020-06-23 18:40:00 -04:00
check ( IsInGameThread ( ) ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
if ( HasValidActivePreLoadScreen ( ) )
{
if ( ensureMsgf ( HasActivePreLoadScreenTypeForEarlyStartup ( ) , TEXT ( " WaitForEngineLoadingScreenToFinish should be called when using an EngineLoadingScreen. " ) ) )
{
HandleStopPreLoadScreen ( ) ;
}
2020-08-11 01:36:57 -04:00
2023-10-25 21:39:35 -04:00
FlushRenderingCommands ( ) ;
2020-06-23 18:40:00 -04:00
}
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
void FPreLoadScreenManager : : HandleStopPreLoadScreen ( )
{
{
if ( HasValidActivePreLoadScreen ( ) )
{
PreLoadScreens [ ActivePreLoadScreenIndex ] - > OnStop ( ) ;
}
2023-10-25 21:39:35 -04:00
{
FScopeLock PreloadScreenLock ( & ActivePreloadScreenCriticalSection ) ;
FPreLoadScreenManager : : ActivePreloadScreen . Reset ( ) ;
}
2020-06-23 18:40:00 -04:00
ActivePreLoadScreenIndex = - 1 ;
//Clear our window content
if ( MainWindow . IsValid ( ) )
{
MainWindow . Pin ( ) - > SetContent ( SNullWidget : : NullWidget ) ;
}
if ( VirtualRenderWindow . IsValid ( ) )
{
VirtualRenderWindow - > SetContent ( SNullWidget : : NullWidget ) ;
}
}
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : PassPreLoadScreenWindowBackToGame ( ) const
{
2023-10-25 21:39:35 -04:00
if ( IsUsingMainWindow ( ) )
{
UGameEngine * GameEngine = Cast < UGameEngine > ( GEngine ) ;
if ( MainWindow . IsValid ( ) & & GameEngine )
{
GameEngine - > GameViewportWindow = MainWindow ;
}
else
{
UE_LOG ( LogPreLoadScreenManager , Warning , TEXT ( " FPreLoadScreenManager::PassLoadingScreenWindowBackToGame failed. No Window " ) ) ;
}
}
2018-09-25 10:11:35 -04:00
}
bool FPreLoadScreenManager : : IsUsingMainWindow ( ) const
{
2023-10-25 21:39:35 -04:00
return MainWindow . IsValid ( ) ;
2018-09-25 10:11:35 -04:00
}
TSharedPtr < SWindow > FPreLoadScreenManager : : GetRenderWindow ( )
{
2023-10-25 21:39:35 -04:00
return MainWindow . IsValid ( ) ? MainWindow . Pin ( ) : nullptr ;
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : WaitForEngineLoadingScreenToFinish ( )
{
2020-06-23 18:40:00 -04:00
check ( IsInGameThread ( ) ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
//Start just doing game logic ticks until the Screen is finished.
//Since this is a non-early screen, rendering happens separately still on the Slate rendering thread, so only need
//the game logic ticks
if ( HasActivePreLoadScreenType ( EPreLoadScreenTypes : : EngineLoadingScreen ) )
{
IPreLoadScreen * ActivePreLoadScreen = GetActivePreLoadScreen ( ) ;
while ( ActivePreLoadScreen & & ! ActivePreLoadScreen - > IsDone ( ) )
{
GameLogicFrameTick ( ) ;
}
}
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
//No longer need SyncMechanism now that the widget has finished rendering
if ( SyncMechanism ! = nullptr )
{
SyncMechanism - > DestroySlateThread ( ) ;
2018-09-25 10:11:35 -04:00
2020-06-23 18:40:00 -04:00
delete SyncMechanism ;
SyncMechanism = nullptr ;
}
HandleStopPreLoadScreen ( ) ;
2018-09-25 10:11:35 -04:00
}
void FPreLoadScreenManager : : SetEngineLoadingComplete ( bool IsEngineLoadingFinished )
{
bIsEngineLoadingComplete = IsEngineLoadingFinished ;
IPreLoadScreen * PreLoadScreen = GetActivePreLoadScreen ( ) ;
if ( PreLoadScreen )
{
PreLoadScreen - > SetEngineLoadingFinished ( IsEngineLoadingFinished ) ;
}
}
bool FPreLoadScreenManager : : ArePreLoadScreensEnabled ( )
{
bool bEnabled = ! GIsEditor & & ! IsRunningDedicatedServer ( ) & & ! IsRunningCommandlet ( ) & & GUseThreadedRendering ;
# if !UE_BUILD_SHIPPING
bEnabled & = ! FParse : : Param ( FCommandLine : : Get ( ) , TEXT ( " NoLoadingScreen " ) ) ;
# endif
# if PLATFORM_UNIX
bEnabled = false ;
# endif
return bEnabled ;
}
void FPreLoadScreenManager : : CleanUpResources ( )
{
2020-06-23 18:40:00 -04:00
// Since we are on the game thread, the PreLoadScreen must be completed.
//But if we are in EngineLoadingScreen, then the thread may be still active if WaitForEngineLoadingScreenToFinish was not called.
bool bHasActiPreLoadScreen = HasValidActivePreLoadScreen ( ) ;
ensureMsgf ( ! bHasActiPreLoadScreen , TEXT ( " StopPreLoadScreen or WaitForEngineLoadingScreenToFinish (if EngineLoadingScreen) should be called before we destroy the Screen Manager. " ) ) ;
if ( SyncMechanism )
{
SyncMechanism - > DestroySlateThread ( ) ;
delete SyncMechanism ;
SyncMechanism = nullptr ;
}
2018-09-25 10:11:35 -04:00
for ( TSharedPtr < IPreLoadScreen > & PreLoadScreen : PreLoadScreens )
{
if ( PreLoadScreen . IsValid ( ) )
{
PreLoadScreen - > CleanUp ( ) ;
}
PreLoadScreen . Reset ( ) ;
}
OnPreLoadScreenManagerCleanUp . Broadcast ( ) ;
//Make sure our FPreLoadSettingsContainer is cleaned up. We do this here instead of one of the
//StartupScreens because we don't know how many of them will be using the same PreLoadScreenContainer, however any
//other game specific settings containers should be cleaned up by their screens/modules
BeginCleanup ( & FPreLoadSettingsContainerBase : : Get ( ) ) ;
}
2019-04-17 22:56:58 -04:00
# if PLATFORM_ANDROID
void FPreLoadScreenManager : : Android_PlatformSpecificGameLogicFrameTick ( )
{
# if USE_ANDROID_EVENTS
// Process any Android events or we may have issues returning from background
FAppEventManager : : GetInstance ( ) - > Tick ( ) ;
# endif //USE_ANDROIID_EVENTS
}
# endif //PLATFORM_ANDROID
# if PLATFORM_IOS
void FPreLoadScreenManager : : IOS_PlatformSpecificGameLogicFrameTick ( )
{
// drain the async task queue from the game thread
[ FIOSAsyncTask ProcessAsyncTasks ] ;
}
2020-06-23 18:40:00 -04:00
# endif //PLATFORM_IOS