foreword
-
Current version: 4.26.2
-
Explanation: It may be easier to understand some nouns in English
-
Table of contents
-
Game flow overview
-
The entry function of each platform startup engine
-
Engine entry function GuardedMain()
-
EnginePreInit engine pre-initialization
-
EngineInit engine initialization
-
EngineLoop engine main loop
-
EngineExit engine exit
-
Game flow overview
-
Explains the process of enabling the engine and running the game.
-
Two main paths are illustrated here: the editor path, and the standalone path.
-
The general sequence of events is to initialize the engine, create and initialize a GameInstance, load the level, and finally start the game. However, there are differences between standalone mode and editor mode in terms of the exact ordering of partially called functions and where functions are called. The following flowchart shows two paths running in parallel, which converge before the game starts.
The entry function of each platform startup engine
-
code path:
Engine\Source\Runtime\Launch\Private\
-
As an entry function, then enter the engine's entry function GuardedMain. As shown below
Engine entry function GuardedMain()
-
code path:
Runtime/Launch/Private/Launch.cpp
-
Execute the four stages of the engine process: EnginePreInit, EngineInit, EngineLoop, EngineExit. The execution flow chart is as follows
EnginePreInit engine pre-initialization
actually call FEngineLoop::PreInit
, and then call PreInitPreStartupScreen
and PreInitPostStartupScreen
, so as to achieve many initialization and core module related things
Execution flow in PreInitPreStartupScreen
-
Perform various initializations first, such as parsing command parameters, trace, stat (performance analysis tool), FModuleManager, IFileManager, FPlatformFileManager, various paths, etc.
-
Load the CoreUObject module and start FTaskGraphInterface
-
via LoadPreInitModules()
-
Load Engine, Renderer, AnimGraphRuntime modules
-
Load D3D12RHI, D3D11RHI, OpenGLDrv and other modules through FPlatformApplicationMisc::LoadPreInitModules() (according to the platform)
-
Load the SlateRHIRenderer module (under non-server)
-
Load Landscape, RenderCore modules
-
Load TextureCompressor, AudioEditor, AnimationModifiers modules
-
-
via FEngineLoop::AppInit()
- localized text
- Init logging to disk
- init config system
- Load Engine, Game, Input configuration files through FConfigCacheIni::LoadGlobalIniFile
- Other configuration files include: Editor, EditorPerProjectUserSettings, EditorSettings, EditorKeyBindings, EditorLayout, Lightmass, Scalability, Hardware, DeviceProfiles, GameUserSettings, etc.
- Load "asap" plugin modules, load modules of type EarliestPossible for projects and plugins
- Check project and plugin module data, whether compilation is required
- Load modules of type PostConfigInit for projects and plugins
- Initialize the headset PreInitHMDDevice();
- print initialization log
- Initialize other systems
FCoreDelegates::OnInit.Broadcast();
-
Set the game main thread
-
Thread pool initialization (if multithreading is supported)
-
Asynchronous IO system initialization (if multithreading is supported)
-
System settings system settings and cvar initialization, cvar is obtained from the ini file, including rendering parameters, resolution, window mode, etc.
-
Scalability system initialization
InitScalabilitySystem()
-
rendering thread
UseRenderThread()
-
Platform-specific initialization such as
FPlatformMisc::PlatformInit()
,FPlatformApplicationMisc::Init()
,FPlatformMemory::Init()
-
IPlatformFeaturesModule::Get()
-
Physics engine initialization
InitGamePhys()
-
Engine localization initialization
InitEngineTextLocalization()
-
Start the audio thread
UseAudioThread()
-
Startup screen display
FPlatformSplash::Show();
-
Platform application creation
FSlateApplication::Create()
; EKeys::Initialize(), FCoreStyle::ResetToDefault() in server mode -
RHI initialization
RHIInit()
-
RenderUtils initialization
RenderUtilsInit()
-
FShaderCodeLibrary::InitForRuntime()
-
FShaderPipelineCache::Initialize()
-
Shader hash cache: InitializeShaderHashCache()
-
GetRendererModule
-
InitializeShaderTypes
-
CompileGlobalShaderMap
-
CreateMoviePlayer
-
etc
Execution flow in PreInitPostStartupScreen
- Play startup animation
GetMoviePlayer()->SetupLoadingScreenFromIni()
- Loading project modules of type PreEarlyLoadingScreen
- Create the window by
FPreLoadScreenManager::Get()->Initialize()
callingUGameEngine::CreateGameWindow();
- Create the window by
- Pak file fetching and mounting
- Config file acquisition and parameter reading
- SlateRenderer initialization
- Load the AssetRegistry module
- UObject classes registration and initialization
- PIEPreviewDeviceProfileSelector
- InitDefaultMaterials
- Initialize the texture streaming system
- Load the core startup module LoadStartupCoreModules, including
- Core、Networking、Messaging
- MRMesh、UnrealEd、EditorStyle、LandscapeEditorUtilities
- SlateCore、Slate、SlateReflector、UMG
- MessageLog、CollisionAnalyzer、FunctionalTesting
- BehaviorTreeEditor、GameplayTasksEditor、StringTableEditor、VREditor、IntroTutorials、Blutility
- Overlay、MediaAssets、ClothingSystemRuntimeNv、ClothingSystemEditor、PacketHandler、NetworkReplayStreaming
- Load modules of type PreDefault, Default, PostDefault through LoadStartupModules
- Load a module of type PreLoadingScreen
- Load modules of type PostEngineInit for projects and plugins
- Online module
- etc
EngineInit engine initialization
execute GEngineLoop.Init()
. If the editor will execute EditorInit()
, in essence, GEngineLoop.Init()
after the execution of the event, some resources of the Editor will be loaded
GEngineLoop.Init()
The analysis is mainly based on the Game non-editor mode
- Non-editor mode:
GEngine = NewObject<UEngine>(GetTransientPackage(), EngineClass);
Editor mode:GEngine = GEditor = GUnrealEd = NewObject<UUnrealEdEngine>(GetTransientPackage(), EngineClass);
- GEngine->Init()
- UGameEngine::Init() non-editor mode
UEngine::Init()
- Subsystem initialization
EngineSubsystemCollection.Initialize(this);
- Head-mounted display device initialization
InitializeHMDDevice();
- Eye Tracking Device Initialization
InitializeEyeTrackingDevice();
- FSlateSoundDevice
- load engine class
LoadObject<UClass>(UEngine::StaticClass()->GetOuter()...
- Engine. ini
LoadConfig();
- Initialize the Object reference
InitializeObjectReferences();
- for editor
CreateNewWorldContext()
InitializeAudioDeviceManager();
- Something related to networking
- Initialise buffer visualization system data
GetBufferVisualizationData().Initialize();
FEngineAnalytics::Initialize();
- 加载引擎 runtime modules:ImageWriteQueue、StreamingPauseRendering、MovieScene、MovieSceneTracks、LevelSequence
- Finish asset manager loading
AssetManager->FinishInitialLoading();
RecordHMDAnalytics();
- Subsystem initialization
GetGameUserSettings()->LoadSettings();
GetGameUserSettings()->ApplyNonResolutionSettings();
- Create game instance
GameInstance = NewObject<UGameInstance>(this, GameInstanceClass);
GameInstance->InitializeStandalone();
- CreateNewWorldContext GameInstance->Init();
OnlineSession = NewObject<UOnlineSession>(this, SpawnClass);
OnlineSession->RegisterOnlineDelegates();
SubsystemCollection.Initialize(this);
- Initialize viewport client
- UGameEngine::Init() non-editor mode
- Load a module of type PostEngineInit
- GEngine->Start()
- UGameEngine::Start() non-editor mode
GameInstance->StartGameInstance();
const UGameMapsSettings* GameMapsSettings = GetDefault<UGameMapsSettings>();
const FString& DefaultMap = GameMapsSettings->GetGameDefaultMap();
Engine->Browse()
server relatedUEngine->LoadMap
- Do some cleaning work, Unload the current world, display the loading screen, clean up the network, etc.
LoadPackage()
, load level- Set new world, CurrentWorld
WorldContext.SetCurrentWorld(NewWorld);
WorldContext.World()->WorldType = WorldContext.WorldType;
WorldContext.World()->InitWorld();
InitializeSubsystems()
FWorldDelegates::OnPreWorldInitialization.Broadcast(this, IVS);
AWorldSettings* WorldSettings = GetWorldSettings();
CreatePhysicsScene(WorldSettings);
CreateAISystem();
SetupParameterCollectionInstances();
Levels.Add( PersistentLevel );
- Some settings of the physical properties of the scene, such as gravity, collision
- Some network related such as NetDriver, listen, etc.
WorldContext.World()->SetGameMode();
GShaderCompilingManager->ProcessAsyncResults()
WorldContext.World()->CreateAISystem();
WorldContext.World()->InitializeActorsForPlay();
FNavigationSystem::AddNavigationSystemToWorld()
SpawnPlayActor()
WorldContext.World()->BeginPlay();
GameMode->StartPlay();
GameState->HandleBeginPlay();
GetWorldSettings()->NotifyBeginPlay();
Call BeginPlay() for each Actor,FActorIterator It(World); It->DispatchBeginPlay(bFromLevelLoad);
GetWorldSettings()->NotifyMatchStarted();
GetAISystem()->StartPlay();
PhysicsScene->OnWorldBeginPlay();
WorldContext.World()->bWorldWasLoadedThisTick = true;
WorldContext.OwningGameInstance->LoadComplete();
- UGameEngine::Start() non-editor mode
WaitForEngineLoadingScreenToFinish()
WaitForMovieToFinish()
- 加载模块: Media、AutomationWorker、AutomationController、ProfilerClient 、SequenceRecorder、SequenceRecorderSections
- thread heartbeat package
FThreadHeartBeat::Get().Start();
- external analyzer
- etc
editorInit()
Executed after calling GEngineLoop.Init()
- Some command lines, notifications, messages, logs, ui, etc. registration
- Load the level startup map
- Process global shader results before we try to render anything
- InitEngineAnalytics
- etc
EngineLoop engine main loop
Execute FEngineLoop::Tick()
TickRenderingTickables();
Make sure something is ticking the rendering tickables in -onethread mode to avoid leaks/bugs.ActiveProfiler->FrameSync();
External Analyzer Frame SynchronizationFCoreDelegates::OnBeginFrame.Broadcast();
GLog->FlushThreadedLogs();
Refresh thread logFlushRenderingCommands()
Render Command UpdateScene->UpdateAllPrimitiveSceneInfos()
BeginFrameRenderThread()
beginning of RHI frameScene->StartFrame();
FlushPendingDeleteRHIResources_RenderThread();
Some tasks in the rendering thread that require frame processing- Some stats related things
GEngine->Tick()
main game engine tick (world, game objects, etc.)- log update
CleanupGameViewport();
- Update subsystems
- tick() update for FEngineAnalytics, FStudioAnalytics
Context.World()->Tick()
USkyLightComponent::UpdateSkyCaptureContents(Context.World());
UReflectionCaptureComponent::UpdateReflectionCaptureContents(Context.World());
- ULocalPlayer processing
- LevelStreaming processing
FTickableGameObject::TickObjects()
MediaModule->TickPostEngine();
- GameViewport->Tick(DeltaSeconds);
- RedrawViewports();
Render everything. - IStreamingManager、GameAudioDeviceManager 更新
- Rendering thread commands related updates GRenderingRealtimeClock, GRenderTargetPool, FRDGBuilder, ICustomResourcePool
GShaderCompilingManager->ProcessAsyncResults(true, false);
GDistanceFieldAsyncQueue->ProcessAsyncTasks();
MediaModule->TickPreSlate();
tick media framework- slate tick and task
- ReplicatedProperties property synchronization
- FTaskGraphInterface processing of some parallel tasks
RHITick()
- frame count, frame interval
- Objects next frame recovery ratio mark
- FrameEndSync frame end synchronization event
EndFrameRenderThread()
FCoreDelegates::OnEndFrame.Broadcast();
EngineExit engine exit
-
Execution
GEngineLoop.Exit()
, mainly to close and release the various modules of the engine, see the source code for details -
last call
FEngineLoop::AppExit()
; exit the application -
source code
void FEngineLoop::Exit() { STAT_ADD_CUSTOMMESSAGE_NAME( STAT_NamedMarker, TEXT( "EngineLoop.Exit" ) ); TRACE_BOOKMARK(TEXT("EngineLoop.Exit")); GIsRunning = 0; GLogConsole = nullptr; IInstallBundleManager::InstallBundleCompleteDelegate.RemoveAll(this); // shutdown visual logger and flush all data #if ENABLE_VISUAL_LOG FVisualLogger::Get().Shutdown(); #endif // Make sure we're not in the middle of loading something. { bool bFlushOnExit = true; if (GConfig) { FBoolConfigValueHelper FlushStreamingOnExitHelper(TEXT("/Script/Engine.StreamingSettings"), TEXT("s.FlushStreamingOnExit"), GEngineIni); bFlushOnExit = FlushStreamingOnExitHelper; } if (bFlushOnExit) { FlushAsyncLoading(); } else { CancelAsyncLoading(); } } // Block till all outstanding resource streaming requests are fulfilled. if (!IStreamingManager::HasShutdown()) { UTexture2D::CancelPendingTextureStreaming(); IStreamingManager::Get().BlockTillAllRequestsFinished(); } #if WITH_ENGINE // shut down messaging delete EngineService; EngineService = nullptr; if (SessionService.IsValid()) { SessionService->Stop(); SessionService.Reset(); } if (GDistanceFieldAsyncQueue) { GDistanceFieldAsyncQueue->Shutdown(); delete GDistanceFieldAsyncQueue; } #endif // WITH_ENGINE if ( GEngine != nullptr ) { GEngine->ReleaseAudioDeviceManager(); } if ( GEngine != nullptr ) { GEngine->PreExit(); } FAudioDeviceManager::Shutdown(); // close all windows FSlateApplication::Shutdown(); #if !UE_SERVER if ( FEngineFontServices::IsInitialized() ) { FEngineFontServices::Destroy(); } #endif #if WITH_EDITOR // These module must be shut down first because other modules may try to access them during shutdown. // Accessing these modules at shutdown causes instability since the object system will have been shut down and these modules uses uobjects internally. FModuleManager::Get().UnloadModule("AssetTools", true); #endif // WITH_EDITOR FModuleManager::Get().UnloadModule("WorldBrowser", true); FModuleManager::Get().UnloadModule("AssetRegistry", true); #if !PLATFORM_ANDROID || PLATFORM_LUMIN // AppPreExit doesn't work on Android AppPreExit(); TermGamePhys(); ParticleVertexFactoryPool_FreePool(); #else // AppPreExit() stops malloc profiler, do it here instead MALLOC_PROFILER( GMalloc->Exec(nullptr, TEXT("MPROF STOP"), *GLog); ); #endif // !ANDROID // Stop the rendering thread. StopRenderingThread(); // Disable the PSO cache FShaderPipelineCache::Shutdown(); // Close shader code map, if any FShaderCodeLibrary::Shutdown(); #if !PLATFORM_ANDROID || PLATFORM_LUMIN // UnloadModules doesn't work on Android #if WITH_ENGINE // Save the hot reload state IHotReloadInterface* HotReload = IHotReloadInterface::GetPtr(); if(HotReload != nullptr) { HotReload->SaveConfig(); } #endif // Unload all modules. Note that this doesn't actually unload the module DLLs (that happens at // process exit by the OS), but it does call ShutdownModule() on all loaded modules in the reverse // order they were loaded in, so that systems can unregister and perform general clean up. FModuleManager::Get().UnloadModulesAtShutdown(); #endif // !ANDROID IStreamingManager::Shutdown(); // Tear down the RHI. RHIExitAndStopRHIThread(); DestroyMoviePlayer(); // Move earlier? #if STATS FThreadStats::StopThread(); #endif FTaskGraphInterface::Shutdown(); FPlatformMisc::ShutdownTaggedStorage(); TRACE_CPUPROFILER_SHUTDOWN(); }
reference
- The original address of this article [UE4] Unreal Engine running process - Di Cairen - Blog Park
- Game flow overview
- \UE_4.26\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp
- \UE_4.26\Engine\Source\Runtime\Launch\Private\Launch.cpp
- \UE_4.26\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp
- \UE_4.26\Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp
- \UE_4.26\Engine\Source\Runtime\Engine\Private\GameEngine.cpp
- \UE_4.26\Engine\Source\Editor\UnrealEd\Private\UnrealEdGlobals.cpp
- \UE_4.26\Engine\Source\Runtime\Engine\Private\GameEngine.cpp