// Copyright Epic Games, Inc. All Rights Reserved. /*============================================================================= MobileDistortionPass.cpp - Mobile specific rendering of primtives with refraction =============================================================================*/ #include "MobileDistortionPass.h" #include "DataDrivenShaderPlatformInfo.h" #include "TranslucentRendering.h" #include "DynamicPrimitiveDrawing.h" #include "PostProcess/PostProcessing.h" #include "PostProcess/SceneFilterRendering.h" #include "PipelineStateCache.h" #include "ScenePrivate.h" #include "DistortionRendering.h" BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FMobileDistortionPassUniformParameters, RENDERER_API) SHADER_PARAMETER_STRUCT(FMobileSceneTextureUniformParameters, SceneTextures) SHADER_PARAMETER(FVector4f, DistortionParams) END_GLOBAL_SHADER_PARAMETER_STRUCT() IMPLEMENT_STATIC_UNIFORM_BUFFER_STRUCT(FMobileDistortionPassUniformParameters, "MobileDistortionPass", SceneTextures); bool IsMobileDistortionActive(const FViewInfo& View) { static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.DisableDistortion")); int32 DisableDistortion = CVar->GetInt(); return View.Family->EngineShowFlags.Translucency && View.bHasDistortionPrimitives && FSceneRenderer::GetRefractionQuality(*View.Family) > 0 && DisableDistortion == 0; } BEGIN_SHADER_PARAMETER_STRUCT(FMobileDistortionPassParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FViewShaderParameters, View) SHADER_PARAMETER_RDG_UNIFORM_BUFFER(FMobileDistortionPassUniformParameters, Pass) SHADER_PARAMETER_STRUCT_INCLUDE(FInstanceCullingDrawParams, InstanceCullingDrawParams) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() TRDGUniformBufferRef CreateMobileDistortionPassUniformBuffer(FRDGBuilder& GraphBuilder, const FViewInfo& View) { auto* Parameters = GraphBuilder.AllocParameters(); EMobileSceneTextureSetupMode SetupMode = EMobileSceneTextureSetupMode::None; if (View.bCustomDepthStencilValid) { SetupMode |= EMobileSceneTextureSetupMode::CustomDepth; } if (MobileRequiresSceneDepthAux(View.GetShaderPlatform())) { SetupMode |= EMobileSceneTextureSetupMode::SceneDepthAux; } else { SetupMode |= EMobileSceneTextureSetupMode::SceneDepth; } SetupMobileSceneTextureUniformParameters(GraphBuilder, View.GetSceneTexturesChecked(), SetupMode, Parameters->SceneTextures); SetupDistortionParams(Parameters->DistortionParams, View); return GraphBuilder.CreateUniformBuffer(Parameters); } FMobileDistortionAccumulateOutputs AddMobileDistortionAccumulatePass(FRDGBuilder& GraphBuilder, FScene* Scene, const FViewInfo& View, const FMobileDistortionAccumulateInputs& Inputs) { const EPixelFormat Format = PF_B8G8R8A8; ETextureCreateFlags TextureCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable; if (UE::PixelFormat::HasCapabilities(Format, EPixelFormatCapabilities::LossyCompressible)) { TextureCreateFlags |= TexCreate_LossyCompressionLowBitrate; } FRDGTextureDesc DistortionAccumulateDesc = FRDGTextureDesc::Create2D(Inputs.SceneColor.Texture->Desc.Extent, Format, FClearValueBinding::Transparent, TextureCreateFlags); FScreenPassRenderTarget DistortionAccumulateOutput = FScreenPassRenderTarget(GraphBuilder.CreateTexture(DistortionAccumulateDesc, TEXT("DistortionAccumulatePass")), Inputs.SceneColor.ViewRect, ERenderTargetLoadAction::EClear); FMobileDistortionPassParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->View = View.GetShaderParameters(); PassParameters->Pass = CreateMobileDistortionPassUniformBuffer(GraphBuilder, View); PassParameters->RenderTargets[0] = DistortionAccumulateOutput.GetRenderTargetBinding(); const FScreenPassTextureViewport SceneColorViewport(Inputs.SceneColor); auto* Pass = const_cast(View).ParallelMeshDrawCommandPasses[EMeshPass::Distortion]; if (Pass) { Pass->BuildRenderingCommands(GraphBuilder, Scene->GPUScene, PassParameters->InstanceCullingDrawParams); } // Pass always added due to clear action. GraphBuilder.AddPass( RDG_EVENT_NAME("DistortionAccumulate %dx%d", SceneColorViewport.Rect.Width(), SceneColorViewport.Rect.Height()), PassParameters, ERDGPassFlags::Raster, [&View, Pass, SceneColorViewport, PassParameters](FRHICommandList& RHICmdList) { if (Pass) { RHICmdList.SetViewport(SceneColorViewport.Rect.Min.X, SceneColorViewport.Rect.Min.Y, 0.0f, SceneColorViewport.Rect.Max.X, SceneColorViewport.Rect.Max.Y, 1.0f); Pass->Draw(RHICmdList, &PassParameters->InstanceCullingDrawParams); } }); FMobileDistortionAccumulateOutputs Outputs; Outputs.DistortionAccumulate = DistortionAccumulateOutput; return MoveTemp(Outputs); } class FMobileDistortionMergePS : public FGlobalShader { public: DECLARE_GLOBAL_SHADER(FMobileDistortionMergePS); SHADER_USE_PARAMETER_STRUCT(FMobileDistortionMergePS, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneColorTexture) SHADER_PARAMETER_SAMPLER(SamplerState, SceneColorTextureSampler) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, DistortionAccumulateTexture) SHADER_PARAMETER_SAMPLER(SamplerState, DistortionAccumulateSampler) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsMobilePlatform(Parameters.Platform); } }; IMPLEMENT_GLOBAL_SHADER(FMobileDistortionMergePS, "/Engine/Private/DistortApplyScreenPS.usf", "Merge_Mobile", SF_Pixel); FScreenPassTexture AddMobileDistortionMergePass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FMobileDistortionMergeInputs& Inputs) { FRDGTextureDesc DistortionMergeDesc = FRDGTextureDesc::Create2D(Inputs.DistortionAccumulate.Texture->Desc.Extent, Inputs.SceneColor.Texture->Desc.Format, FClearValueBinding::Black, TexCreate_ShaderResource | TexCreate_RenderTargetable); FScreenPassRenderTarget DistortionMergeOutput = FScreenPassRenderTarget(GraphBuilder.CreateTexture(DistortionMergeDesc, TEXT("DistortionMergePass")), Inputs.DistortionAccumulate.ViewRect, ERenderTargetLoadAction::EClear); TShaderMapRef PixelShader(View.ShaderMap); FMobileDistortionMergePS::FParameters* PassParameters = GraphBuilder.AllocParameters(); PassParameters->RenderTargets[0] = DistortionMergeOutput.GetRenderTargetBinding(); PassParameters->View = View.ViewUniformBuffer; PassParameters->SceneColorTexture = Inputs.SceneColor.Texture; PassParameters->SceneColorTextureSampler = TStaticSamplerState::GetRHI(); PassParameters->DistortionAccumulateTexture = Inputs.DistortionAccumulate.Texture; PassParameters->DistortionAccumulateSampler = TStaticSamplerState::GetRHI(); const FScreenPassTextureViewport InputViewport(Inputs.SceneColor); const FScreenPassTextureViewport OutputViewport(DistortionMergeOutput); AddDrawScreenPass(GraphBuilder, RDG_EVENT_NAME("DistortionMerge"), View, OutputViewport, InputViewport, PixelShader, PassParameters); return MoveTemp(DistortionMergeOutput); }