UE4启动过程


UE4启动过程


这个文件夹中有各个平台的入口函数,最终都会调用Launch.cpp中的函数。

LaunchWindows.cpp

int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* pCmdLine, _In_ int32 nCmdShow)
{
        //这里进入引擎
	int32 Result = LaunchWindowsStartup(hInInstance, hPrevInstance, pCmdLine, nCmdShow, nullptr);
	LaunchWindowsShutdown();
	return Result;
}

LaunchWindowsStartup调用Launch.cpp的GuardedMain函数进行引擎的初始化和循环等。

GuardedMain函数的执行

  • 引擎循环的预先加载int32 EnginePreInit(const TCHAR* CmdLine)
  • 引擎循环的初始化int32 EngineInit()或int32 EditorInit(IEngineLoop& EngineLoop)
  • Tick引擎循环void EngineTick(void)
  • 关闭引擎void EngineExit(void)

这些函数都定义在Launch.cpp中,只有做了更多操作的int32 EditorInit(IEngineLoop& EngineLoop)定义在Engine\Source\Editor\UnrealEd\Private\UnrealEdGlobals.cpp中。

FEngineLoop GEngineLoop是当前Launch.cpp下的一个全局变量,定义在LaunchEngineLoop.h中。
注意只是把GEngineLoop传入到不同的Init函数里面,一个是EngineInit,一个是EditorInit,EditorInit则定义在不同的文件中。

class FEngineLoop
#if WITH_ENGINE
:public IEngineLoop
#endif
{
public:
//main loop的预先初始化,并且从main()的标准ArgC/ArgV生成命令行
int32 PreInit(int32 ArgC, TCHAR* ArgV[], const TCHAR* AdditionalCommandline = nullptr);

//预先初始化main loop,分析命令行,设置GIsEditor
int32 PreInit(const TCHAR* CmdLine);

//PreInit的第一部分
int32 PreInitPreStartupScreen(const TCHAR* CmdLine);

//PreInit的第二部分
int32 PreInitPostStartupScreen(const TCHAR* CmdLine);

//在Init之前加载所有需要的模块
void LoadPreInitModules();

//加载核心模块
bool LoadCoreModules();

//清除PreInit context
void CleanupPreInitContext();

#if WITH_ENGINE
//加载所有需要的核心模块在一开始
bool LoadStartupCoreModules();

//加载所有的模块在一开始
bool LoadStartupModules();

//初始化主循环(剩余的初始化)
virtual int32 Init() override;

//从命令行初始化timing选项
void InitTime();

//执行关闭函数
void Exit();

//引擎是否应当在一个idle模式操作,不使用CPU或者GPU时间
bool ShouldUseIdleMode() const;

//促进主循环
virtual void Tick() override;

//通过删除对任何待清理对象的引用来删除这些对象
virtual void ClearPendingCleanupObjects() override;
#endif

//RHI后初始化
static void PostInitRHI();

//预初始化HMD设备(如果需要的话)
static void PreInitHMDDevice();

//初始化应用
static bool AppInit();

//准备应用的关闭
static void AppPreExit();

//关闭应用
static void AppExit();

private:
//工具函数处理Slate操作
void ProcessLocalPlayerSlateOperations() const;

protected:
//以毫秒为单位保存动态扩展的帧时间数组(如果FApp::IsBenchmarking()被设置)
TArray<float> FrameTimes;

//保存勾选引擎所花的时间
double TotalTickTime;

//保存引擎应当tick的最大数量的秒数
double MaxTickTime;

//保存需要渲染的最大数量的帧数在benchmarking模式下
uint64 MaxFrameCounter;

//保存上一帧cycles的数量
uint32 LastFrameCycles;

#if WITH_ENGINE
//保存需要清理的对象,当渲染线程完成上一帧
FPendingCleanupObjects* PendingCleanupObjects;
#endif
private:

#if WITH_ENGINE
//保存engine service
FEngineService* EngineService;

//保存应用session服务
TSharedPtr<ISessionService> SessionService;
#endif
//这个用来保存预先初始化的时候,一些模块的加载返回过来的状态的bool变量,或者是否开启一些模块的bool变量
FPreInitContext PreInitContext;
};

WITH_ENGINE,对于那些包含引擎项目的所有构建才会开启,只有在构建独立APP链接引擎的核心的时候才会关闭。
打包好后的项目不包含这个宏。

GEngineLoop的PreInit过程

GEngineLoop的函数定义在LaunchEngineLoop.cpp中,先调用PreInitPreStartupScreen函数,再调用PreInitPostStartupScreen函数。

PreInitPreStartupScreen函数的简化调用过程

int32 FEngineLoop::PreInitPreStartupScreen(const TCHAR* CmdLine)
{
//暂时不知道做啥的一个函数
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::StartOfEnginePreInit);

//GLog单例的惰性初始化
GLog->SetCurrentThreadAsMasterThread();

//设置TLS的缓存在当前线程
FMemory::SetupTLSCachesOnCurrentThread();

//解析命令行,设置UTF8的输出
if (FParse::Param(CmdLine, TEXT("UTF8Output")))
{
	FPlatformMisc::SetUTF8Output();
}

//转入可执行目录,设置当前的工作目录为基目录
FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir();

//初始化trace
FTraceAuxiliary::Initialize(CmdLine);

//关闭/开启LLM基于命令行
LLM(FLowLevelMemTracker::Get().ProcessCommandLine(CmdLine));

//创建stats malloc分析代理
if (FStatsMallocProfilerProxy::HasMemoryProfilerToken())
{
	if (PLATFORM_USES_FIXED_GMalloc_CLASS)
	{
		UE_LOG(LogMemory, Fatal, TEXT("Cannot do malloc profiling with PLATFORM_USES_FIXED_GMalloc_CLASS."));
	}
	//假设这里没有并行
	GMalloc = FStatsMallocProfilerProxy::Get();
}

//初始化log命令控制台去避免静态初始化问题,当从命令行登录的时候
GScopedLogConsole = TUniquePtr<FOutputDeviceConsole>(FPlatformApplicationMisc::CreateConsoleOutputDevice());

//总是开启backlog,那么我们可以得到所有的信息,我们将关闭和清理它在游戏中,
//一旦我们决定是否GIsEditor == false
GLog->EnableBacklog(true);

//初始化std out设备尽可能早,如果在命令行中要求
if (FParse::Param(FCommandLine::Get(), TEXT("stdout")))
{
	InitializeStdOutDevice();
}

//设置当前的工作目录为基目录
FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir();

//初始化输出设备
GError = FPlatformApplicationMisc::GetErrorOutputDevice();
GWarn = FPlatformApplicationMisc::GetFeedbackContext();

//开始预先初始化文本本地化
BeginPreInitTextLocalization();

//预先初始化着色器库
FShaderCodeLibrary::PreInit();

//允许命令行去重写平台文件单例
bool bFileOverrideFound = false;
{
	SCOPED_BOOT_TIMING("LaunchCheckForFileOverride");
	if (LaunchCheckForFileOverride(CmdLine, bFileOverrideFound) == false)
	{
		// if it failed, we cannot continue
		return 1;
	}
}

//初始化文件管理器
{
	SCOPED_BOOT_TIMING("IFileManager::Get().ProcessCommandLineOptions");
	IFileManager::Get().ProcessCommandLineOptions();
}

//初始化异步IO
{
	SCOPED_BOOT_TIMING("InitializeNewAsyncIO");
	FPlatformFileManager::Get().InitializeNewAsyncIO();
}

#if !UE_BUILD_SHIPPING
	// Benchmarking.
	FApp::SetBenchmarking(FParse::Param(FCommandLine::Get(), TEXT("BENCHMARK")));
#else
	FApp::SetBenchmarking(false);
#endif

//初始化task graph子系统,使用潜在的多线程
FTaskGraphInterface::Startup(FPlatformMisc::NumberOfCores());
FTaskGraphInterface::Get().AttachToThread(ENamedThreads::GameThread);

//加载所有需要工作的核心模块(需要在InitializeRenderingCVarsCaching之前加载)
if (!LoadCoreModules())
{
	UE_LOG(LogInit, Error, TEXT("Failed to load Core modules."));
	return 1;
}

//从Ini读取配置
if (bDumpEarlyConfigReads)
{
	RecordConfigReadsFromIni();
}

//从Pak读取文件
if (bDumpEarlyPakFileReads)
{
	RecordFileReadsFromPaks();
}
//开始记录配置补丁的CVar更改
RecordApplyCVarSettingsFromIni();

//初始化渲染CVarsCaching
InitializeRenderingCVarsCaching();

//得到log输出设备的指针
GLogConsole = GScopedLogConsole.Get();

//加载预初始化模块
LoadPreInitModules();

//开始应用
{
	SCOPED_BOOT_TIMING("AppInit");
	if (!AppInit())
	{
		return 1;
	}
}


//初始化系统设置在任何人尝试使用它的时候
GSystemSettings.Initialize(bHasEditorToken);
//从存储在INIT文件中的控制台变量应用渲染设置
ApplyCVarSettingsFromIni(TEXT("/Script/Engine.RendererSettings"), *GEngineIni, ECVF_SetByProjectSetting);
ApplyCVarSettingsFromIni(TEXT("/Script/Engine.RendererOverrideSettings"), *GEngineIni, ECVF_SetByProjectSetting);
ApplyCVarSettingsFromIni(TEXT("/Script/Engine.StreamingSettings"), *GEngineIni, ECVF_SetByProjectSetting);
ApplyCVarSettingsFromIni(TEXT("/Script/Engine.GarbageCollectionSettings"), *GEngineIni, ECVF_SetByProjectSetting);

//预加载分辨率设置
UGameUserSettings::PreloadResolutionSettings();

//初始化scalability系统和默认值
Scalability::InitScalabilitySystem();

//设置设备配置文件中已经设置的控制台变量
//将加载并应用游戏用户设置
UDeviceProfileManager::InitializeCVarsForActiveDeviceProfile();

//尽早避免昂贵的子系统重新初始化
//在SystemSettings.ini文件加载,那么我们可以得到正确的状态
Scalability::LoadState((bHasEditorToken && !GEditorSettingsIni.IsEmpty()) ? GEditorSettingsIni : GGameUserSettingsIni);

//使用渲染线程
if (FPlatformMisc::UseRenderThread())
{
	GUseThreadedRendering = true;
}

//从INIT加载控制台变量
FConfigCacheIni::LoadConsoleVariablesFromINI();

//SystemSettings加载的时候,平台相关的进行初始化
FPlatformMisc::PlatformInit();
FPlatformApplicationMisc::Init();
FPlatformMemory::Init();

//允许平台去开启它希望使用的特性
IPlatformFeaturesModule::Get();

//初始化物理引擎系统
InitGamePhys();

//初始化引擎文本本地化
InitEngineTextLocalization();

//Slate初始化高DPI
FSlateApplication::InitHighDPI(bForceEnableHighDPI);

//初始化平台应用
FSlateApplication::Create();

//初始化所有UniformBuffer结构体
FShaderParametersMetadata::InitializeAllUniformBufferStructs();

//初始化RHI
RHIInit(bHasEditorToken);

//基于引擎配置初始化全局变量
RenderUtilsInit();

//将打开材质着色代码存储库,如果项目打包了它
FShaderCodeLibrary::InitForRuntime(GMaxRHIShaderPlatform);

//着色器相关的进行初始化
GDistanceFieldAsyncQueue = new FDistanceFieldAsyncQueue();
GShaderCompilerStats = new FShaderCompilerStats();
GShaderCompilingManager = new FShaderCompilingManager();
InitializeShaderHashCache();

//在主线程Cache渲染模块,那么我们之后可以从渲染模块安全地取回它
GetRendererModule();

//在加载任何着色器之前初始化着色器类型
InitializeShaderTypes();

//加载全局着色器
CompileGlobalShaderMap(false);

//SLATE模块的加载
...

//用之前的PreInitContext保存那些bool变量
PreInitContext.bDumpEarlyConfigReads = bDumpEarlyConfigReads;
PreInitContext.bDumpEarlyPakFileReads = bDumpEarlyPakFileReads;
PreInitContext.bForceQuitAfterEarlyReads = bForceQuitAfterEarlyReads;
PreInitContext.bWithConfigPatching = bWithConfigPatching;
PreInitContext.bHasEditorToken = bHasEditorToken;

PreInit初始化过程总结

  • GLog设置当前创建它的线程为它的主线程。
  • 如果是Windows平台,则为Ctrl-C注册一个处理程序。
  • FMemory设置当前线程的TLS Cache。
  • 分析命令行参数是否有UTF8Output来调用FPlatformMisc::SetUTF8Output()
  • 设置当前的工作目录为根目录。
  • 如果是发行版本的游戏,则重写命令行,防止被潜在的漏洞利用。
  • 初始化trace。//1503


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM