【UE4】虚幻引擎运行流程
前言
-
当前版本:4.26.2
-
说明:有些名词保持英文可能更容易理解
-
目录
-
游戏流程总览
-
各个平台启动引擎的入口函数
-
引擎入口函数 GuardedMain()
-
EnginePreInit 引擎预初始化
-
EngineInit 引擎初始化
-
EngineLoop 引擎主循环
-
EngineExit 引擎退出
-
游戏流程总览
-
解释启用引擎和运行游戏的过程。
-
此处说明两种主要路径:编辑器路径、standalone 路径。
-
事件的一般顺序为初始化引擎、创建并初始化 GameInstance、加载关卡,最后开始游戏。然而在部分被调用函数的准确排序和函数被调用的位置方面,standalone 模式和编辑器模式之间存在差异。以下流程图展示两个平行运行的路径,它们在游戏开始之前汇聚。
各个平台启动引擎的入口函数
-
代码路径:
Engine\Source\Runtime\Launch\Private\
-
作为入口函数,然后进入引擎的入口函数GuardedMain。如下图所示
引擎入口函数 GuardedMain()
-
代码路径:
Runtime/Launch/Private/Launch.cpp
-
执行引擎四大阶段的流程:EnginePreInit 、EngineInit 、EngineLoop、EngineExit 。执行流程图如下所示
EnginePreInit 引擎预初始化
实际上调用 FEngineLoop::PreInit
,再调用 PreInitPreStartupScreen
和 PreInitPostStartupScreen
,从而实现许多初始化和核心模块相关的事情
PreInitPreStartupScreen 里的执行流程
-
先进行各种初始化,如解析command参数、trace、stat(性能分析工具)、FModuleManager、IFileManager、FPlatformFileManager、各种路径等
-
加载CoreUObject模块,启动FTaskGraphInterface
-
通过LoadPreInitModules()
-
加载 Engine、Renderer、AnimGraphRuntime 模块
-
通过 FPlatformApplicationMisc::LoadPreInitModules()加载 D3D12RHI、D3D11RHI、OpenGLDrv等模块(根据所在平台)
-
加载 SlateRHIRenderer模块(非服务器下)
-
加载 Landscape、RenderCore 模块
-
加载 TextureCompressor、AudioEditor、AnimationModifiers 模块
-
-
通过 FEngineLoop::AppInit() 进行
- 本地化文本
- Init logging to disk
- init config system
- 通过 FConfigCacheIni::LoadGlobalIniFile 加载Engine、Game、Input 配置文件
- 其他配置文件还有:Editor、EditorPerProjectUserSettings、EditorSettings、EditorKeyBindings、EditorLayout、Lightmass、Scalability、Hardware、DeviceProfiles、GameUserSettings等
- Load "asap" plugin modules,为项目和插件加载类型为 EarliestPossible 的模块
- 检查项目和插件模块数据,是否需要编译
- 为项目和插件加载类型为 PostConfigInit 的模块
- 初始化头显 PreInitHMDDevice();
- 打印初始化日志
- 初始化其他系统
FCoreDelegates::OnInit.Broadcast();
-
设置游戏主线程
-
线程池初始化(如果支持多线程)
-
异步IO系统初始化(如果支持多线程)
-
系统设置system settings和 cvar 初始化,cvar从 ini 文件获取,含渲染参数、分辨率、窗口模式等
-
Scalability系统初始化
InitScalabilitySystem()
-
渲染线程
UseRenderThread()
-
平台特定的初始化,如
FPlatformMisc::PlatformInit()
、FPlatformApplicationMisc::Init()
、FPlatformMemory::Init()
-
IPlatformFeaturesModule::Get()
-
物理引擎初始化
InitGamePhys()
-
引擎本地化初始化
InitEngineTextLocalization()
-
开启音频线程
UseAudioThread()
-
启动界面显示
FPlatformSplash::Show();
-
平台应用程序创建
FSlateApplication::Create()
;服务器模式下EKeys::Initialize()、FCoreStyle::ResetToDefault(); -
RHI 初始化
RHIInit()
-
RenderUtils初始化
RenderUtilsInit()
-
FShaderCodeLibrary::InitForRuntime()
-
FShaderPipelineCache::Initialize()
-
Shader hash cache: InitializeShaderHashCache()
-
GetRendererModule
-
InitializeShaderTypes
-
CompileGlobalShaderMap
-
CreateMoviePlayer
-
etc
PreInitPostStartupScreen 里的执行流程
- 播放启动动画
GetMoviePlayer()->SetupLoadingScreenFromIni()
- 加载PreEarlyLoadingScreen类型的项目模块
- 通过
FPreLoadScreenManager::Get()->Initialize()
调用UGameEngine::CreateGameWindow();
创建窗口
- 通过
- Pak 文件获取和挂载
- Config 文件获取和参数读取
- SlateRenderer 初始化
- 加载 AssetRegistry 模块
- UObject classes 注册和初始化
- PIEPreviewDeviceProfileSelector
- InitDefaultMaterials
- Initialize the texture streaming system
- 加载核心启动模块 LoadStartupCoreModules,包括
- 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
- 通过LoadStartupModules 加载PreDefault、Default、PostDefault类型的模块
- 加载 PreLoadingScreen 类型的模块
- 为项目和插件加载 PostEngineInit 类型的模块
- Online模块
- etc
EngineInit 引擎初始化
执行GEngineLoop.Init()
。如果事编辑器会执行 EditorInit()
,本质上事执行 GEngineLoop.Init()
后再进行Editor 的一些资源加载
GEngineLoop.Init()
分析主要以Game非编辑器模式为主
- 非编辑器模式:
GEngine = NewObject<UEngine>(GetTransientPackage(), EngineClass);
编辑器模式:GEngine = GEditor = GUnrealEd = NewObject<UUnrealEdEngine>(GetTransientPackage(), EngineClass);
- GEngine->Init()
- UGameEngine::Init() 非编辑器模式
UEngine::Init()
- Subsystems 初始化
EngineSubsystemCollection.Initialize(this);
- 头显设备初始化
InitializeHMDDevice();
- 眼动追踪设备初始化
InitializeEyeTrackingDevice();
- FSlateSoundDevice
- 加载引擎类
LoadObject<UClass>(UEngine::StaticClass()->GetOuter()...
- Engine.ini
LoadConfig();
- 初始化 Object 引用
InitializeObjectReferences();
- 为编辑器
CreateNewWorldContext()
InitializeAudioDeviceManager();
- networking 相关的一些东西
- Initialise buffer visualization system data
GetBufferVisualizationData().Initialize();
FEngineAnalytics::Initialize();
- 加载引擎 runtime modules:ImageWriteQueue、StreamingPauseRendering、MovieScene、MovieSceneTracks、LevelSequence
- Finish asset manager loading
AssetManager->FinishInitialLoading();
RecordHMDAnalytics();
- Subsystems 初始化
GetGameUserSettings()->LoadSettings();
GetGameUserSettings()->ApplyNonResolutionSettings();
- 创建 game instance
GameInstance = NewObject<UGameInstance>(this, GameInstanceClass);
GameInstance->InitializeStandalone();
—— CreateNewWorldContext GameInstance->Init();
OnlineSession = NewObject<UOnlineSession>(this, SpawnClass);
OnlineSession->RegisterOnlineDelegates();
SubsystemCollection.Initialize(this);
- 初始化 viewport client
- UGameEngine::Init() 非编辑器模式
- 加载 PostEngineInit 类型的模块
- GEngine->Start()
- UGameEngine::Start() 非编辑器模式
GameInstance->StartGameInstance();
const UGameMapsSettings* GameMapsSettings = GetDefault<UGameMapsSettings>();
const FString& DefaultMap = GameMapsSettings->GetGameDefaultMap();
Engine->Browse()
服务器相关UEngine->LoadMap
- 做一些清理工作,Unload 当前world、显示loading screen、清理 networking等
LoadPackage()
,加载level- 设置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 );
- 场景物理特性的一些设置,如重力、碰撞
- 一些网络相关如 NetDriver、listen 等
WorldContext.World()->SetGameMode();
GShaderCompilingManager->ProcessAsyncResults()
WorldContext.World()->CreateAISystem();
WorldContext.World()->InitializeActorsForPlay();
FNavigationSystem::AddNavigationSystemToWorld()
SpawnPlayActor()
WorldContext.World()->BeginPlay();
GameMode->StartPlay();
GameState->HandleBeginPlay();
GetWorldSettings()->NotifyBeginPlay();
为每个Actor调用BeginPlay(),FActorIterator It(World); It->DispatchBeginPlay(bFromLevelLoad);
GetWorldSettings()->NotifyMatchStarted();
GetAISystem()->StartPlay();
PhysicsScene->OnWorldBeginPlay();
WorldContext.World()->bWorldWasLoadedThisTick = true;
WorldContext.OwningGameInstance->LoadComplete();
- UGameEngine::Start() 非编辑器模式
WaitForEngineLoadingScreenToFinish()
WaitForMovieToFinish()
- 加载模块: Media、AutomationWorker、AutomationController、ProfilerClient 、SequenceRecorder、SequenceRecorderSections
- 线程心跳包
FThreadHeartBeat::Get().Start();
- 外部分析器
- etc
EditorInit()
调用GEngineLoop.Init() 后执行
- 一些命令行、通知、消息、日志、ui等注册
- 加载关卡 startup map
- Process global shader results before we try to render anything
- InitEngineAnalytics
- etc
EngineLoop 引擎主循环
执行 FEngineLoop::Tick()
TickRenderingTickables();
Make sure something is ticking the rendering tickables in -onethread mode to avoid leaks/bugs.ActiveProfiler->FrameSync();
外部分析器帧同步FCoreDelegates::OnBeginFrame.Broadcast();
GLog->FlushThreadedLogs();
刷新线程日志FlushRenderingCommands()
渲染命令更新Scene->UpdateAllPrimitiveSceneInfos()
BeginFrameRenderThread()
beginning of RHI frameScene->StartFrame();
FlushPendingDeleteRHIResources_RenderThread();
渲染线程里一些需要帧处理的任务- 一些 stats 相关的事情
GEngine->Tick()
main game engine tick (world, game objects, etc.)- log 更新
CleanupGameViewport();
- 更新 subsystems
- FEngineAnalytics、FStudioAnalytics 的 tick() 更新
Context.World()->Tick()
USkyLightComponent::UpdateSkyCaptureContents(Context.World());
UReflectionCaptureComponent::UpdateReflectionCaptureContents(Context.World());
- ULocalPlayer 处理
- LevelStreaming 处理
FTickableGameObject::TickObjects()
MediaModule->TickPostEngine();
- GameViewport->Tick(DeltaSeconds);
- RedrawViewports();
Render everything. - IStreamingManager、GameAudioDeviceManager 更新
- 渲染线程命令相关更新 GRenderingRealtimeClock、GRenderTargetPool、FRDGBuilder、ICustomResourcePool
GShaderCompilingManager->ProcessAsyncResults(true, false);
GDistanceFieldAsyncQueue->ProcessAsyncTasks();
MediaModule->TickPreSlate();
tick media framework- slate 的 tick 和 task
- ReplicatedProperties 属性同步
- FTaskGraphInterface 一些并行任务的处理
RHITick()
- 帧计数、帧间隔
- Objects 下一帧回收比标记
- FrameEndSync 帧结束同步事件
EndFrameRenderThread()
FCoreDelegates::OnEndFrame.Broadcast();
EngineExit 引擎退出
-
执行
GEngineLoop.Exit()
,主要是关闭和释放引擎的各个模块,具体可看源码 -
最后调用
FEngineLoop::AppExit()
; 退出应用 -
源码
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(); }
参考
- 本文原创地址 https://www.cnblogs.com/shiroe/p/15547566.html
- 游戏流程总览
- \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