UE4引擎构架浅析思路引导

UE引擎构架浅析思路引导

前言:
刚接触UE时候,想必很多人很难置信UE整个平台框架是从c++Win32框架搭建的,很多人想必对于其实现的基本流程很迷茫,在此,记录自己学习研究步骤,有问题请指出

在Vs中点击在文件中查找,如果是rider或者其他编辑器平台,应该有属于自己的查询方式
在这里插入图片描述
在查找框中搜索int main,并点击查找全部
在这里插入图片描述点击LaunchLumin.cpp中的查找项
在这里插入图片描述
这时候我们看到了此处main函数中的代码代码块:

int main(int argc, char *argv[])
{
    
    
	FPlatformMisc::SetGracefulTerminationHandler();

	int ErrorLevel = 0;

	// read the command line file
	InitCommandLine();
	FPlatformMisc::LowLevelOutputDebugStringf(TEXT("Final commandline: %s\n"), FCommandLine::Get());

#if !UE_BUILD_SHIPPING
	GAlwaysReportCrash = true;	// set by default and reverse the behavior
	if (FParse::Param(FCommandLine::Get(), TEXT("nocrashreports")) || FParse::Param(FCommandLine::Get(), TEXT("no-crashreports")))
	{
    
    
		GAlwaysReportCrash = false;
	}
#endif

	if (!IncreasePerProcessLimits())
	{
    
    
		fprintf(stderr, "Could not set desired per-process limits, consider changing system limits.\n");
		ErrorLevel = 1;
		return ErrorLevel;
	}
// 		if (!FPlatformMisc::IsDebuggerPresent() || GAlwaysReportCrash)
// 		{
    
    
// 			// Use default crash handler, but we still need to set this up to register signal handlers
// 			FPlatformMisc::SetCrashHandler(nullptr);
// 		}
// 		ErrorLevel = GuardedMain(FCommandLine::Get());


	// initialize the engine
	GEngineLoop.PreInit(0, NULL, FCommandLine::Get());

	// initialize HMDs 
	// @todo Lumin: I guess we don't need this?
	// InitHMDs();

	UE_LOG(LogAndroid, Display, TEXT("Passed PreInit()"));

	GLog->SetCurrentThreadAsMasterThread();

	GEngineLoop.Init();

	UE_LOG(LogAndroid, Log, TEXT("Passed GEngineLoop.Init()"));

#if !UE_BUILD_SHIPPING
	if (FParse::Param(FCommandLine::Get(), TEXT("Messaging")))
	{
    
    
		// initialize messaging subsystem
		FModuleManager::LoadModuleChecked<IMessagingModule>("Messaging");
		TSharedPtr<ISessionService> SessionService = FModuleManager::LoadModuleChecked<ISessionServicesModule>("SessionServices").GetSessionService();
		SessionService->Start();

		// Initialize functional testing
		FModuleManager::Get().LoadModule("FunctionalTesting");
	}
#endif

	// tick until done
	while (!IsEngineExitRequested())
	{
    
    
// 		FAppEventManager::GetInstance()->Tick();
// 		if(!FAppEventManager::GetInstance()->IsGamePaused())
		{
    
    
			GEngineLoop.Tick();
		}
// 		else
// 		{
    
    
// 			// use less CPU when paused
// 			FPlatformProcess::Sleep(0.10f);
// 		}

#if !UE_BUILD_SHIPPING
		// show console window on next game tick
// 		if (GShowConsoleWindowNextTick)
// 		{
    
    
// 			GShowConsoleWindowNextTick = false;
// 			AndroidThunkCpp_ShowConsoleWindow();
// 		}
#endif
	}
// 	FAppEventManager::GetInstance()->TriggerEmptyQueue();

	UE_LOG(LogAndroid, Log, TEXT("Exiting"));

	// exit out!
	GEngineLoop.Exit();
	FEngineLoop::AppExit();

	FPlatformMisc::LowLevelOutputDebugString(TEXT("Exiting is over"));

	if (ErrorLevel)
	{
    
    
		printf("Exiting abnormally (error code: %d)\n", ErrorLevel);
	}
	return ErrorLevel;
}

看到这,想必大家知道了引擎的入口从哪开始的了
在这里插入图片描述

接着转入引擎的循环函数Tick()
在这里插入图片描述
这便是引擎的Tick函数

void FEngineLoop::Tick()
{
    
    
    // make sure to catch any FMemStack uses outside of UWorld::Tick
    FMemMark MemStackMark(FMemStack::Get());

#if !UE_BUILD_SHIPPING && !UE_BUILD_TEST && MALLOC_GT_HOOKS
	FScopedSampleMallocChurn ChurnTracker;
#endif
	// let the low level mem tracker pump once a frame to update states
	LLM(FLowLevelMemTracker::Get().UpdateStatsPerFrame());

	LLM_SCOPE(ELLMTag::EngineMisc);

	// Send a heartbeat for the diagnostics thread
	FThreadHeartBeat::Get().HeartBeat(true);
	FGameThreadHitchHeartBeat::Get().FrameStart();
	FPlatformMisc::TickHotfixables();

	// Make sure something is ticking the rendering tickables in -onethread mode to avoid leaks/bugs.
	if (!GUseThreadedRendering && !GIsRenderingThreadSuspended.Load(EMemoryOrder::Relaxed))
	{
    
    
		TickRenderingTickables();
	}

	// Ensure we aren't starting a frame while loading or playing a loading movie
	ensure(GetMoviePlayer()->IsLoadingFinished() && !GetMoviePlayer()->IsMovieCurrentlyPlaying());

#if UE_EXTERNAL_PROFILING_ENABLED
	FExternalProfiler* ActiveProfiler = FActiveExternalProfilerBase::GetActiveProfiler();
	if (ActiveProfiler)
	{
    
    
		ActiveProfiler->FrameSync();
	}
#endif		// UE_EXTERNAL_PROFILING_ENABLED

	FPlatformMisc::BeginNamedEventFrame();

	uint64 CurrentFrameCounter = GFrameCounter;

#if ENABLE_NAMED_EVENTS
	TCHAR IndexedFrameString[32] = {
    
     0 };
	const TCHAR* FrameString = nullptr;
	if (UE_TRACE_CHANNELEXPR_IS_ENABLED(CpuChannel))
	{
    
    
		FrameString = TEXT("FEngineLoop");
	}
	else
	{
    
    
#if PLATFORM_LIMIT_PROFILER_UNIQUE_NAMED_EVENTS
		FrameString = TEXT("FEngineLoop");
#else
		FCString::Snprintf(IndexedFrameString, 32, TEXT("Frame %d"), CurrentFrameCounter);
		FrameString = IndexedFrameString;
#endif
	}
	SCOPED_NAMED_EVENT_TCHAR(FrameString, FColor::Red);
#endif

	// execute callbacks for cvar changes
	{
    
    
		QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_CallAllConsoleVariableSinks);
		IConsoleManager::Get().CallAllConsoleVariableSinks();
	}

	{
    
    
		TRACE_BEGIN_FRAME(TraceFrameType_Game);

		SCOPE_CYCLE_COUNTER(STAT_FrameTime);

		#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

		FCoreDelegates::OnBeginFrame.Broadcast();

		// flush debug output which has been buffered by other threads
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_FlushThreadedLogs); 
			GLog->FlushThreadedLogs();
		}

		// exit if frame limit is reached in benchmark mode, or if time limit is reached
		if ((FApp::IsBenchmarking() && MaxFrameCounter && (GFrameCounter > MaxFrameCounter)) ||
			(MaxTickTime && (TotalTickTime > MaxTickTime)))
		{
    
    
			FPlatformMisc::RequestExit(0);
		}

		// set FApp::CurrentTime, FApp::DeltaTime and potentially wait to enforce max tick rate
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_UpdateTimeAndHandleMaxTickRate);
			GEngine->UpdateTimeAndHandleMaxTickRate();
			GEngine->SetGameLatencyMarkerStart(CurrentFrameCounter);
		}

		for (const FWorldContext& Context : GEngine->GetWorldContexts())
		{
    
    
			UWorld* CurrentWorld = Context.World();
			if (CurrentWorld)
			{
    
    
				FSceneInterface* Scene = CurrentWorld->Scene;
				ENQUEUE_RENDER_COMMAND(UpdateScenePrimitives)(
					[Scene](FRHICommandListImmediate& RHICmdList)
				{
    
    
					Scene->UpdateAllPrimitiveSceneInfos(RHICmdList);
				});
			}
		}

		// beginning of RHI frame
		ENQUEUE_RENDER_COMMAND(BeginFrame)([CurrentFrameCounter](FRHICommandListImmediate& RHICmdList)
		{
    
    
			BeginFrameRenderThread(RHICmdList, CurrentFrameCounter);
		});

		for (const FWorldContext& Context : GEngine->GetWorldContexts())
		{
    
    
			UWorld* CurrentWorld = Context.World();
			if (CurrentWorld)
			{
    
    
				FSceneInterface* Scene = CurrentWorld->Scene;

				ENQUEUE_RENDER_COMMAND(SceneStartFrame)([Scene](FRHICommandListImmediate& RHICmdList)
				{
    
    
					Scene->StartFrame();
				});
			}
		}

#if !UE_SERVER && WITH_ENGINE
		if (!GIsEditor && GEngine->GameViewport && GEngine->GameViewport->GetWorld() && GEngine->GameViewport->GetWorld()->IsCameraMoveable())
		{
    
    
			// When not in editor, we emit dynamic resolution's begin frame right after RHI's.
			GEngine->EmitDynamicResolutionEvent(EDynamicResolutionStateEvent::BeginFrame);
		}
#endif

		// tick performance monitoring
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_TickFPSChart);
			GEngine->TickPerformanceMonitoring( FApp::GetDeltaTime() );

			extern COREUOBJECT_API void ResetAsyncLoadingStats();
			ResetAsyncLoadingStats();
		}

#if UPDATE_MALLOC_STATS
		// update memory allocator stats
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Malloc_UpdateStats);
			GMalloc->UpdateStats();
		}
#endif
	}

	FStats::AdvanceFrame( false, FStats::FOnAdvanceRenderingThreadStats::CreateStatic( &AdvanceRenderingThreadStatsGT ) );

	{
    
    
		SCOPE_CYCLE_COUNTER( STAT_FrameTime );

		// Calculates average FPS/MS (outside STATS on purpose)
		CalculateFPSTimings();

		// Note the start of a new frame
		MALLOC_PROFILER(GMalloc->Exec(nullptr, *FString::Printf(TEXT("SNAPSHOTMEMORYFRAME")),*GLog));

		// handle some per-frame tasks on the rendering thread
		ENQUEUE_RENDER_COMMAND(ResetDeferredUpdates)(
			[](FRHICommandList& RHICmdList)
			{
    
    
				FDeferredUpdateResource::ResetNeedsUpdate();
				FlushPendingDeleteRHIResources_RenderThread();
			});

		{
    
    
			SCOPE_CYCLE_COUNTER(STAT_PumpMessages);
			FPlatformApplicationMisc::PumpMessages(true);
		}

		bool bIdleMode;
		{
    
    

			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Idle);

			// Idle mode prevents ticking and rendering completely
			bIdleMode = ShouldUseIdleMode();
			if (bIdleMode)
			{
    
    
				// Yield CPU time
				FPlatformProcess::Sleep(.1f);
			}
		}

		// @todo vreditor urgent: Temporary hack to allow world-to-meters to be set before
		// input is polled for motion controller devices each frame.
		extern ENGINE_API float GNewWorldToMetersScale;
		if( GNewWorldToMetersScale != 0.0f  )
		{
    
    
#if WITH_ENGINE
			UWorld* WorldToScale = GWorld;

#if WITH_EDITOR
			if( GIsEditor && GEditor->PlayWorld != nullptr && GEditor->bIsSimulatingInEditor )
			{
    
    
				WorldToScale = GEditor->PlayWorld;
			}
#endif //WITH_EDITOR

			if( WorldToScale != nullptr )
			{
    
    
				if( GNewWorldToMetersScale != WorldToScale->GetWorldSettings()->WorldToMeters )
				{
    
    
					WorldToScale->GetWorldSettings()->WorldToMeters = GNewWorldToMetersScale;
				}
			}

			GNewWorldToMetersScale = 0.0f;
		}
#endif //WITH_ENGINE

		// tick active platform files
		FPlatformFileManager::Get().TickActivePlatformFile();

		// Roughly track the time when the input was sampled
		FCoreDelegates::OnSamplingInput.Broadcast();

		// process accumulated Slate input
		if (FSlateApplication::IsInitialized() && !bIdleMode)
		{
    
    
			CSV_SCOPED_TIMING_STAT_EXCLUSIVE(Input);
			SCOPE_TIME_GUARD(TEXT("SlateInput"));
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_SlateInput);
			LLM_SCOPE(ELLMTag::UI);

			FSlateApplication& SlateApp = FSlateApplication::Get();
            {
    
    
                QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_PollGameDeviceState);
                SlateApp.PollGameDeviceState();
            }
			// Gives widgets a chance to process any accumulated input
            {
    
    
                QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_FinishedInputThisFrame);
                SlateApp.FinishedInputThisFrame();
            }
		}

#if !UE_SERVER
		// tick media framework
		static const FName MediaModuleName(TEXT("Media"));
		IMediaModule* MediaModule = FModuleManager::LoadModulePtr<IMediaModule>(MediaModuleName);

		if (MediaModule != nullptr)
		{
    
    
			MediaModule->TickPreEngine();
		}
#endif

		// main game engine tick (world, game objects, etc.)
		GEngine->Tick(FApp::GetDeltaTime(), bIdleMode);

		// If a movie that is blocking the game thread has been playing,
		// wait for it to finish before we continue to tick or tick again
		// We do this right after GEngine->Tick() because that is where user code would initiate a load / movie.
		{
    
    
            if (FPreLoadScreenManager::Get())
            {
    
    
                if (FPreLoadScreenManager::Get()->HasRegisteredPreLoadScreenType(EPreLoadScreenTypes::EngineLoadingScreen))
                {
    
    
                    //Wait for any Engine Loading Screen to stop
                    if (FPreLoadScreenManager::Get()->HasActivePreLoadScreenType(EPreLoadScreenTypes::EngineLoadingScreen))
                    {
    
    
                        FPreLoadScreenManager::Get()->WaitForEngineLoadingScreenToFinish();
                    }

                    //Switch Game Window Back
                    UGameEngine* GameEngine = Cast<UGameEngine>(GEngine);
                    if (GameEngine)
                    {
    
    
                        GameEngine->SwitchGameWindowToUseGameViewport();
                    }
                }
                
                //Destroy / Clean Up PreLoadScreenManager as we are now done
                FPreLoadScreenManager::Destroy();
            }
			else
			{
    
    
				QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_WaitForMovieToFinish);
				GetMoviePlayer()->WaitForMovieToFinish(true);
			}
		}

		if (GShaderCompilingManager)
		{
    
    
			// Process any asynchronous shader compile results that are ready, limit execution time
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_GShaderCompilingManager);
			GShaderCompilingManager->ProcessAsyncResults(true, false);
		}

		if (GDistanceFieldAsyncQueue)
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_GDistanceFieldAsyncQueue);
			GDistanceFieldAsyncQueue->ProcessAsyncTasks();
		}

#if !UE_SERVER
		// tick media framework
		if (MediaModule != nullptr)
		{
    
    
			MediaModule->TickPreSlate();
		}
#endif

		// Tick the platform and input portion of Slate application, we need to do this before we run things
		// concurrent with networking.
		if (FSlateApplication::IsInitialized() && !bIdleMode)
		{
    
    
			{
    
    
				QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_ProcessPlayerControllersSlateOperations);
				check(!IsRunningDedicatedServer());

				// Process slate operations accumulated in the world ticks.
				ProcessLocalPlayerSlateOperations();
			}

			FSlateApplication::Get().Tick(ESlateTickType::PlatformAndInput);
		}

#if WITH_ENGINE
		// process concurrent Slate tasks
		FGraphEventRef ConcurrentTask;
		const bool bDoConcurrentSlateTick = GEngine->ShouldDoAsyncEndOfFrameTasks();

		const UGameViewportClient* const GameViewport = GEngine->GameViewport;
		const UWorld* const GameViewportWorld = GameViewport ? GameViewport->GetWorld() : nullptr;
		UDemoNetDriver* const CurrentDemoNetDriver = GameViewportWorld ? GameViewportWorld->GetDemoNetDriver() : nullptr;

		// Optionally validate that Slate has not modified any replicated properties for client replay recording.
		FDemoSavedPropertyState PreSlateObjectStates;
		const bool bValidateReplicatedProperties = CurrentDemoNetDriver && CVarDoAsyncEndOfFrameTasksValidateReplicatedProperties.GetValueOnGameThread() != 0;
		if (bValidateReplicatedProperties)
		{
    
    
			PreSlateObjectStates = CurrentDemoNetDriver->SavePropertyState();
		}

		if (bDoConcurrentSlateTick)
		{
    
    
			const float DeltaSeconds = FApp::GetDeltaTime();

			if (CurrentDemoNetDriver && CurrentDemoNetDriver->ShouldTickFlushAsyncEndOfFrame())
			{
    
    
				ConcurrentTask = TGraphTask<FExecuteConcurrentWithSlateTickTask>::CreateTask(nullptr, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(
					[CurrentDemoNetDriver, DeltaSeconds]()
				{
    
    
					if (CVarDoAsyncEndOfFrameTasksRandomize.GetValueOnAnyThread(true) > 0)
					{
    
    
						FPlatformProcess::Sleep(FMath::RandRange(0.0f, .003f)); // this shakes up the threading to find race conditions
					}

					if (CurrentDemoNetDriver != nullptr)
					{
    
    
						CurrentDemoNetDriver->TickFlushAsyncEndOfFrame(DeltaSeconds);
					}
				});
			}
		}
#endif

		// Tick(Advance) Time for the application and then tick and paint slate application widgets.
		// We split separate this action from the one above to permit running network replication concurrent with slate widget ticking and painting.
		if (FSlateApplication::IsInitialized() && !bIdleMode)
		{
    
    
			FSlateApplication::Get().Tick(ESlateTickType::TimeAndWidgets);
		}

#if WITH_ENGINE
		if (bValidateReplicatedProperties)
		{
    
    
			const bool bReplicatedPropertiesDifferent = CurrentDemoNetDriver->ComparePropertyState(PreSlateObjectStates);
			if (bReplicatedPropertiesDifferent)
			{
    
    
				UE_LOG(LogInit, Log, TEXT("Replicated properties changed during Slate tick!"));
			}
		}

		if (ConcurrentTask.GetReference())
		{
    
    
			CSV_SCOPED_SET_WAIT_STAT(Slate);

			QUICK_SCOPE_CYCLE_COUNTER(STAT_ConcurrentWithSlateTickTasks_Wait);
			FTaskGraphInterface::Get().WaitUntilTaskCompletes(ConcurrentTask);
			ConcurrentTask = nullptr;
		}
		{
    
    
			ENQUEUE_RENDER_COMMAND(WaitForOutstandingTasksOnly_for_DelaySceneRenderCompletion)(
				[](FRHICommandList& RHICmdList)
				{
    
    
					QUICK_SCOPE_CYCLE_COUNTER(STAT_DelaySceneRenderCompletion_TaskWait);
					FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::WaitForOutstandingTasksOnly);
				});
		}
#endif

#if STATS
		// Clear any stat group notifications we have pending just in case they weren't claimed during FSlateApplication::Get().Tick
		extern CORE_API void ClearPendingStatGroups();
		ClearPendingStatGroups();
#endif

#if WITH_EDITOR && !UE_BUILD_SHIPPING
		// tick automation controller (Editor only)
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_AutomationController);
			static FName AutomationController("AutomationController");
			if (FModuleManager::Get().IsModuleLoaded(AutomationController))
			{
    
    
				FModuleManager::GetModuleChecked<IAutomationControllerModule>(AutomationController).Tick();
			}
		}
#endif

#if WITH_ENGINE && WITH_AUTOMATION_WORKER
		// tick automation worker
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_Tick_AutomationWorker);
			static const FName AutomationWorkerModuleName = TEXT("AutomationWorker");
			if (FModuleManager::Get().IsModuleLoaded(AutomationWorkerModuleName))
			{
    
    
				FModuleManager::GetModuleChecked<IAutomationWorkerModule>(AutomationWorkerModuleName).Tick();
			}
		}
#endif

		// tick render hardware interface
		{
    
    			
			SCOPE_CYCLE_COUNTER(STAT_RHITickTime);
			RHITick( FApp::GetDeltaTime() ); // Update RHI.
		}

		// Increment global frame counter. Once for each engine tick.
		GFrameCounter++;

		// Disregard first few ticks for total tick time as it includes loading and such.
		if (GFrameCounter > 6)
		{
    
    
			TotalTickTime += FApp::GetDeltaTime();
		}

		// Find the objects which need to be cleaned up the next frame.
		FPendingCleanupObjects* PreviousPendingCleanupObjects = PendingCleanupObjects;
		PendingCleanupObjects = GetPendingCleanupObjects();

		{
    
    
			SCOPE_CYCLE_COUNTER(STAT_FrameSyncTime);
			// this could be perhaps moved down to get greater parallelism
			// Sync game and render thread. Either total sync or allowing one frame lag.
			static FFrameEndSync FrameEndSync;
			static auto CVarAllowOneFrameThreadLag = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.OneFrameThreadLag"));
			FrameEndSync.Sync( CVarAllowOneFrameThreadLag->GetValueOnGameThread() != 0 );
		}

		// tick core ticker, threads & deferred commands
		{
    
    
			SCOPE_CYCLE_COUNTER(STAT_DeferredTickTime);
			CSV_SCOPED_TIMING_STAT_EXCLUSIVE(DeferredTickTime);
			// Delete the objects which were enqueued for deferred cleanup before the previous frame.
			delete PreviousPendingCleanupObjects;

#if WITH_COREUOBJECT
			DeleteLoaders(); // destroy all linkers pending delete
#endif

			FTicker::GetCoreTicker().Tick(FApp::GetDeltaTime());
			FThreadManager::Get().Tick();
			GEngine->TickDeferredCommands();		
		}

#if !UE_SERVER
		// tick media framework
		if (MediaModule != nullptr)
		{
    
    
			QUICK_SCOPE_CYCLE_COUNTER(STAT_FEngineLoop_MediaTickPostRender);
			MediaModule->TickPostRender();
		}
#endif

		FCoreDelegates::OnEndFrame.Broadcast();

		#if !UE_SERVER && WITH_ENGINE
		{
    
    
			// We emit dynamic resolution's end frame right before RHI's. GEngine is going to ignore it if no BeginFrame was done.
			GEngine->EmitDynamicResolutionEvent(EDynamicResolutionStateEvent::EndFrame);
		}
		#endif

		// end of RHI frame
		ENQUEUE_RENDER_COMMAND(EndFrame)(
			[CurrentFrameCounter](FRHICommandListImmediate& RHICmdList)
			{
    
    
				EndFrameRenderThread(RHICmdList, CurrentFrameCounter);
			});

		GEngine->SetGameLatencyMarkerEnd(CurrentFrameCounter);

		// Set CPU utilization stats.
		const FCPUTime CPUTime = FPlatformTime::GetCPUTime();
		SET_FLOAT_STAT( STAT_CPUTimePct, CPUTime.CPUTimePct );
		SET_FLOAT_STAT( STAT_CPUTimePctRelative, CPUTime.CPUTimePctRelative );

		// Set the UObject count stat
#if UE_GC_TRACK_OBJ_AVAILABLE
		SET_DWORD_STAT(STAT_Hash_NumObjects, GUObjectArray.GetObjectArrayNumMinusAvailable());
#endif
		TRACE_END_FRAME(TraceFrameType_Game);
	}

#if BUILD_EMBEDDED_APP
	static double LastSleepTime = FPlatformTime::Seconds();
	double TimeNow = FPlatformTime::Seconds();
	if (LastSleepTime > 0 && TimeNow - LastSleepTime >= CVarSecondsBeforeEmbeddedAppSleeps.GetValueOnAnyThread())
	{
    
    
		LastSleepTime = 0;
		FEmbeddedCommunication::AllowSleep(TEXT("FirstTicks"));
	}
#endif
}

在这个Tick函数中我们可以找到我们常见的帧记录:
在这里插入图片描述
这里,看到了来自UE的线程管理
在这里插入图片描述

这里也可以看到在UE非服务器上,都会去执行属于自己的media核心框架
在这里插入图片描述
在帧末尾,绑定了最后一帧应当做的事,与发射动态解决方法的事件
在这里插入图片描述

文章描述得很简单,到最后,只是告诉大家一个查询源码的思路,UE代码块很多,根据自己的感兴趣的方向看就好,去查找就好

猜你喜欢

转载自blog.csdn.net/weixin_56946623/article/details/124729202