FRenderCommandFence Fence;
// wait for render thread to finish
Fence.BeginFence();
Fence.Wait();
bool bEmptyGameThreadTasks = !FTaskGraphInterface::Get().IsThreadProcessingTasks(ENamedThreads::GameThread);
if (bEmptyGameThreadTasks)
在FRenderCommandFence的BeginFence函数中
当GameThread与RHI线程及GPU同步时,GameThread会使用宏ENQUEUE_RENDER_COMMAND向RenderThread的TaskGraph队列中投递一个FSyncFrameCommand任务,以便将Command List同步投递到RHI线程
当GameThread与RenderThread同步时,GameThread会创建一个FNullGraphTask空任务,放到RenderThread的TaskGraph队列中让其执行
在FRenderCommandFence的Wait函数中,会检查投递给RenderThread的CompletionEvent是否被执行,如果没有执行则调用GameThreadWaitForTask函数来阻塞等待(通过Event实现)
void FRenderCommandFence::BeginFence(bool bSyncToRHIAndGPU)
{
if (!GIsThreadedRendering)
{
return;
}
else
{
// Render thread is a default trigger for the CompletionEvent
TriggerThreadIndex = ENamedThreads::ActualRenderingThread;
if (BundledCompletionEvent.GetReference() && IsInGameThread())
{
CompletionEvent = BundledCompletionEvent;
return;
}
int32 GTSyncType = CVarGTSyncType.GetValueOnAnyThread();
if (bSyncToRHIAndGPU)
{
// Don't sync to the RHI and GPU if GtSyncType is disabled, or we're not vsyncing
//@TODO: do this logic in the caller?
static auto CVarVsync = IConsoleManager::Get().FindConsoleVariable(TEXT("r.VSync")); // 是否开了VSync
check(CVarVsync != nullptr);
if ( GTSyncType == 0 || CVarVsync->GetInt() == 0 ) // r.GTSyncType为0或r.VSync为0时,GameThread不与RHI线程及GPU同步
{
bSyncToRHIAndGPU = false;
}
}
if (bSyncToRHIAndGPU) // GameThread与RHI线程及GPU同步时
{
if (IsRHIThreadRunning())
{
// Change trigger thread to RHI
TriggerThreadIndex = ENamedThreads::RHIThread;
}
// Create a task graph event which we can pass to the render or RHI threads.
CompletionEvent = FGraphEvent::CreateGraphEvent();
FGraphEventRef InCompletionEvent = CompletionEvent;
/* ---------------------------------------------- ENQUEUE_RENDER_COMMAND宏展开后 ------------------------------------------------
struct FSyncFrameCommandName
{
static const char* CStr() { return "FSyncFrameCommand"; }
static const TCHAR* TStr() { return L"FSyncFrameCommand"; }
};
EnqueueUniqueRenderCommand<FSyncFrameCommandName>( */
ENQUEUE_RENDER_COMMAND(FSyncFrameCommand)(
[InCompletionEvent, GTSyncType](FRHICommandListImmediate& RHICmdList)
{
if (IsRHIThreadRunning()) // 如果开启了RHI线程
{
ALLOC_COMMAND_CL(RHICmdList, FRHISyncFrameCommand)(InCompletionEvent, GTSyncType); // 将创建的CompletionEvent投递到RHI线程的TaskGraph的任务队列中
RHICmdList.ImmediateFlush(EImmediateFlushType::DispatchToRHIThread);
}
else // 渲染线程直接执行
{
FRHISyncFrameCommand Command(InCompletionEvent, GTSyncType);
Command.Execute(RHICmdList);
}
});
}
else // GameThead与RenderThread同步
{
// Sync Game Thread with Render Thread only
DECLARE_CYCLE_STAT(TEXT("FNullGraphTask.FenceRenderCommand"),
STAT_FNullGraphTask_FenceRenderCommand,
STATGROUP_TaskGraphTasks);
CompletionEvent = TGraphTask<FNullGraphTask>::CreateTask(NULL, ENamedThreads::GameThread).ConstructAndDispatchWhenReady(
GET_STATID(STAT_FNullGraphTask_FenceRenderCommand), ENamedThreads::GetRenderThread());
}
}
}
/**
* Waits for pending fence commands to retire.
*/
void FRenderCommandFence::Wait(bool bProcessGameThreadTasks) const
{
if (!IsFenceComplete())
{
StopRenderCommandFenceBundler();
GameThreadWaitForTask(CompletionEvent, TriggerThreadIndex, bProcessGameThreadTasks);
}
}
bool FRenderCommandFence::IsFenceComplete() const
{
if (!GIsThreadedRendering)
{
return true;
}
check(IsInGameThread() || IsInAsyncLoadingThread());
CheckRenderingThreadHealth();
if (!CompletionEvent.GetReference() || CompletionEvent->IsComplete())
{
CompletionEvent = NULL; // this frees the handle for other uses, the NULL state is considered completed
return true;
}
return false;
}