概述
笔记
代码版本5.3
从宏观的角度看引擎的初始化和Tick。
https://www.yuque.com/chenweilin-tryw7/gbfomp/ffox34r27nwf9nte?singleDoc# 《UE 架构基础入门》
跨平台Main入口
首先我们能很容易的找到主函数在哪
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;
}
锁定源码目录
Launch/Private 下能找到各个平台的文件夹。其中Windows文件夹下的LaunchWindows.cpp就是win平台的入口
在 LaunchWindowsStartup 中,进行了一些windows的命令行参数环境变量的设置
ErrorLevel = GuardedMain( CmdLine );
各个操作系统的主函数入口最终都会走到这里面,实现跨平台入口的统一。
这个函数位于Launch目录下的Launch.cpp
/**
* Static guarded main function. Rolled into own function so we can have error handling for debug/ release builds depending
* on whether a debugger is attached or not.
*/
int32 GuardedMain( const TCHAR* CmdLine )
{
struct EngineLoopCleanupGuard
{
~EngineLoopCleanupGuard()
{
if (!GUELibraryOverrideSettings.bIsEmbedded)
{
EngineExit();
}
}
} CleanupGuard;
int32 ErrorLevel = EnginePreInit( CmdLine );
#if WITH_EDITOR
if (GIsEditor)
{
ErrorLevel = EditorInit(GEngineLoop);
}
else
#endif
{
ErrorLevel = EngineInit();
}
while( !IsEngineExitRequested() )
{
EngineTick();
}
#if WITH_EDITOR
if( GIsEditor )
{
EditorExit();
}
#endif
return ErrorLevel;
}
掐头去尾,结构很简单
int32 ErrorLevel = EnginePreInit( CmdLine );
ErrorLevel = EditorInit(GEngineLoop);
ErrorLevel = EngineInit();
while( !IsEngineExitRequested() )
{
EngineTick();
}
EditorExit();
EngineExit();
预初始化,编辑器初始化,引擎初始化,一直tick,编辑器退出,引擎退出
在 int32 ErrorLevel = EnginePreInit( CmdLine ); 之前还有一点代码。主要是
- 解析 waitforattach,WaitForDebugger 等待调试器附加命令,如果有就阻塞
- BootTimingPoint("DefaultMain") 记录引擎启动时间点
- FCoreDelegates::GetPreMainInitDelegate().Broadcast(); 调用“PreMainInit”的 core delegates。UE的CoreDelegate贯穿整个引擎生命周期,我们可以通过绑定各种core delegate来在引擎各个阶段插入代码
- struct EngineLoopCleanupGuard 利用局部对象析构调用析构函数来调用 EngineExit
- MiniDumpFilenameW 是UE 拼接的一个dump文件名字
如何梳理记忆引擎初始化流程
另外为方便对引擎初始化的大致流程做划分梳理。我们可以用
这个枚举
enum class EDelayedRegisterRunPhase : uint8
{
StartOfEnginePreInit,
FileSystemReady,
TaskGraphSystemReady,
StatSystemReady,
IniSystemReady,
EarliestPossiblePluginsLoaded,
ShaderTypesReady,
PreObjectSystemReady,
ObjectSystemReady,
DeviceProfileManagerReady,
EndOfEngineInit,
NumPhases,
};
在代码里面搜索类似这样的逻辑,标明引擎初始化到了 StartOfEnginePreInit 开始引擎预初始化这一阶段。
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::StartOfEnginePreInit);
或者
或者找这个枚举 ELoadingPhase 和这种调用
IProjectManager::Get().LoadModulesForProject(ELoadingPhase::Default)
IPluginManager::Get().LoadModulesForEnabledPlugins(ELoadingPhase::Default)
引擎加载到xx阶段,开始加载 ELoadingPhase::Default 这个阶段的插件
EnginePreInit
int32 ErrorLevel = EnginePreInit( CmdLine );
/**
* PreInits the engine loop
*/
int32 EnginePreInit( const TCHAR* CmdLine )
{
int32 ErrorLevel = GEngineLoop.PreInit( CmdLine );
return( ErrorLevel );
}
这个 GEngineLoop 是什么。这是一个全局变量。没什么特别的。
FEngineLoop GEngineLoop;
打开后是两个函数
int32 FEngineLoop::PreInit(const TCHAR* CmdLine)
{
const int32 rv1 = PreInitPreStartupScreen(CmdLine);
const int32 rv2 = PreInitPostStartupScreen(CmdLine);
}
PreInitPreStartupScreen
StartOfEnginePreInit
函数位于: int32 FEngineLoop::PreInitPreStartupScreen(const TCHAR* CmdLine)
-
ON_SCOPE_EXIT { GEnginePreInitPreStartupScreenEndTime = FPlatformTime::Seconds(); }; 记录作用域最后完成时间
-
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::StartOfEnginePreInit);
- 表示 进入 EDelayedRegisterRunPhase::StartOfEnginePreInit 阶段了
-
如果GLog对象存在,则 SetCurrentThreadAsPrimaryThread 设置当前线程为主线程
-
FApp::SetDebugGame(true); 如果需要就设置DebugGame
-
命令处理:statnamedevents,verbosenamedevents
-
FWindowsPlatformMisc::SetGracefulTerminationHandler(); 注册ctrl+c注册程序
-
FMemory::SetupTLSCachesOnCurrentThread();
-
命令处理:UTF8Output,IgnoreDebugger
-
FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir(); 当前工作目录切到exe目录
-
从环境变量中获取 "UE-CmdLineArgs"如果有就加进来命令处理
-
LaunchSetGameName(CmdLine, GameProjectFilePathUnnormalized) 设置当前游戏名称
-
FTraceAuxiliary::Initialize(CmdLine); 初始化追踪(堆栈,版本之类的)
-
LLM(FLowLevelMemTracker::Get().ProcessCommandLine(CmdLine)); LLM 初始化
-
FCoreUObjectDelegates::PostGarbageCollectConditionalBeginDestroy.AddStatic(DeferredPhysResourceCleanup); 注册垃圾回收后执行这个什么物理资源回收的函数
-
FCoreDelegates::OnSamplingInput.AddStatic(UpdateGInputTime); 输入采用事件
-
GMalloc = FStatsMallocProfilerProxy::Get(); 内存profile对象,如果在profile模式
-
GScopedLogConsole = TUniquePtr
(FPlatformApplicationMisc::CreateConsoleOutputDevice()); // 初始化控制台输出设备 -
stdout命令 InitializeStdOutDevice();
-
if FPlatformProperties::SupportsQuit() 解析命令 testexit= 然后丢到输出设备里面去
-
FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir(); // 又来一次
-
SCOPED_BOOT_TIMING("Fix up the relative project path"); // 非 Program 模式下修复路径
-
SCOPED_BOOT_TIMING("Init Output Devices"); // 初始化输出设备,这里GError,GWarn 对象被创建。这个代理被广播 OnOutputDevicesInit
-
SCOPED_BOOT_TIMING("Command Line Adjustments"); // 非发布版本,检查命令行参数的准确性
-
FIoDispatcher::Initialize(); // 初始化IO调度器
-
BeginPreInitTextLocalization(); // 文本本地化初始化
-
FShaderCodeLibrary::PreInit(); // Shader初始化
-
SCOPED_BOOT_TIMING("LaunchCheckForFileOverride"); // 命令行参数是否有文本覆盖的选项
-
FModuleManager::Get().AddExtraBinarySearchPaths(); // 模块添加二进制搜索路径,保证某些库能被找到
-
IFileManager::Get().ProcessCommandLineOptions(); // 文件管理器,解析命令行,删除目录 ScreenShotDir ProjectLogDir
-
FPlatformFileManager::Get().InitializeNewAsyncIO(); // 初始化异步IO
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::FileSystemReady);
看到这里可以对上面一大段做一个总结:
文件系统初始化已经准备好了。
FileSystemReady
ps: 这个标题并没有归类的意思,只是划分这里,已经执行完了 FileSystemReady 这个代理,一个分割线的作用
线程相关
GIsGameAgnosticExe, LaunchHasIncompleteGameName() 检测游戏名字的完整性
GGameThreadId = FPlatformTLS::GetCurrentThreadId(); // 当前主线程的ID
FPlatformProcess::SetupGameThread(); // 主线程名字改为 GameThread
- 有几个lambda。一堆判断来设置程序运行环境,编辑器,DS,还是客户端
SetIsRunningAsCommandlet
SetIsRunningAsRegularClient
SetIsRunningAsDedicatedServer
SetIsRunningAsEditor
GIsClient, -Game -Server 这种
-
BENCHMARK 是否启动基准测试
-
// Initialize random number generator. // 随机数种子初始化
-
FPaths::SetProjectFilePath(ProjectFilePath); // 没有设置项目名字,就会默认一个
-
for => PlatformFileChainElement->InitializeAfterProjectFilePath(); // 初始化平台的文件管理器
-
LaunchFixProjectPathCase 修复路径大小写
-
// Now verify the project file if we have one 验证项目文件,并加载一些目录
IProjectManager::Get().LoadProjectFile(FPaths::GetProjectFilePath()) // 加载项目文件,企业目录是否存在,在就额外加载一个Binaries进来
AddDllDirectory,SetGameBinariesDirectory // 设置DLL和二进制目录
AddShaderSourceDirectoryMapping(TEXT("/Engine"), FPlatformProcess::ShaderDir()); // 添加Shader目录 GShaderSourceDirectoryMappings.Add
AddShaderSourceDirectoryMapping(TEXT("/ShaderAutogen"), AutogenAbsolutePath);
- 创建线程
FTaskGraphInterface::Startup(FPlatformMisc::NumberOfWorkerThreadsToSpawn());
FTaskGraphInterface::Get().AttachToThread(ENamedThreads::GameThread);
GLargeThreadPool
GThreadPool
GBackgroundPriorityThreadPool // 创建各种线程池
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::TaskGraphSystemReady);
TaskGraphSystemReady
FThreadStats::StartThread(); // 启动线程统计
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::StatSystemReady);
StatSystemReady
LoadCoreModules() // 加载核心模块,加载 CoreUObject 这个 Module
InitializeRenderingCVarsCaching(); // 渲染相关后面再看
FOodleDataCompression::StartupPreInit(); // OODLE 初始化,这是一个UE的压缩模块
LoadPreInitModules() // 加载 PreInit的模块,比如Engine, Renderer, Landscape, RenderCore 等。。。
FCsvProfiler::Get()->Init(); // CSV分析器
AppLifetimeEventCapture::Init(); // 程序生命周期事件捕获
AppInit
// Start the application
{
SCOPED_BOOT_TIMING("AppInit");
if (!AppInit())
{
return 1;
}
}
bool FEngineLoop::AppInit( ) 位于LaunchEngineLoop。是一个很重要的调用流程
-
BeginInitTextLocalization(); // 初始化文本本地化
-
FPlatformMisc::PlatformPreInit(); // 平台特定的初始化内容
-
FPlatformApplicationMisc::PreInit(); // 平台对于预初始化
-
FPlatformProcess::SetCurrentWorkingDirectoryToBaseDir(); // 看到第三次了
-
IFileManager::Get().ProcessCommandLineOptions(); // 处理命令行
-
内存相关设置
-
如果有命令 BUILDMACHINE 添加命令 FCommandLine::AddToSubprocessCommandline(TEXT(" -buildmachine"));。可以学一下
-
IFileManager::Get().MakeDirectory( *FPaths::ProjectLogDir(), true ); // 创建LOG保存路径文件夹
-
FCString::Strcpy(MiniDumpFilenameW, IFileManager::Get().ConvertToAbsolutePathForExternalAppForWrite(FString::Printf(TEXT("%sunreal-v%i-%s.dmp"), FPaths::ProjectLogDir(), FEngineVersion::Current().GetChangelist(), FDateTime::Now().ToString())));
- 构造一个dump文件名字
-
FPlatformOutputDevices::SetupOutputDevices(); // Init logging to disk
-
FConfigCacheIni::InitializeConfigSystem(); // 配置系统ini文件复制给全局变量,已经相关初始化
-
FModuleManager::Get().LoadModule("IoStoreOnDemand");
-
FTraceAuxiliary::InitializePresets(FCommandLine::Get()); // 最终初始化
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::IniSystemReady);
IniSystemReady
- // 开始加载 ELoadingPhase::EarliestPossible 这个阶段的插件了
ProjectManager.LoadModulesForProject(ELoadingPhase::EarliestPossible) PluginManager.LoadModulesForEnabledPlugins(ELoadingPhase::EarliestPossible)
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::EarliestPossiblePluginsLoaded);
EarliestPossiblePluginsLoaded
-
FPlatformStackWalk::Init(); // Now that configs have been initialized, setup stack walking options
-
CheckForPrintTimesOverride();
-
// 加载 ELoadingPhase::PostConfigInit 阶段的插件
ProjectManager.LoadModulesForProject(ELoadingPhase::PostConfigInit) PluginManager.LoadModulesForEnabledPlugins(ELoadingPhase::PostConfigInit)
检查是否有插件需要更新
- PreInitHMDDevice(); // 头显
- FAutomationTestFramework::Get().SetForceSmokeTests(bForceSmokeTests); // 是否冒烟测试
- FApp::InitializeSession();
- FCoreDelegates::OnInit.Broadcast();
AppInit 结束
// Start the application
{
SCOPED_BOOT_TIMING("AppInit");
if (!AppInit())
{
return 1;
}
}
回到上一层从这里继续
-
NoLogThread 命令
-
SCOPED_BOOT_TIMING("GIOThreadPool->Create"); // 创建IO线程
-
GSystemSettings.Initialize(bHasEditorToken); // 初始化系统设置
-
UE::ConfigUtilities::ApplyCVarSettingsFromIni // 从ini读取一些渲染设置
-
UGameUserSettings::PreloadResolutionSettings(); // 预加载分辨率设置
-
Scalability::InitScalabilitySystem(); // 控制台变量数值变化的委托绑定
-
UDeviceProfileManager::InitializeCVarsForActiveDeviceProfile(); //
-
FConfigCacheIni::LoadConsoleVariablesFromINI(); // 从ini 读取配置变量
-
FPlatformMisc::PlatformInit(); FPlatformApplicationMisc::Init(); FPlatformMemory::Init(); // 平台杂项初始化,平台应用程序初始化,平台内存初始化
-
UE::DerivedData::IoStore::InitializeIoDispatcher(); // 初始化DerivedData模块的IoDispatcher
-
如果上面有问题,这里就会强退了
if (!FPlatformMisc::CommandLineCommands()) { FPlatformMisc::RequestExit(false, TEXT("FEngineLoop::PreInitPreStartupScreen.CommandLineCommands")); }
-
InitGamePhys() // 初始化物理系统
-
FPlatformProcess::CleanShaderWorkingDir(); // 清除shader工作目录
-
InitEngineTextLocalization(); // 字体本地化
-
FSlateApplication::InitHighDPI(bForceEnableHighDPI); // 设置DPI
-
FAudioThread::SetUseThreadedAudio(bUseThreadedAudio); // 音频线程
-
FPlatformSplash::Show();
-
FSlateApplication::Create(); // 展示Splash,就是那个加载小框
这一小段基本都是渲染的。
- RHIInit(bHasEditorToken); RHI
- RenderUtilsInit();
- InitializeShaderHashCache(); //
- GetRendererModule(); // Cache the renderer module in the main thread
- InitializeShaderTypes(); //
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::ShaderTypesReady);
ShaderTypesReady
-
CompileGlobalShaderMap(false); // 编译全局shader map
-
CreateMoviePlayer(); // 播放电影,如果有
-
FPreLoadScreenManager::Create();
-
CurrentSlateApp.InitializeRenderer(SlateRendererSharedRef); // 初始化slate渲染 比如D3D
-
FEngineFontServices::Create();
-
ELoadingPhase::PostSplashScreen 这个阶段的插件
保存一些变量
// Save PreInitContext
PreInitContext.bDumpEarlyConfigReads = bDumpEarlyConfigReads;
PreInitContext.bDumpEarlyPakFileReads = bDumpEarlyPakFileReads;
PreInitContext.bForceQuitAfterEarlyReads = bForceQuitAfterEarlyReads;
PreInitContext.bWithConfigPatching = bWithConfigPatching;
PreInitContext.bHasEditorToken = bHasEditorToken;
PreInitPostStartupScreen
// 屏幕加载
- GetMoviePlayer()->SetupLoadingScreenFromIni(); // 从ini中加载屏幕的电影配置到内存
- ELoadingPhase::PreEarlyLoadingScreen 加载这个阶段的插件
- if GetMoviePlayer()->HasEarlyStartupMovie()
- GetMoviePlayer()->PlayEarlyStartupMovies(); // 有动画要播放咯
- else FPreLoadScreenManager 。。。// 一些是否有加载进度之类的逻辑
// pak 和 shader
-
SCOPED_BOOT_TIMING("MountPaksAfterEarlyStartupScreen"); // pak 相关
-
SCOPED_BOOT_TIMING("FShaderCodeLibrary::OpenLibrary"); // 全局 Shader 加载
- Handle opening shader library after our EarlyLoadScreen
-
FShaderPipelineCache::OpenPipelineFileCache(GMaxRHIShaderPlatform);
-
InitGameTextLocalization();
-
FModuleManager::Get().LoadModule("AssetRegistry"); // AssetRegistry
-
IPackageResourceManager::Initialize(); // 资源管理器,后面读取Object依赖这个
-
IBulkDataRegistry::Initialize(); // 数据表,大块数据结构
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::PreObjectSystemReady);
PreObjectSystemReady
-
ProcessNewlyLoadedUObjects // UObject 注册
-
UE::Virtualization::Initialize(UE::Virtualization::EInitializationFlags::None);
-
FTextLocalizationManager::Get().WaitForAsyncTasks();
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::ObjectSystemReady);
ObjectSystemReady
-
PIEPreviewDeviceProfileSelector // 不同平台的一些渲染配置
-
初始化默认材质
UMaterialInterface::InitDefaultMaterials(); UMaterialInterface::AssertDefaultMaterialsExist(); UMaterialInterface::AssertDefaultMaterialsPostLoaded();
-
IStreamingManager::Get(); // 纹理流系统
-
FModuleManager::Get().StartProcessingNewlyLoadedObjects(); // 通知模块管理,现在可以处理 newly-loaded UObjects 了
-
GUObjectArray.DisableDisregardForGC() // 设置GC优化
// 加载核心模块了,里面包括Core, Networking, LiveCoding, UnrealEd, Slate 等
-
LoadStartupCoreModules
- 可以会议下,上面 StatSystemReady的后面的,LoadPreInitModules() 加载预初始化模块
-
ELoadingPhase::PreLoadingScreen 加载这个阶段的插件
-
GetMoviePlayer()->Initialize 初始化电影播放器
// 渲染
-
PostInitRHI();
-
StartRenderingThread(); // 开启渲染线程了
-
GetMoviePlayer()->PlayMovie(); // 播放电影
-
FUnrealEdMisc::Get().MountTemplateSharedPaths(); // 安装共享shader路径
-
LoadStartupModules // 又是加载模块,这次是对所有 PreDefault,Default,PostDefault 阶段的插件做加载了。
-
UOnlineEngineInterface
-
ELoadingPhase::PostEngineInit 阶段的插件
-
GetHighResScreenshotConfig().Init(); // 高清截图配置初始化
-
PrecacheComputePipelineStatesForGlobalShaders
-
FAutomationTestFramework::Get().RunSmokeTests();
EditorInit
》EditorInit
调用位置大概在这里
int32 GuardedMain( const TCHAR* CmdLine )
{
int32 ErrorLevel = EnginePreInit( CmdLine );
...
ErrorLevel = EditorInit(GEngineLoop);
}
int32 EditorInit( IEngineLoop& EngineLoop )
- GDebugToolExec = new FDebugToolExec; // debug工具
int32 ErrorLevel = EngineLoop.Init();
FEngineLoop::Init
》EditorInit》FEngineLoop::Init
UClass* EngineClass = nullptr;
if( !GIsEditor )
{
SCOPED_BOOT_TIMING("Create GEngine");
// We're the game.
FString GameEngineClassName;
GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("GameEngine"), GameEngineClassName, GEngineIni);
EngineClass = StaticLoadClass( UGameEngine::StaticClass(), nullptr, *GameEngineClassName);
if (EngineClass == nullptr)
{
UE_LOG(LogInit, Fatal, TEXT("Failed to load UnrealEd Engine class '%s'."), *GameEngineClassName);
}
GEngine = NewObject<UEngine>(GetTransientPackage(), EngineClass);
}
else
{
#if WITH_EDITOR
// We're UnrealEd.
FString UnrealEdEngineClassName;
GConfig->GetString(TEXT("/Script/Engine.Engine"), TEXT("UnrealEdEngine"), UnrealEdEngineClassName, GEngineIni);
EngineClass = StaticLoadClass(UUnrealEdEngine::StaticClass(), nullptr, *UnrealEdEngineClassName);
if (EngineClass == nullptr)
{
UE_LOG(LogInit, Fatal, TEXT("Failed to load UnrealEd Engine class '%s'."), *UnrealEdEngineClassName);
}
GEngine = GEditor = GUnrealEd = NewObject<UUnrealEdEngine>(GetTransientPackage(), EngineClass);
#else
check(0);
#endif
}
这一段可以看到,
GEngine,GEditor,GUnrealEd 的对象初始化
编辑器模式下默认是 UUnrealEdEngine,游戏模式下默认是 GameEngine。
并且 GConfig 的 配置,可以设置我们自己的引擎类覆盖上去
-
GetMoviePlayer()->PassLoadingScreenWindowBackToGame(); // 将加载的窗口丢给game,GameEngine->GameViewportWindow = MainWindow;
-
FPreLoadScreenManager::Get()->PassPreLoadScreenWindowBackToGame();
-
GEngine->ParseCommandline(); // 解析 noailogging,enableailogging,MaxAlloc 命令
-
InitTime(); // 时间相关的变量初始化
GEngine->Init(this);
根据上面,这里有可能的是
void UGameEngine::Init(IEngineLoop InEngineLoop)
void UUnrealEdEngine::Init(IEngineLoop InEngineLoop)
继承关系
class UUnrealEdEngine : public UEditorEngine
class UEditorEngine : public UEngine
class UGameEngine : : public UEngine
我们看更复杂的编辑器的版本。所以这里是 UUnrealEdEngine::Init
UUnrealEdEngine::Init
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init
void UUnrealEdEngine::Init(IEngineLoop* InEngineLoop)
一开始就Super::Init(InEngineLoop); // UEditorEngine::Init
UEditorEngine::Init
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init》UEditorEngine::Init
void UEditorEngine::Init(IEngineLoop* InEngineLoop)
- RF_ClassDefaultObject // 检查对象是否不是类的默认对象
- 绑定了一堆代理,PIE流程相关,level add remove to word, on asset loaded 之类的
- GEditor = this;
- InitEditor(InEngineLoop);
UEditorEngine::InitEditor
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init》UEditorEngine::Init》UEditorEngine::InitEditor
void UEditorEngine::InitEditor(IEngineLoop* InEngineLoop)
- InitDerivedDataBuildWorkers(); // 初始化派生数据构建的工作线程?
- UEngine::Init(InEngineLoop);
UEngine::Init
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init》UEditorEngine::Init》UEditorEngine::InitEditor》UEngine::Init
void UEngine::Init(IEngineLoop* InEngineLoop)
// 一些错误处理初始化
-
ErrorsAndWarningsCollector = MakePimpl
(); // 一个错误警告收集器 -
if(!FEngineBuildSettings::IsInternalBuild())
- 遍历所有enable的插件,把插件的定义json取出来
- FGenericCrashContext::AddPlugin(DescStr); 丢给这个,用于后续奔溃报告
-
FPlatformMisc::SetMemoryWarningHandler(EngineMemoryWarningHandler); // 内存警告处理程序
-
EngineLoop = InEngineLoop;
-
RegisterEngineElements();
- 加载 TypedElementFramework,TypedElementRuntime 模块
- RegisterEngineObjectElements
- RegisterEngineActorElements
- RegisterEngineComponentElements
- RegisterEngineSMInstanceElements
- OnRegisterEngineElementsDelegate.Broadcast();
-
FURL::StaticInit();
-
EngineSubsystemCollection.Initialize(this); // 所有UDynamicSubsystem子类的subsystem初始化
-
UGameMapsSettings::SetGameDefaultMap(MapString); // 默认地图名字的处理
-
InitializeRunningAverageDeltaTime(); // 初始化平均帧时间
-
AddToRoot();
-
InitializeHMDDevice InitializeEyeTrackingDevice // 头显和眼动追踪
-
EnableScreenSaver( false ); // 禁用屏保
// slate声音和测试
-
CurrentSlateApp.InitializeSound( TSharedRef
( new FSlateSoundDevice() ) ); -
RestoreSlateTestSuite();
-
FObjectThumbnail::SetThumbnailCompressors // 缩略图的压缩解压器
-
LoadObject
(UEngine::StaticClass()->GetOuter(), *UEngine::StaticClass()->GetName(), NULL, LOAD_Quiet|LOAD_NoWarn, NULL ); // 加载引擎默认对象 -
LoadConfig
-
SetConfiguredProcessLimits // 进程限制配置
-
FModuleManager::Get().LoadModule("WorldPartitionEditor");
-
InitializeObjectReferences(); //
-
FBlueprintCoreDelegates::SetScriptMaximumLoopIterations( GEngine->MaximumLoopIterationCount ); // 蓝图最大循环
-
SetNearClipPlaneGlobals(NearClipPlane); // 全局近景层面
-
UTextRenderComponent::InitializeMIDCache(); // 初始化文本渲染组件的材质实例动态缓存
-
GReadOnlyCVARCache.Init()
// !!!重要 World的创建,链接到其他笔记
if (GIsEditor)
{
// Create a WorldContext for the editor to use and create an initially empty world.
FWorldContext &InitialWorldContext = CreateNewWorldContext(EWorldType::Editor);
InitialWorldContext.SetCurrentWorld( UWorld::CreateWorld( EWorldType::Editor, true ) );
GWorld = InitialWorldContext.World();
}
-
const UGeneralProjectSettings& ProjectSettings = *GetDefault
(); // 加载项目通用设置 -
FNetworkVersion::SetProjectVersion(*ProjectSettings.ProjectVersion); // 设置网络版本
-
命令处理,垂直同步命令
-
一些代理
-
GetBufferVisualizationData().Initialize();
-
GetNaniteVisualizationData().Initialize();
-
GetVirtualShadowMapVisualizationData().Initialize();
-
InitializePortalServices(); // 门户服务
-
FEngineAnalytics::Initialize(); // 引擎分析工具
-
InitializeAudioDeviceManager(); // 音频设备管理
-
加载一些模块
-
AssetManager->FinishInitialLoading();
-
RecordHMDAnalytics();
-
InitThreadConfig();
UEngine::Init end
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init》UEditorEngine::Init》UEditorEngine::InitEditor
回退
void UEditorEngine::InitEditor(IEngineLoop* InEngineLoop)
{
// Call base.
UEngine::Init(InEngineLoop);
// ...
InitEditor end
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init》UEditorEngine::Init
回退到这一层继续下去
void UEditorEngine::Init(IEngineLoop* InEngineLoop)
{
InitEditor(InEngineLoop);
// 。。。
}
-
LoadEditorFeatureLevel(); // 编辑器特性级别
-
Trans = CreateTrans(); // 事务性操作,undo redo 是如何设计的
-
加载了一堆模块
-
GameUserSettings Load and Apply
-
Cleanse( false, 0, NSLOCTEXT("UnrealEd", "Startup", "Startup") ); // 清理垃圾
-
FEditorCommandLineUtils::ProcessEditorCommands(FCommandLine::Get()); // 编辑器命令
-
CheckForMissingAdvancedRenderingRequirements // 检查缺失的高级渲染要求
-
bIsInitialized = true;
UEditorEngine::Init end
》EditorInit》FEngineLoop::Init》UUnrealEdEngine::Init
回到这一层
void UUnrealEdEngine::Init(IEngineLoop* InEngineLoop)
{
Super::Init(InEngineLoop);
// ...
}
-
RegisterEditorElements(); // 注册编辑器元素。
- RegisterEditorObjectElements();
- RegisterEditorActorElements();
- RegisterEditorComponentElements();
- RegisterEditorSMInstanceElements();
-
RebuildTemplateMapData(); // 重建模板映射数据,不知道拿来干啥的
-
ValidateFreeDiskSpace(); // 是否有空闲磁盘空间
-
FSourceCodeNavigation::Initialize(); // 源码导航,就是编辑器点一下能跳去VS的那个功能
-
PackageAutoSaver->LoadRestoreFile(); // 自动保存
-
PerformanceMonitor = new FPerformanceMonitor;
-
VerifyMountPointWritePermission(*RootPath); // 验证Content目录有读写权限,非常暴力,write一个文件,成功就有权限
-
一堆代理
-
FSnappingUtils::InitEditorSnappingTools(); // ViewportSnapping 视口对齐工具
TODO 。。。
UUnrealEdEngine::Init End
》EditorInit》FEngineLoop::Init》
回退到这里继续
int32 FEngineLoop::Init()
{
{
SCOPED_BOOT_TIMING("GEngine->Init");
GEngine->Init(this);
}
//。。。
}
-
SessionServices
-
EngineService = new FEngineService(); // 引擎服务实例,初始化消息传递,并指定了处理不同类型消息的回调函数和接收线程
-
ELoadingPhase::PostEngineInit 这个阶段的插件
-
GEngine->Start(); // 子类空接口
-
引擎节目加载。等待电影结束
-
FTraceAuxiliary::EnableChannels();
-
Media Module
-
加载一些模块。。。
-
GIsRunning = true;
-
FViewport::SetGameRenderingEnabled(true, 3); // 渲染启用,并隐藏3帧数
-
FThreadHeartBeat::Get().Start(); // 心跳其他线程是否活着
-
FShaderPipelineCache::PauseBatching(); // 暂停shader缓存处理
-
FCoreDelegates::OnFEngineLoopInitComplete.Broadcast();
-
FShaderPipelineCache::ResumeBatching(); // 恢复shader缓存处理
-
初始化分析器
FDelayedAutoRegisterHelper::RunAndClearDelayedAutoRegisterDelegates(EDelayedRegisterRunPhase::EndOfEngineInit);
上面提到的枚举的最后一个阶段。
EDelayedRegisterRunPhase::EndOfEngineInit
FEngineLoop::Init End
》EditorInit》
回退到这里
int32 EditorInit( IEngineLoop& EngineLoop )
{
// ...
int32 ErrorLevel = EngineLoop.Init();
if( ErrorLevel != 0 )
{
FPlatformSplash::Hide();
return 0;
}
//。。。
-
if ( FEngineAnalytics::IsAvailable() )
- FEngineAnalytics::GetProvider().RecordEvent(TEXT("Editor.ProgramStarted"), EventAttributes);
- Let the analytics know that the editor has started
-
FActorFolders::Get(); // Set up the actor folders singleton, 绑定actor文件变化的事件,actor文件上下文系统
-
FUnrealEdMisc::Get().OnInit();
- void FUnrealEdMisc::OnInit() // 杂项初始化
-
FEditorDirectories::Get().LoadLastDirectories();
-
FDesktopPlatformModule::Get()->GetTargetsForCurrentProject(); // 缓存当前项目可用图标
-
FPlatformSplash::Hide(); // ok了,隐藏加载框了
// Main Frame
-
FModuleManager::LoadModuleChecked
(TEXT("MainFrame")); -
MainFrameModule.CreateDefaultMainFrame(bStartImmersive, bStartPIE);
-
CheckAndMaybeGoToVRModeInternal(bIsImmersive); // check VR
-
否需要更新游戏项目文件到当前版本, 检查并警告项目文件名是否有效
// =================== EDITOR STARTUP FINISHED ===================
- Stat tracking
- FModuleManager::LoadModuleChecked
(TEXT("HierarchicalLODOutliner")); // 加载模块-层次结构LOD大纲视图 - we have to remove invalid keys. 移除无效按键
EngineInit
FEngineLoop::Init
和上面的是同一个函数,在GIsEditor的地方做了区分
EngineTick
// Don't tick if we're running an embedded engine - we rely on the outer
// application ticking us instead.
if (!GUELibraryOverrideSettings.bIsEmbedded)
{
while( !IsEngineExitRequested() )
{
EngineTick();
}
}
void FEngineLoop::Tick() 到了这里
-
FScopedSampleMallocChurn ChurnTracker; // 非发布,非测试。追踪内存分配和释放情况
-
LLM(FLowLevelMemTracker::Get().UpdateStatsPerFrame()); // let the low level mem tracker pump once a frame to update states 低内存追踪器每帧更新
-
BeginExitIfRequested(); // 是否有退出请求
-
TRACE_CPUPROFILER_EVENT_SCOPE(HeartBeat); // 用于在CPU性能分析器中记录心跳事件
-
FThreadHeartBeat::Get().HeartBeat(true); // 给诊断线程发一个心跳
-
FGameThreadHitchHeartBeat::Get().FrameStart(); // 游戏线程帧开始,卡顿检测
-
FPlatformMisc::TickHotfixables(); // tick 热修复,
-
TickRenderingTickables(); // 遍历渲染线程的tickable 对象,执行tick
-
FMoviePlayerProxy::BlockingForceFinished(); // 卡住,等待电影播放完才能继续
-
ActiveProfiler->FrameSync(); // 和外部的分析器协同,让外部分析器能够停止虚幻帧,大概这么一个东西
-
FPlatformMisc::BeginNamedEventFrame(); // 开始一个命名事件帧数,用于分析工具记录事件用
-
uint64 CurrentFrameCounter = GFrameCounter; // 当前帧计数
-
TraceNamedEventsToggler.Update(bTraceCpuChannelEnabled && UE::Trace::IsTracing()); // 更新自动命名事件开关的状态
-
IConsoleManager::Get().CallAllConsoleVariableSinks(); // 更新控制台变量
#if WITH_PROFILEGPU && !UE_BUILD_SHIPPING
// Issue the measurement of the execution time of a basic LongGPUTask unit on the very first frame
// The results will be retrived on the first call of IssueScalableLongGPUTask
if (GFrameCounter == 0 && IsFeatureLevelSupported(GMaxRHIShaderPlatform, ERHIFeatureLevel::SM5) && FApp::CanEverRender())
{
FlushRenderingCommands();
ENQUEUE_RENDER_COMMAND(MeasureLongGPUTaskExecutionTimeCmd)(
[](FRHICommandListImmediate& RHICmdList)
{
MeasureLongGPUTaskExecutionTime(RHICmdList);
});
}
#endif
如果第一帧,特性级别支持,
FlushRenderingCommands(); // 刷新渲染命令列表,里面围栏等待渲染完成
ENQUEUE_RENDER_COMMAND 里面的东西在渲染线程执行。
MeasureLongGPUTaskExecutionTime(RHICmdList); // 测量长时间的GPU任务执行时间,命令添加到渲染命令队列中。
-
FCoreDelegates::OnBeginFrame.Broadcast();
-
GLog->FlushThreadedLogs(EOutputDeviceRedirectorFlushOptions::Async); // 刷新由其他线程缓存的LOG
-
GEngine->UpdateTimeAndHandleMaxTickRate(); // 更新时间,处理最大tick帧率。
-
GEngine->SetSimulationLatencyMarkerStart(CurrentFrameCounter); // 设置模拟延迟标记
// 渲染帧相关
- ENQUEUE_RENDER_COMMAND: BeginFrameRenderThread(RHICmdList, CurrentFrameCounter); // 渲染线程调用开始帧
- ENQUEUE_RENDER_COMMAND: for all Scene => Scene->StartFrame(); // 渲染线程,场景开始帧
- GEngine->EmitDynamicResolutionEvent(EDynamicResolutionStateEvent::BeginFrame); // 动态分辨率的开始帧
// 监视统计
-
GEngine->TickPerformanceMonitoring( FApp::GetDeltaTime() ); // 性能监视器的 tick
-
ResetAsyncLoadingStats // 重置异步加载的统计数据
-
GMalloc->UpdateStats(); // 内存统计
-
FStats::AdvanceFrame( false, FStats::FOnAdvanceRenderingThreadStats::CreateStatic( &AdvanceRenderingThreadStatsGT ) );
- 推进帧状态,并执行 AdvanceRenderingThreadStatsGT
- 会添加渲染命令 AdvanceRenderingThreadStats
-
CalculateFPSTimings(); // FPS
-
ENQUEUE_RENDER_COMMAND
- FDeferredUpdateResource::ResetNeedsUpdate(); // 重置需要延迟更新的资源
- FlushPendingDeleteRHIResources_RenderThread(); // 刷新待删除的渲染线程RHI资源
-
bIdleMode = ShouldUseIdleMode();
- if bIdleMode: FPlatformProcess::Sleep(.1f); // 空闲模式sleep
-
GNewWorldToMetersScale // 世界到米的缩放
-
FPlatformFileManager::Get().TickActivePlatformFile(); // 更新活动平台文件,
-
FCoreDelegates::OnSamplingInput.Broadcast(); // 采样输入事件
-
SlateApp.PollGameDeviceState() // 处理累计的slate输入
-
FRDGBuilder::InitResourceDump(); // RDG初始化,这个是渲染相关的
-
GEngine->Tick(FApp::GetDeltaTime(), bIdleMode);
UUnrealEdEngine::Tick
void UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode)
{
Super::Tick( DeltaSeconds, bIdleMode ); // void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode )
// 。。。
}
UEditorEngine::Tick
UUnrealEdEngine::Tick 》UEditorEngine::Tick
void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode )
-
FCoreUObjectDelegates::ObjectsModifiedThisFrame.Empty(); // 清空本帧修改对象的列表
-
WorldList.Reserve(WorldList.Num() + 10); // 预留空间给这一帧要创建的World
-
IConsoleManager::Get().CallAllConsoleVariableSinks(); // 控制台变量的回调函数,(~的控制台,的变量,有些被修改了,要回调他)
-
FRemoteConfigAsyncTaskManager::Get()->Tick(); // 更新远程配置IO管理器
-
CleanupGameViewport(); // 清除已关闭的游戏视口
-
If all viewports closed, close the current play level.
- EndPlayMap();
-
EditorContext.World()->ConditionallyBuildStreamingData(); // 根据条件重新构建流式数据,把需要加载的关卡加到流式管理器中
-
TimerManager->Tick(DeltaSeconds);
-
StaticTick(DeltaSeconds, !!GAsyncLoadingUseFullTimeLimit, GAsyncLoadingTimeLimit / 1000.f);
- ProcessAsyncLoading(true, bUseFullTimeLimit, AsyncLoadingTime);
- Serializes a bit of data each frame with a soft time limit. The function is designed to be able to fully load a package in a single pass given sufficient time.
- Set name table stats.
- ProcessAsyncLoading(true, bUseFullTimeLimit, AsyncLoadingTime);
// 分析工具
-
FEngineAnalytics::Tick(DeltaSeconds); // 分析工具tick
-
FStudioAnalytics::Tick(DeltaSeconds); // 啥也没有
-
找有音频焦点的视口。可能会 FApp::SetVolumeMultiplier 设置声音,是否播放。
-
FTickableEditorObject::TickObjects( DeltaSeconds );
-
FAssetRegistryModule::TickAssetRegistry(DeltaSeconds); // 资产注册表,编辑器设置asset manager 里面可以设置。primary asset types to scan
-
SourceCodeAccessModule.GetAccessor().Tick(DeltaSeconds); // 点击跳到vs代码的那个模块tick
-
DirectoryWatcherModule.Get()->Tick(DeltaSeconds); // 目录监控的tick
-
EditorContext.World()->Tick(TickType, DeltaSeconds); // 编辑器 World 的Tick
// Perform editor level streaming previs if no PIE session is currently in progress.
更新流关卡的显示状态
- 遍历所有视口
- 对于 ViewportClient->IsPerspective() 透视视口和 bLevelStreamingVolumePrevis 开启了流式加载体积预览的视口
- 计算视点是否在流式加载体积内,并根据计算结果更新流式加载级别的可见状态
- EditorContext.World()->HasStreamingLevelsToConsider()
- EditorContext.World()->UpdateLevelStreaming()
// PIE & SIE
-
bool bToggledBetweenPIEandSIE = bIsToggleBetweenPIEandSIEQueued; // 上一帧是否有PIE, SIE 状态
-
if (PlaySessionRequest.IsSet())
- StartQueuedPlaySessionRequest(); // SIE 下点物体,右键从此处运行
-
bIsToggleBetweenPIEandSIEQueued
- ToggleBetweenPIEandSIE(); // 切换PIE 和 SIE
-
AddPendingLateJoinClient(); // play as client 模式下,使用 add client 快捷键(keyboard shortcuts)添加新的客户端会跑到这,快捷键需要搜索add client设置一下
-
!bFirstTick
- USkyLightComponent::UpdateSkyCaptureContents(EditorContext.World()); // 反射捕获和天光
- UReflectionCaptureComponent::UpdateReflectionCaptureContents(EditorContext.World(), nullptr, false, false, bInsideTick); // 更新天光捕获内容
-
EmitDynamicResolutionEvent(EDynamicResolutionStateEvent::BeginFrame); // 动态分辨率开始帧事件
-
if( FSlateThrottleManager::Get().IsAllowingExpensiveTasks() )
- TArray<FWorldContext*> LocalPieContextPtrs; // 维护一个 LocalPieContextPtrs,大概就是找到所有PIE的World
- 更新 bMovieSequenceTickWillBeHandled // 收集每一个World是否需要更新多媒体的Tick
-
MediaModule->TickPreEngine(); // 多媒体Tick,如果需要
-
*for (FWorldContext PieContextPtr : LocalPieContextPtrs) // 对所有PIE的World,Tick World, GameViewport 等等,具体一点**
- TickWorldTravel(PieContext, TickDeltaSeconds); // Tick all travel and Pending NetGames (Seamless, server, client)
- UpdateTransitionType(PlayWorld); // Updates 'connecting' message in PIE network games
- PlayWorld->UpdateLevelStreaming(); // DS 更新关卡流
- GameViewport->SetDropDetail(TickDeltaSeconds); // 根据帧率降低细节
- PieContext.World()->Tick( LEVELTICK_All, TickDeltaSeconds ); // UWorld Tick
- 非第一次tick,更新天光,反射
- GameViewport->Tick(TickDeltaSeconds); // GameViewport Tick
-
FTickableGameObject::TickObjects(nullptr, TickType, false, DeltaSeconds);
-
MediaModule->TickPostEngine(); // 多媒体tick
-
GPlayInEditorID = INDEX_NONE;
-
CleanupGameViewport(); // 清理已经关闭的 Viewport
-
// If all viewports closed, close the current play level. 如果所有viewport关闭,就关闭关卡
- EndPlayMap();
-
EditorWorldExtensionsManager->Tick( DeltaSeconds ); // 更新所有编辑器的扩展
-
AllViewportClients 对所有客户端视口做tick
-
!bIsMouseOverAnyLevelViewport // 鼠标是否悬停在关卡上
- FLevelEditorViewportClient::ClearHoverFromObjects(); // 没有就清除悬停的效果,拖拽窗口悬停在其他窗口上的一个显示效果
-
EditorContext.World()->CommitModelSurfaces(); // 提交BSP模型的修改
-
ForEachObjectOfClass(UWorld::StaticClass(), [&WorldsToEOFUpdate](UObject* WorldObj)
- WorldsToEOFUpdate.Add(World); // 遍历World,是否需要延迟就的末尾帧需要更新
-
World->SendAllEndOfFrameUpdates(); // 然后更新,把延迟更新的组件发送到渲染线程
===================
渲染相关
-
const bool bAllWindowsHidden = !bHasFocus && AreAllWindowsHidden(); // 编辑器窗口是否被隐藏,比如运行的时候
-
FPixelInspectorModule& PixelInspectorModule = FModuleManager::LoadModuleChecked
(TEXT("PixelInspectorModule")); // tools->debug->pixel inspector 可以找到这个像素查看器工具 -
// Render view parents, then view children. GCurrentLevelEditingViewportClient 这个是否要被渲染
- UpdateSingleViewportClient
-
for (int32 bRenderingChildren = 0; bRenderingChildren < 2; bRenderingChildren++)
- UpdateSingleViewportClient
-
ENQUEUE_RENDER_COMMAND RHICmdList.ImmediateFlush(EImmediateFlushType::FlushRHIThreadFlushResources); // 让渲染线程马上刷新RHI资源
-
if (!bAllWindowsHidden || bRunDrawWithEditorHidden)
- GetRendererModule().PostRenderAllViewports();
- ENQUEUE_RENDER_COMMAND CoarseMeshSM->UpdateResourceStates(); // 更新资源状态
- GetRendererModule().PostRenderAllViewports();
-
ISourceControlModule::Get().Tick();
-
ILocalizationServiceModule::Get().Tick();
-
IsAllowingExpensiveTasks
- 遍历所有PIE World
- GameViewport->Viewport->Draw()
-
IStreamingManager::Get().Tick(DeltaSeconds);
-
AudioDeviceManager // 更新音频驱动
-
EditorContext.World()->UpdateConstraintActors(); // 物理约束角色
-
ENQUEUE_RENDER_COMMAND
- GRenderingRealtimeClock.Tick(DeltaTime); 更新渲染时钟
- GRenderTargetPool.TickPoolElements(); 渲染目标池
- FRDGBuilder::TickPoolElements();
- ICustomResourcePool::TickPoolElements(RHICmdList); // 资源池
// 资产分析和性能分析
-
FUnrealEdMisc::Get().TickAssetAnalytics();
-
FUnrealEdMisc::Get().TickPerformanceAnalytics();
-
BroadcastPostEditorTick(DeltaSeconds); // 事件
UEditorEngine::Tick End
UUnrealEdEngine::Tick 》
void UUnrealEdEngine::Tick(float DeltaSeconds, bool bIdleMode)
{
Super::Tick( DeltaSeconds, bIdleMode ); // void UEditorEngine::Tick( float DeltaSeconds, bool bIdleMode )
// 。。。
}
回到这里
-
PackageAutoSaver->UpdateAutoSaveCount(DeltaSeconds); // 根据是否有耗时任务等等情况,更新自动保存技术
-
PackageAutoSaver->AttemptAutoSave(); // 尝试自动保存
-
AttemptModifiedPackageNotification(); // 尝试通知用户有修改的包需要签出和写入权限的警告
-
UpdateBuildLighting // 更新构建光照
UUnrealEdEngine::Tick End
FEngineLoop::Tick()
void FEngineLoop::Tick()
{
GEngine->Tick(FApp::GetDeltaTime(), bIdleMode);
// ...
}
回到这个位置继续往下
- FPreLoadScreenManager // 电影相关
- FAssetCompilingManager::Get().ProcessAsyncTasks(true); // FAssetCompilingManager 异步任务
- FMoviePlayerProxy::BlockingForceFinished(); // 阻塞等待电影播完
Slate相关
-
ProcessLocalPlayerSlateOperations();
-
FSlateApplication::Get().Tick(ESlateTickType::PlatformAndInput);
-
// process concurrent Slate tasks
-
ENQUEUE_RENDER_COMMAND
- FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::WaitForOutstandingTasksOnly);
-
ClearPendingStatGroups // 则清除所有待处理的统计组通知
// 自动化模块,自动化测试
- FModuleManager::GetModuleChecked
(AutomationController).Tick(); - FModuleManager::GetModuleChecked
(AutomationWorkerModuleName).Tick();
RHITick( FApp::GetDeltaTime() ); // Update RHI.
void FD3D12DynamicRHI::RHITick(float DeltaTime)
{
check(IsInGameThread());
// Check if any swap chains have been invalidated.
auto& Viewports = GetAdapter().GetViewports();
for (int32 ViewportIndex = 0; ViewportIndex < Viewports.Num(); ViewportIndex++)
{
Viewports[ViewportIndex]->ConditionalResetSwapChain(false);
}
}
更换交换链
-
GEngine->SetSimulationLatencyMarkerEnd(CurrentFrameCounter); // 设置模拟延迟结束
-
GFrameCounter++;
-
ENQUEUE_RENDER_COMMAND GFrameCounterRenderThread = CurrentFrameCounter; // 帧数传给渲染线程
-
if (GFrameCounter > 6)
- TotalTickTime += FApp::GetDeltaTime();
-
PendingCleanupObjects = GetPendingCleanupObjects(); // 下一帧需要清理的对象
-
是否有命令 r.OneFrameThreadLag
- 有就用 static FFrameEndSync FrameEndSync; 同步渲染线程和主线程
-
DeleteLoaders(); // destroy all linkers pending delete
-
FTSTicker::GetCoreTicker().Tick(FApp::GetDeltaTime());
-
FThreadManager::Get().Tick();
-
GEngine->TickDeferredCommands();
-
// tick media framework
-
FCoreDelegates::OnEndFrame.Broadcast();
-
FRDGBuilder::EndResourceDump(); // 结束RDG 资源存储
-
GEngine->EmitDynamicResolutionEvent(EDynamicResolutionStateEvent::EndFrame); // 动态分辨率结束事件
-
ENQUEUE_RENDER_COMMAND EndFrameRenderThread(RHICmdList, CurrentFrameCounter);