UE游戏、渲染线程

· ☕ 3 分钟 · 👻 Victor
🏷️
  • #C++
  • #UE4
  • #Game
  • 探索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函数。

    分享

    redisread
    作者
    Victor
    Full Stack