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