You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Various legacy game thread code assumes the render thread will never be more than one frame behind. The original change in 36468180 switched from syncing the GT with the RT, to syncing the GT with the RHIT. That left the render thread "floating" in the center of the pipeline, and led to cases where resources are deleted too soon. - New approach is to always sync with the GT with the N-1 RT frame, so the GT is never too far ahead of the RT. This maintains compatibility with the legacy GT code paths. In addition to the GT->RT sync, we also sync with the RHIT to prevent the engine running ahead, which was the original bug that 36468180 was fixing. - "r.GTSyncType" mode 0 now allows for 1 frame of GT->RT overlap, and 2 frames of GT->RHIT overlap. - For debugging purposes, "r.GTSyncType" can also be made negative, which increases the number of GT->RHIT overlap frames, e.g. "r.GTSyncType -3" gives 5 frames of GT->RHIT overlap. While this is not overly useful in a shipped title, it can be used to prove the correctness of the rendering pipeline. - Merged the FDeferredCleanupInterface / FPendingCleanupObjects processing into the FFrameEndSync code path, plus made FFrameEndSync a static singleton. This allows us to manage the N frames of overlap between the GT and RHIT in a central place, and correctly cleanup deferred resources when the RT fences have passed. In future, we will need to revisit this as part of the frame pacing initiative. Game thread code should be written to not require render thread fences for correctness / threadsafety. #jira UE-223692 #rb zach.bethel [CL 36758377 by luke thatcher in 5.5 branch]
194 lines
4.7 KiB
C++
194 lines
4.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
|
|
#if WITH_ENGINE
|
|
#include "UnrealEngine.h"
|
|
#endif
|
|
|
|
class FEngineService;
|
|
class FTraceService;
|
|
class ISessionService;
|
|
class FSlateRenderer;
|
|
|
|
struct FScopedSlowTask;
|
|
|
|
struct FPreInitContext
|
|
{
|
|
bool bDumpEarlyConfigReads = false;
|
|
bool bDumpEarlyPakFileReads = false;
|
|
bool bForceQuitAfterEarlyReads = false;
|
|
bool bWithConfigPatching = false;
|
|
UE_DEPRECATED(5.5, "Use gc.MaxObjectsNotConsideredByGC=0 ini setting instead")
|
|
bool bDisableDisregardForGC = false;
|
|
bool bHasEditorToken = false;
|
|
bool bIsRegularClient = false;
|
|
UE_DEPRECATED(5.1, "Use bIsPossiblyUnrecognizedCommandlet instead")
|
|
bool bTokenDoesNotHaveDash = false;
|
|
bool bIsPossiblyUnrecognizedCommandlet = false;
|
|
|
|
FString Token;
|
|
FString CommandletCommandLine;
|
|
|
|
FScopedSlowTask* SlowTaskPtr = nullptr;
|
|
|
|
void Cleanup();
|
|
|
|
#if WITH_ENGINE && !UE_SERVER
|
|
TSharedPtr<FSlateRenderer> SlateRenderer;
|
|
#endif // WITH_ENGINE && !UE_SERVER
|
|
};
|
|
|
|
/**
|
|
* 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();
|
|
|
|
/** Allow override of the project module loaded from project file */
|
|
void OverrideProjectModule(const FString& InOriginalProjectModuleName, const FString& InReplacementProjectModuleName);
|
|
|
|
/** 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;
|
|
|
|
#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;
|
|
|
|
private:
|
|
|
|
|
|
#if WITH_ENGINE
|
|
|
|
/** Holds the engine service. */
|
|
FEngineService* EngineService;
|
|
|
|
/** Trace control service */
|
|
FTraceService* TraceService;
|
|
|
|
/** Holds the application session service. */
|
|
TSharedPtr<ISessionService> SessionService;
|
|
|
|
#endif // WITH_ENGINE
|
|
FPreInitContext PreInitContext;
|
|
};
|
|
|
|
|
|
/** Global engine loop object. This is needed so wxWindows can access it. */
|
|
extern FEngineLoop GEngineLoop;
|