Please enable Javascript to view the contents

UE游戏、渲染线程

 ·  ☕ 3 分钟 · 👀... 阅读

探索UE4游戏线程的进入

游戏线程 & 渲染线程

UE4游戏线程启动

游戏线程每一帧更新所有内容。

Engine-tick

这个tick是哪里打开的?

头文件:Engine\Source\Runtime\Launch\Private\Launch.cpp

image-20200603204559269

Lauch.cpp定义了一个全局的变量FEngineLoop GEngineLoop;

image-20200603204743789

该类路径:Engine\Source\Runtime\Launch\Public\LaunchEngineLoop.h,继承一个接口类IEngineLoop,定义如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * Implements the main engine loop.	
 */
class FEngineLoop
#if WITH_ENGINE
	: public IEngineLoop
#endif
{
public:
	/** Default constructor. */
	FEngineLoop();
	virtual ~FEngineLoop() { }
public:
	/**
	 * Pre-Initialize the main loop, and generates the commandline from standard ArgC/ArgV from main().
	 *
	 * @param ArgC The number of strings in ArgV.
	 * @param ArgV The command line parameters (ArgV[0] is expected to be the executable name).
	 * @param AdditionalCommandLine Optional string to append to the command line (after ArgV is put together).
	 * @return Returns the error level, 0 if successful and > 0 if there were errors.
	 */ 
	int32 PreInit(int32 ArgC, TCHAR* ArgV[], const TCHAR* AdditionalCommandline = nullptr);

	/**
	 * Pre-Initialize the main loop - parse command line, sets up GIsEditor, etc.
	 *
	 * @param CmdLine The command line.
	 * @return The error level; 0 if successful, > 0 if there were errors.
	 */ 
	int32 PreInit(const TCHAR* CmdLine);
	
	/** First part of PreInit. */
	int32 PreInitPreStartupScreen(const TCHAR* CmdLine);

	/** Second part of PreInit. */
	int32 PreInitPostStartupScreen(const TCHAR* CmdLine);

	/** Load all modules needed before Init. */ 
	void LoadPreInitModules();

	/** Load core modules. */
	bool LoadCoreModules();

	/** Clean up PreInit context. */
	void CleanupPreInitContext();

#if WITH_ENGINE
	
	/** Load all core modules needed at startup time. */
	bool LoadStartupCoreModules();
	
	/** Load all modules needed at startup time. */
	bool LoadStartupModules();

	/**
	 * Initialize the main loop (the rest of the initialization).
	 *
	 * @return The error level; 0 if successful, > 0 if there were errors.
	 */ 
	virtual int32 Init() override;

	/** Initialize the timing options from the command line. */ 
	void InitTime();

	/** Performs shut down. */
	void Exit();

	/** Whether the engine should operate in an idle mode that uses no CPU or GPU time. */
	bool ShouldUseIdleMode() const;

	// Advances the main loop.推进主循环
	virtual void Tick() override;

	/** Removes references to any objects pending cleanup by deleting them. */
	virtual void ClearPendingCleanupObjects() override;

#endif // WITH_ENGINE

	/** RHI post-init initialization */
	static void PostInitRHI();

	/** Pre-init HMD device (if necessary). */
	static void PreInitHMDDevice();

public:

	/** Initializes the application. */
	static bool AppInit();

	/**
	 * Prepares the application for shutdown.
	 *
	 * This function is called from within guarded exit code, only during non-error exits.
	 */
	static void AppPreExit();

	/**
	 * Shuts down the application.
	 *
	 * This function called outside guarded exit code, during all exits (including error exits).
	 */
	static void AppExit();

private:

	/** Utility function that processes Slate operations. */
	void ProcessLocalPlayerSlateOperations() const;

protected:

	/** Holds a dynamically expanding array of frame times in milliseconds (if FApp::IsBenchmarking() is set). */
	TArray<float> FrameTimes;

	/** Holds the total time spent ticking engine. */
	double TotalTickTime;
	
	/** Holds the maximum number of seconds engine should be ticked. */
	double MaxTickTime;
	
	/** Holds the maximum number of frames to render in benchmarking mode. */
	uint64 MaxFrameCounter;
	
	/** Holds the number of cycles in the last frame. */
	uint32 LastFrameCycles;

#if WITH_ENGINE

	/** Holds the objects which need to be cleaned up when the rendering thread finishes the previous frame. */
	FPendingCleanupObjects* PendingCleanupObjects;

#endif //WITH_ENGINE

private:

#if WITH_ENGINE

	/** Holds the engine service. */
	FEngineService* EngineService;

	/** Holds the application session service. */
	TSharedPtr<ISessionService> SessionService;

#endif // WITH_ENGINE
	FPreInitContext PreInitContext;
};

该文件只需#include "CoreMinimal.h",最多加上#include "UnrealEngine.h"

接口类,位于路径Engine\Source\Runtime\Engine\Public\UnrealEngine.h

1
2
3
4
5
6
7
8
9
/** Public interface to FEngineLoop so we can call it from editor or editor code */
class IEngineLoop
{
public:
	virtual int32 Init() = 0;
	virtual void Tick() = 0;
	/** Removes references to any objects pending cleanup by deleting them. */
	virtual void ClearPendingCleanupObjects() = 0;
};

开启Tick函数之前需要初始化,初始化函数在Launch.cpp这个文件中:

1
2
3
4
5
6
/* Inits the engine loop */
int32 EngineInit()
{
	int32 ErrorLevel = GEngineLoop.Init();
	return( ErrorLevel );
}

GEngineLoop.Init()函数:

image-20200603212333812

其中会判断是进入那种引擎模式,分为Game模式与Editor模式。

结束引擎的函数为:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/**
 * Shuts down the engine
 */
void EngineExit( void )
{
	// Make sure this is set
	RequestEngineExit(TEXT("EngineExit() was called"));

	GEngineLoop.Exit();
}

也在Launch.cpp

Launch.cpp中的函数多次使用GEngine这个外部变量,这个变量在上面的初始化函数会自定设置为相应的引擎,即Game引擎或者Editor引擎:

所在文件Engine.h

image-20200603212911727

FEngineLoop::Tick()函数会调用GEngine的Tick函数:

image-20200603213738709

也就是本文开始的那个Tick函数。


VictorHong
作者
VictorHong
📚Learner🤓Nerd🌐Developer 努力做有价值的事情