Keywords: UE4, Deferred Shading Renderer, Multipass

Shading Model

Documents

Real Shading in Unreal Engine 4 (BRDF)

Multipass

Documents

Content-Driven Multipass Rendering in UE4 | GDC 2017 | Unreal Engine
https://www.youtube.com/watch?v=QGIKrD7uHu8

Render Thread

Callstack in engine source

Entrance of tick function on Deffered Shading Rendering: void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList).
Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

UE4Editor-Renderer.dll!FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate & RHICmdList) Line 1263    C++
 UE4Editor-Renderer.dll!RenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneRenderer * SceneRenderer) Line 3581    C++
 [Inline Frame] UE4Editor-Renderer.dll!FRendererModule::BeginRenderingViewFamily::__l35::<lambda_759d0c4589f205101b108f5da3fb1556>::operator()(FRHICommandListImmediate &) Line 3820    C++
 UE4Editor-Renderer.dll!TEnqueueUniqueRenderCommandType<`FRendererModule::BeginRenderingViewFamily'::`35'::FDrawSceneCommandName,<lambda_759d0c4589f205101b108f5da3fb1556>>::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 195    C++
 UE4Editor-Renderer.dll!TGraphTask<TEnqueueUniqueRenderCommandType<`FRendererModule::BeginRenderingViewFamily'::`35'::FDrawSceneCommandName,<lambda_759d0c4589f205101b108f5da3fb1556>>>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & NewTasks, ENamedThreads::Type CurrentThread) Line 849    C++
 [Inline Frame] UE4Editor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & CurrentThread, ENamedThreads::Type) Line 516    C++
 UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall) Line 692    C++
 UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 587    C++
 UE4Editor-RenderCore.dll!RenderingThreadMain(FEvent * TaskGraphBoundSyncEvent) Line 341    C++
 UE4Editor-RenderCore.dll!FRenderingThread::Run() Line 492    C++
 UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 86    C++
 UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 27    C++

Downsampling

Callstack in engine source
 UE4Editor-Renderer.dll!AddDownsamplePass(FRDGBuilder & GraphBuilder, const FViewInfo & View, const FDownsamplePassInputs & Inputs) Line 173    C++
 UE4Editor-Renderer.dll!AddPostProcessingPasses(FRDGBuilder & GraphBuilder, const FViewInfo & View, const FPostProcessingInputs & Inputs) Line 503    C++
UE4Editor-Renderer.dll!FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate & RHICmdList) Line 2794    C++
 UE4Editor-Renderer.dll!RenderViewFamily_RenderThread(FRHICommandListImmediate & RHICmdList, FSceneRenderer * SceneRenderer) Line 3581    C++
 [Inline Frame] UE4Editor-Renderer.dll!FRendererModule::BeginRenderingViewFamily::__l35::<lambda_759d0c4589f205101b108f5da3fb1556>::operator()(FRHICommandListImmediate &) Line 3820    C++
 UE4Editor-Renderer.dll!TEnqueueUniqueRenderCommandType<`FRendererModule::BeginRenderingViewFamily'::`35'::FDrawSceneCommandName,<lambda_759d0c4589f205101b108f5da3fb1556>>::DoTask(ENamedThreads::Type CurrentThread, const TRefCountPtr<FGraphEvent> & MyCompletionGraphEvent) Line 195    C++
 UE4Editor-Renderer.dll!TGraphTask<TEnqueueUniqueRenderCommandType<`FRendererModule::BeginRenderingViewFamily'::`35'::FDrawSceneCommandName,<lambda_759d0c4589f205101b108f5da3fb1556>>>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & NewTasks, ENamedThreads::Type CurrentThread) Line 849    C++
 [Inline Frame] UE4Editor-Core.dll!FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32>> & CurrentThread, ENamedThreads::Type) Line 516    C++
 UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksNamedThread(int QueueIndex, bool bAllowStall) Line 692    C++
 UE4Editor-Core.dll!FNamedTaskThread::ProcessTasksUntilQuit(int QueueIndex) Line 587    C++
 UE4Editor-RenderCore.dll!RenderingThreadMain(FEvent * TaskGraphBoundSyncEvent) Line 341    C++
 UE4Editor-RenderCore.dll!FRenderingThread::Run() Line 492    C++
 UE4Editor-Core.dll!FRunnableThreadWin::Run() Line 86    C++
 UE4Editor-Core.dll!FRunnableThreadWin::GuardedRun() Line 27    C++
 [External Code]    
Critical Code

Quoted from void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
\Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp

FRDGBuilder GraphBuilder(RHICmdList);

FSceneTextureParameters SceneTextures;
SetupSceneTextureParameters(GraphBuilder, &SceneTextures);

// Fallback to a black texture if no velocity.
if (!SceneTextures.SceneVelocityBuffer)
{
    SceneTextures.SceneVelocityBuffer = GSystemTextures.GetBlackDummy(GraphBuilder);
}

FPostProcessingInputs PostProcessingInputs;
PostProcessingInputs.SceneTextures = &SceneTextures;
PostProcessingInputs.ViewFamilyTexture = CreateViewFamilyTexture(GraphBuilder, ViewFamily);
PostProcessingInputs.SceneColor = GraphBuilder.RegisterExternalTexture(SceneContext.GetSceneColor(), TEXT("SceneColor"));
PostProcessingInputs.CustomDepth = GraphBuilder.TryRegisterExternalTexture(SceneContext.CustomDepth, TEXT("CustomDepth"));
PostProcessingInputs.SeparateTranslucency = RegisterExternalTextureWithFallback(GraphBuilder, SceneContext.SeparateTranslucencyRT, SceneContext.GetSeparateTranslucencyDummy(), TEXT("SeparateTranslucency"));
PostProcessingInputs.SeparateModulation = RegisterExternalTextureWithFallback(GraphBuilder, SceneContext.SeparateTranslucencyModulateRT, SceneContext.GetSeparateTranslucencyModulateDummy(), TEXT("SeparateModulate"));

if (ViewFamily.UseDebugViewPS())
{
    for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
    {
        FViewInfo& View = Views[ViewIndex];

        SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
        RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
        AddDebugPostProcessingPasses(GraphBuilder, View, PostProcessingInputs);
    }
}
else
{
    for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
    {
        FViewInfo& View = Views[ViewIndex];

        SCOPED_GPU_MASK(RHICmdList, View.GPUMask);
        RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex);
        AddPostProcessingPasses(GraphBuilder, View, PostProcessingInputs);
    }
}

Quoted from void AddPostProcessingPasses(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FPostProcessingInputs& Inputs)
\Engine\Source\Runtime\Renderer\Private\PostProcess\PostProcessing.cpp

// If TAA didn't do it, downsample the scene color texture by half.
if (!HalfResolutionSceneColor.Texture)
{
    FDownsamplePassInputs PassInputs;
    PassInputs.Name = TEXT("HalfResolutionSceneColor");
    PassInputs.SceneColor = SceneColor;
    PassInputs.Quality = DownsampleQuality;
    PassInputs.FormatOverride = DownsampleOverrideFormat;

    HalfResolutionSceneColor = AddDownsamplePass(GraphBuilder, View, PassInputs);
}

Quoted from FScreenPassTexture AddDownsamplePass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FDownsamplePassInputs& Inputs)
\Engine\Source\Runtime\Renderer\Private\PostProcess\PostProcessDownsample.cpp

FScreenPassTexture AddDownsamplePass(
FRDGBuilder& GraphBuilder,
const FViewInfo& View,
const FDownsamplePassInputs& Inputs)
{
    check(Inputs.SceneColor.IsValid());

    bool bIsComputePass = View.bUseComputePasses;

    if ((Inputs.Flags & EDownsampleFlags::ForceRaster) == EDownsampleFlags::ForceRaster)
    {
        bIsComputePass = false;
    }

    FScreenPassRenderTarget Output;

    // Construct the output texture to be half resolution (rounded up to even) with an optional format override.
    {
        FRDGTextureDesc Desc = Inputs.SceneColor.Texture->Desc;
        Desc.Reset();
        Desc.Extent = FIntPoint::DivideAndRoundUp(Desc.Extent, 2);
        Desc.Extent.X = FMath::Max(1, Desc.Extent.X);
        Desc.Extent.Y = FMath::Max(1, Desc.Extent.Y);
        Desc.TargetableFlags &= ~(TexCreate_RenderTargetable | TexCreate_UAV);
        Desc.TargetableFlags |= bIsComputePass ? TexCreate_UAV : TexCreate_RenderTargetable;
        Desc.Flags |= GFastVRamConfig.Downsample;
        Desc.DebugName = Inputs.Name;
        Desc.ClearValue = FClearValueBinding(FLinearColor(0, 0, 0, 0));

        if (Inputs.FormatOverride != PF_Unknown)
        {
            Desc.Format = Inputs.FormatOverride;
        }

        Output.Texture = GraphBuilder.CreateTexture(Desc, Inputs.Name);
        Output.ViewRect = FIntRect::DivideAndRoundUp(Inputs.SceneColor.ViewRect, 2);
        Output.LoadAction = ERenderTargetLoadAction::ENoAction;
    }

    FDownsamplePermutationDomain PermutationVector;
    PermutationVector.Set<FDownsampleQualityDimension>(Inputs.Quality);

    const FScreenPassTextureViewport SceneColorViewport(Inputs.SceneColor);
    const FScreenPassTextureViewport OutputViewport(Output);

    if (bIsComputePass)
    {
        FDownsampleCS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDownsampleCS::FParameters>();
        PassParameters->Common = GetDownsampleParameters(View, Output, Inputs.SceneColor, Inputs.Quality);
        PassParameters->OutComputeTexture = GraphBuilder.CreateUAV(Output.Texture);

        TShaderMapRef<FDownsampleCS> ComputeShader(View.ShaderMap, PermutationVector);

        FComputeShaderUtils::AddPass(
            GraphBuilder,
            RDG_EVENT_NAME("Downsample.%s %dx%d (CS)", Inputs.Name, Inputs.SceneColor.ViewRect.Width(), Inputs.SceneColor.ViewRect.Height()),
            ComputeShader,
            PassParameters,
            FComputeShaderUtils::GetGroupCount(OutputViewport.Rect.Size(), FIntPoint(GDownsampleTileSizeX, GDownsampleTileSizeY)));
    }
    else
    {
        FDownsamplePS::FParameters* PassParameters = GraphBuilder.AllocParameters<FDownsamplePS::FParameters>();
        PassParameters->Common = GetDownsampleParameters(View, Output, Inputs.SceneColor, Inputs.Quality);
        PassParameters->RenderTargets[0] = Output.GetRenderTargetBinding();

        TShaderMapRef<FDownsamplePS> PixelShader(View.ShaderMap, PermutationVector);

        FPixelShaderUtils::AddFullscreenPass(
            GraphBuilder,
            View.ShaderMap,
            RDG_EVENT_NAME("Downsample.%s %dx%d (PS)", Inputs.Name, Inputs.SceneColor.ViewRect.Width(), Inputs.SceneColor.ViewRect.Height()),
            PixelShader,
            PassParameters,
            OutputViewport.Rect);
    }

    return MoveTemp(Output);
}

There is nothing quite so useless, as doing with great efficiency, something that should not be done at all. ― Peter Drucker