// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. /*============================================================================= PostProcessHMD.cpp: Post processing for HMD devices. =============================================================================*/ #include "RendererPrivate.h" #include "ScenePrivate.h" #include "ScreenRendering.h" #include "SceneFilterRendering.h" #include "PostProcessHMD.h" #include "PostProcessing.h" #include "PostProcessHistogram.h" #include "PostProcessEyeAdaptation.h" #include "IHeadMountedDisplay.h" #include "RHICommandList.h" #include "SceneUtils.h" /** The filter vertex declaration resource type. */ class FDistortionVertexDeclaration : public FRenderResource { public: FVertexDeclarationRHIRef VertexDeclarationRHI; /** Destructor. */ virtual ~FDistortionVertexDeclaration() {} virtual void InitRHI() override { uint16 Stride = sizeof(FDistortionVertex); FVertexDeclarationElementList Elements; Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, Position),VET_Float2,0, Stride)); Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, TexR), VET_Float2, 1, Stride)); Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, TexG), VET_Float2, 2, Stride)); Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, TexB), VET_Float2, 3, Stride)); Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, VignetteFactor), VET_Float1, 4, Stride)); Elements.Add(FVertexElement(0, STRUCT_OFFSET(FDistortionVertex, TimewarpFactor), VET_Float1, 5, Stride)); VertexDeclarationRHI = RHICreateVertexDeclaration(Elements); } virtual void ReleaseRHI() override { VertexDeclarationRHI.SafeRelease(); } }; /** The Distortion vertex declaration. */ TGlobalResource GDistortionVertexDeclaration; /** Encapsulates the post processing vertex shader. */ template class FPostProcessHMDVS : public FGlobalShader { DECLARE_SHADER_TYPE(FPostProcessHMDVS, Global); // Distortion parameter values FShaderParameter EyeToSrcUVScale; FShaderParameter EyeToSrcUVOffset; // Timewarp-related params FShaderParameter EyeRotationStart; FShaderParameter EyeRotationEnd; static bool ShouldCache(EShaderPlatform Platform) { return true; } static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("USE_TIMEWARP"), uint32(bTimeWarp ? 1 : 0)); } /** Default constructor. */ FPostProcessHMDVS() {} public: /** Initialization constructor. */ FPostProcessHMDVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { EyeToSrcUVScale.Bind(Initializer.ParameterMap, TEXT("EyeToSrcUVScale")); EyeToSrcUVOffset.Bind(Initializer.ParameterMap, TEXT("EyeToSrcUVOffset")); if (bTimeWarp) { EyeRotationStart.Bind(Initializer.ParameterMap, TEXT("EyeRotationStart")); EyeRotationEnd.Bind(Initializer.ParameterMap, TEXT("EyeRotationEnd")); } } void SetVS(const FRenderingCompositePassContext& Context, EStereoscopicPass StereoPass) { const FVertexShaderRHIParamRef ShaderRHI = GetVertexShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); check(GEngine->HMDDevice.IsValid()); FVector2D EyeToSrcUVScaleValue; FVector2D EyeToSrcUVOffsetValue; GEngine->HMDDevice->GetEyeRenderParams_RenderThread(StereoPass, EyeToSrcUVScaleValue, EyeToSrcUVOffsetValue); SetShaderValue(Context.RHICmdList, ShaderRHI, EyeToSrcUVScale, EyeToSrcUVScaleValue); SetShaderValue(Context.RHICmdList, ShaderRHI, EyeToSrcUVOffset, EyeToSrcUVOffsetValue); if (bTimeWarp) { FMatrix startM, endM; GEngine->HMDDevice->GetTimewarpMatrices_RenderThread(StereoPass, startM, endM); SetShaderValue(Context.RHICmdList, ShaderRHI, EyeRotationStart, startM); SetShaderValue(Context.RHICmdList, ShaderRHI, EyeRotationEnd, endM); } } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << EyeToSrcUVScale << EyeToSrcUVOffset; if (bTimeWarp) { Ar << EyeRotationStart << EyeRotationEnd; } return bShaderHasOutdatedParameters; } }; IMPLEMENT_SHADER_TYPE(template<>, FPostProcessHMDVS, TEXT("PostProcessHMD"), TEXT("MainVS"), SF_Vertex); /** Encapsulates the post processing HMD distortion and correction pixel shader. */ template class FPostProcessHMDPS : public FGlobalShader { DECLARE_SHADER_TYPE(FPostProcessHMDPS, Global); static bool ShouldCache(EShaderPlatform Platform) { return true; } /** Default constructor. */ FPostProcessHMDPS() {} public: FPostProcessPassParameters PostprocessParameter; FDeferredPixelShaderParameters DeferredParameters; /** Initialization constructor. */ FPostProcessHMDPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { PostprocessParameter.Bind(Initializer.ParameterMap); DeferredParameters.Bind(Initializer.ParameterMap); } void SetPS(const FRenderingCompositePassContext& Context, FIntRect SrcRect, FIntPoint SrcBufferSize, EStereoscopicPass StereoPass, FMatrix& QuadTexTransform) { const FPixelShaderRHIParamRef ShaderRHI = GetPixelShader(); FGlobalShader::SetParameters(Context.RHICmdList, ShaderRHI, Context.View); PostprocessParameter.SetPS(ShaderRHI, Context, TStaticSamplerState::GetRHI()); DeferredParameters.Set(Context.RHICmdList, ShaderRHI, Context.View); } // FShader interface. virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << PostprocessParameter << DeferredParameters; return bShaderHasOutdatedParameters; } static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment) { FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment); OutEnvironment.SetDefine(TEXT("USE_TIMEWARP"), uint32(bTimeWarp ? 1 : 0)); } }; IMPLEMENT_SHADER_TYPE(template<>, FPostProcessHMDPS, TEXT("PostProcessHMD"), TEXT("MainPS"), SF_Pixel); void FRCPassPostProcessHMD::Process(FRenderingCompositePassContext& Context) { SCOPED_DRAW_EVENT(Context.RHICmdList, PostProcessHMD); const FPooledRenderTargetDesc* InputDesc = GetInputDesc(ePId_Input0); if(!InputDesc) { // input is not hooked up correctly return; } const FSceneView& View = Context.View; const FSceneViewFamily& ViewFamily = *(View.Family); const FIntRect SrcRect = View.ViewRect; const FIntRect DestRect = View.UnscaledViewRect; const FIntPoint SrcSize = InputDesc->Extent; const FSceneRenderTargetItem& DestRenderTarget = PassOutputs[0].RequestSurface(Context); // Set the view family's render target/viewport. SetRenderTarget(Context.RHICmdList, DestRenderTarget.TargetableTexture, FTextureRHIRef()); Context.SetViewportAndCallRHI(DestRect); Context.RHICmdList.Clear(true, FLinearColor::Black, false, 1.0f, false, 0, FIntRect()); // set the state Context.RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); Context.RHICmdList.SetRasterizerState(TStaticRasterizerState<>::GetRHI()); Context.RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); FMatrix QuadTexTransform = FMatrix::Identity; FMatrix QuadPosTransform = FMatrix::Identity; check(GEngine->HMDDevice.IsValid()); { TShaderMapRef > VertexShader(Context.GetShaderMap()); TShaderMapRef > PixelShader(Context.GetShaderMap()); static FGlobalBoundShaderState BoundShaderState; SetGlobalBoundShaderState(Context.RHICmdList, Context.GetFeatureLevel(), BoundShaderState, GDistortionVertexDeclaration.VertexDeclarationRHI, *VertexShader, *PixelShader); VertexShader->SetVS(Context, View.StereoPass); PixelShader->SetPS(Context, SrcRect, SrcSize, View.StereoPass, QuadTexTransform); } GEngine->HMDDevice->DrawDistortionMesh_RenderThread(Context, View, SrcSize); Context.RHICmdList.CopyToResolveTarget(DestRenderTarget.TargetableTexture, DestRenderTarget.ShaderResourceTexture, false, FResolveParams()); } FPooledRenderTargetDesc FRCPassPostProcessHMD::ComputeOutputDesc(EPassOutputId InPassOutputId) const { FPooledRenderTargetDesc Ret = PassOutputs[0].RenderTargetDesc; Ret.Reset(); Ret.DebugName = TEXT("HMD"); return Ret; }