无名 发表于 2022-5-8 17:21:49

【冷漠搬砖】UE4随笔——渲染线程使用


通常情况下UE4的渲染操作是在渲染线程下执行的,这样无疑可以提高系统的效率以及电脑CPU的利用率,当然在某些情况下也可能在game线程下进行渲染操作,但一般都是渲染线程会比game线程晚一帧执行。下面将对渲染线程的调用流程进行一个简单的介绍。

http://cdn.u1.huluxia.com/g4/M02/F9/58/rBAAdl8w6K2AVSfbAAAP5DPxc6c587.jpg
1 线程创建

将代码定位到

int32 FEngineLoop::PreInit(const TCHAR* CmdLine

其中有一行代码为

// initialize task graph sub-system with potential multiple threads
   FTaskGraphInterface::Startup(FPlatformMisc::

这行代码就是在引擎加载阶段对线程进行创建,具体过程请继续往下看,

http://cdn.u1.huluxia.com/g4/M02/F9/58/rBAAdl8w6K6AFRkbAAEDIRmwJhk472.jpg
在上述代码中FTaskGraphInterface是一个单件,而FTaskGraphImplementation是FTaskGraphInterface的一个实现类,也就是创建这个单件,下面进入FTaskGraphImplementation来看下这个单件实现类。

http://cdn.u1.huluxia.com/g4/M02/F9/58/rBAAdl8w6K-AanSjAAVHdkkXl9M200.jpg

纵观以上代码,说白了就是计算需要创建线程个数,并且创建的过程,线程分为FTaskThreadAnyThread和FNamedTaskThread两种,创建的代码如下:

http://cdn.u1.huluxia.com/g4/M02/F9/58/rBAAdl8w6LCAKPtGAAD9KFn69X4367.jpg

创建好的任务线程保存在WorkerThreads[]中,而且这些任务线程均继承于FRunnable接口,该接口是UE4自定义的线程,不过是一个假的线程,线程真正的创建在以下代码中执行。

WorkerThreads.RunnableThread = FRunnableThread::

以上线程的创建并未包括渲染线程,渲染线程的创建如下:

void StartRenderingThread()
{
    static uint32 ThreadCount = 0;
    check(!GIsThreadedRendering && GUseThreadedRendering);

    check(!GRHIThread_InternalUseOnly && !GIsRunningRHIInSeparateThread_InternalUseOnly && !GIsRunningRHIInDedicatedThread_InternalUseOnly && !GIsRunningRHIInTaskThread_InternalUseOnly);

    if (GUseRHIThread_InternalUseOnly)
    {
      FRHICommandListExecutor::GetImmediateCommandList().ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);      
      if (!FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::RHIThread))
      {
            FRHIThread::Get().Start();
      }
      DECLARE_CYCLE_STAT(TEXT("Wait For RHIThread"), STAT_WaitForRHIThread, STATGROUP_TaskGraphTasks);

      FGraphEventRef CompletionEvent = TGraphTask<FOwnershipOfRHIThreadTask>::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(true, GET_STATID(STAT_WaitForRHIThread));
      QUICK_SCOPE_CYCLE_COUNTER(STAT_StartRenderingThread);
   

该过程也是在以下代码中调用。

int32 FEngineLoop::PreInit(const TCHAR* CmdLine)

2 线程调用

渲染线程创建完成之后便可以对其进行使用了,下面以FPrimitiveSceneProxy::SetSelection_GameThread为例进行讲解,完整代码如下所示。

页: [1]
查看完整版本: 【冷漠搬砖】UE4随笔——渲染线程使用