You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#jira none #rb zach.bethel, mihnea.balta, florin.pascu #preflight 61312f4a79ce170001d4a79e #ROBOMERGE-SOURCE: CL 17422777 in //UE5/Main/... #ROBOMERGE-BOT: STARSHIP (Main -> Release-Engine-Test) (v865-17346139) #ROBOMERGE[bot1]: emt [CL 17422941 by christopher waters in ue5-release-engine-test branch]
475 lines
21 KiB
C++
475 lines
21 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
|
|
=============================================================================*/
|
|
#include "MobileReflectionEnvironmentCapture.h"
|
|
#include "ReflectionEnvironmentCapture.h"
|
|
#include "ShaderParameterUtils.h"
|
|
#include "RHIStaticStates.h"
|
|
#include "SceneRenderTargets.h"
|
|
#include "SceneUtils.h"
|
|
#include "ScreenRendering.h"
|
|
#include "PipelineStateCache.h"
|
|
#include "SceneFilterRendering.h"
|
|
#include "OneColorShader.h"
|
|
|
|
extern int32 GDiffuseIrradianceCubemapSize;
|
|
extern float ComputeSingleAverageBrightnessFromCubemap(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 TargetSize, FSceneRenderTargetItem& Cubemap);
|
|
extern void FullyResolveReflectionScratchCubes(FRHICommandListImmediate& RHICmdList);
|
|
|
|
static TAutoConsoleVariable<int32> CVarMobileUseHighQualitySkyCaptureFiltering(
|
|
TEXT("r.Mobile.HighQualitySkyCaptureFiltering"),
|
|
1,
|
|
TEXT("1: (default) use high quality filtering when generating mobile sky captures.")
|
|
TEXT("0: use simple bilinear filtering when generating mobile sky captures."),
|
|
ECVF_RenderThreadSafe);
|
|
|
|
extern TGlobalResource<FReflectionScratchCubemaps> GReflectionScratchCubemaps;
|
|
|
|
class FMobileDownsamplePS : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FMobileDownsamplePS, Global);
|
|
public:
|
|
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
|
|
{
|
|
return IsMobilePlatform(Parameters.Platform);
|
|
}
|
|
|
|
FMobileDownsamplePS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) :
|
|
FGlobalShader(Initializer)
|
|
{
|
|
CubeFace.Bind(Initializer.ParameterMap, TEXT("CubeFace"));
|
|
SourceMipIndex.Bind(Initializer.ParameterMap, TEXT("SourceMipIndex"));
|
|
SourceCubemapTexture.Bind(Initializer.ParameterMap, TEXT("SourceCubemapTexture"));
|
|
SourceCubemapSampler.Bind(Initializer.ParameterMap, TEXT("SourceCubemapSampler"));
|
|
}
|
|
FMobileDownsamplePS() {}
|
|
|
|
void SetParameters(FRHICommandList& RHICmdList, int32 CubeFaceValue, int32 SourceMipIndexValue, FSceneRenderTargetItem& SourceTextureValue)
|
|
{
|
|
SetShaderValue(RHICmdList, RHICmdList.GetBoundPixelShader(), CubeFace, CubeFaceValue);
|
|
SetShaderValue(RHICmdList, RHICmdList.GetBoundPixelShader(), SourceMipIndex, SourceMipIndexValue);
|
|
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
RHICmdList.GetBoundPixelShader(),
|
|
SourceCubemapTexture,
|
|
SourceCubemapSampler,
|
|
TStaticSamplerState<SF_Bilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
|
|
SourceTextureValue.ShaderResourceTexture);
|
|
}
|
|
|
|
private:
|
|
LAYOUT_FIELD(FShaderParameter, CubeFace)
|
|
LAYOUT_FIELD(FShaderParameter, SourceMipIndex)
|
|
LAYOUT_FIELD(FShaderResourceParameter, SourceCubemapTexture)
|
|
LAYOUT_FIELD(FShaderResourceParameter, SourceCubemapSampler)
|
|
};
|
|
|
|
IMPLEMENT_SHADER_TYPE(, FMobileDownsamplePS, TEXT("/Engine/Private/ReflectionEnvironmentShaders.usf"), TEXT("DownsamplePS_Mobile"), SF_Pixel);
|
|
namespace MobileReflectionEnvironmentCapture
|
|
{
|
|
/** Encapsulates render target picking logic for cubemap mip generation. */
|
|
FSceneRenderTargetItem& GetEffectiveRenderTarget(bool bDownsamplePass, int32 TargetMipIndex)
|
|
{
|
|
int32 ScratchTextureIndex = TargetMipIndex % 2;
|
|
|
|
if (!bDownsamplePass)
|
|
{
|
|
ScratchTextureIndex = 1 - ScratchTextureIndex;
|
|
}
|
|
|
|
return GReflectionScratchCubemaps.Color[ScratchTextureIndex]->GetRenderTargetItem();
|
|
}
|
|
|
|
/** Encapsulates source texture picking logic for cubemap mip generation. */
|
|
FSceneRenderTargetItem& GetEffectiveSourceTexture(bool bDownsamplePass, int32 TargetMipIndex)
|
|
{
|
|
int32 ScratchTextureIndex = TargetMipIndex % 2;
|
|
|
|
if (bDownsamplePass)
|
|
{
|
|
ScratchTextureIndex = 1 - ScratchTextureIndex;
|
|
}
|
|
|
|
return GReflectionScratchCubemaps.Color[ScratchTextureIndex]->GetRenderTargetItem();
|
|
}
|
|
|
|
void ComputeAverageBrightness(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, float& OutAverageBrightness)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, ComputeAverageBrightness);
|
|
|
|
const int32 EffectiveTopMipSize = CubmapSize;
|
|
const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
|
|
|
|
// necessary to resolve the clears which touched all the mips. scene rendering only resolves mip 0.
|
|
FullyResolveReflectionScratchCubes(RHICmdList);
|
|
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMips);
|
|
|
|
// Downsample all the mips, each one reads from the mip above it
|
|
for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0);
|
|
const int32 MipSize = 1 << (NumMips - MipIndex - 1);
|
|
|
|
FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(true, MipIndex);
|
|
FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(true, MipIndex);
|
|
check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture);
|
|
|
|
for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store);
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = CubeFace;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = MipIndex;
|
|
TransitionRenderPassTargets(RHICmdList, RPInfo);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("AverageBrightness"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
|
|
const FIntRect ViewRect(0, 0, MipSize, MipSize);
|
|
RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f);
|
|
|
|
TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
|
|
TShaderMapRef<FMobileDownsamplePS> PixelShader(ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
|
|
PixelShader->SetParameters(RHICmdList, CubeFace, SourceMipIndex, EffectiveSource);
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
FIntPoint(ViewRect.Width(), ViewRect.Height()),
|
|
FIntPoint(MipSize, MipSize),
|
|
VertexShader);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
FResolveParams ResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex);
|
|
ResolveParams.SourceAccessFinal = ERHIAccess::SRVMask;
|
|
ResolveParams.DestAccessFinal = ERHIAccess::SRVMask;
|
|
RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, ResolveParams);
|
|
}
|
|
}
|
|
}
|
|
|
|
OutAverageBrightness = ComputeSingleAverageBrightnessFromCubemap(RHICmdList, FeatureLevel, CubmapSize, GetEffectiveRenderTarget(true, NumMips - 1));
|
|
}
|
|
|
|
void CopyToSkyTexture(FRHICommandList& RHICmdList, FScene* Scene, FTexture* ProcessedTexture)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, CopyToSkyTexture);
|
|
if (ProcessedTexture->TextureRHI)
|
|
{
|
|
const bool bUseHQFiltering = CVarMobileUseHighQualitySkyCaptureFiltering.GetValueOnRenderThread() == 1;
|
|
const int32 EffectiveTopMipSize = ProcessedTexture->GetSizeX();
|
|
const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
|
|
|
|
RHICmdList.Transition(FRHITransitionInfo(ProcessedTexture->TextureRHI, ERHIAccess::Unknown, ERHIAccess::CopyDest));
|
|
|
|
FRHICopyTextureInfo CopyInfo;
|
|
CopyInfo.Size = FIntVector(ProcessedTexture->GetSizeX(), ProcessedTexture->GetSizeY(), 1);
|
|
CopyInfo.NumSlices = 6;
|
|
|
|
// GPU copy back to the skylight's texture, which is not a render target
|
|
for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
// For simple mobile bilin filtering the source for this copy is the dest from the filtering pass.
|
|
// In the HQ case, the full image is contained in GetEffectiveRenderTarget(.., false,0).
|
|
FSceneRenderTargetItem& EffectiveSource = GetEffectiveRenderTarget(false, bUseHQFiltering ? 0 : MipIndex);
|
|
RHICmdList.Transition(FRHITransitionInfo(EffectiveSource.ShaderResourceTexture, ERHIAccess::Unknown, ERHIAccess::CopySrc));
|
|
RHICmdList.CopyTexture(EffectiveSource.ShaderResourceTexture, ProcessedTexture->TextureRHI, CopyInfo);
|
|
|
|
++CopyInfo.SourceMipIndex;
|
|
++CopyInfo.DestMipIndex;
|
|
CopyInfo.Size.X = FMath::Max(1, CopyInfo.Size.X / 2);
|
|
CopyInfo.Size.Y = FMath::Max(1, CopyInfo.Size.Y / 2);
|
|
}
|
|
|
|
RHICmdList.Transition(FRHITransitionInfo(ProcessedTexture->TextureRHI, ERHIAccess::CopyDest, ERHIAccess::SRVMask));
|
|
}
|
|
}
|
|
|
|
/** Generates mips for glossiness and filters the cubemap for a given reflection. */
|
|
void FilterReflectionEnvironment(FRHICommandListImmediate& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, int32 CubmapSize, FSHVectorRGB3* OutIrradianceEnvironmentMap)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, FilterReflectionEnvironment);
|
|
|
|
const int32 EffectiveTopMipSize = CubmapSize;
|
|
const int32 NumMips = FMath::CeilLogTwo(EffectiveTopMipSize) + 1;
|
|
const bool bUseHQFiltering = CVarMobileUseHighQualitySkyCaptureFiltering.GetValueOnRenderThread() == 1;
|
|
{
|
|
FSceneRenderTargetItem& EffectiveColorRT = GReflectionScratchCubemaps.Color[0]->GetRenderTargetItem();
|
|
// Premultiply alpha in-place using alpha blending
|
|
for (uint32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(EffectiveColorRT.TargetableTexture, ERenderTargetActions::Load_Store);
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = CubeFace;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = 0;
|
|
|
|
TransitionRenderPassTargets(RHICmdList, RPInfo);
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterReflectionEnvironment"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_Zero, BF_DestAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();
|
|
|
|
const FIntPoint SourceDimensions(CubmapSize, CubmapSize);
|
|
const FIntRect ViewRect(0, 0, EffectiveTopMipSize, EffectiveTopMipSize);
|
|
RHICmdList.SetViewport(0, 0, 0.0f, EffectiveTopMipSize, EffectiveTopMipSize, 1.0f);
|
|
|
|
TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
|
|
TShaderMapRef<FOneColorPS> PixelShader(GetGlobalShaderMap(FeatureLevel));
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
|
|
FLinearColor UnusedColors[1] = { FLinearColor::Black };
|
|
PixelShader->SetColors(RHICmdList, UnusedColors, UE_ARRAY_COUNT(UnusedColors));
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
0, 0,
|
|
SourceDimensions.X, SourceDimensions.Y,
|
|
FIntPoint(ViewRect.Width(), ViewRect.Height()),
|
|
SourceDimensions,
|
|
VertexShader);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
FResolveParams ResolveParams(FResolveRect(), (ECubeFace)CubeFace);
|
|
ResolveParams.SourceAccessFinal = ERHIAccess::SRVMask;
|
|
ResolveParams.DestAccessFinal = ERHIAccess::SRVMask;
|
|
RHICmdList.CopyToResolveTarget(EffectiveColorRT.TargetableTexture, EffectiveColorRT.ShaderResourceTexture, ResolveParams);
|
|
} // end for
|
|
}
|
|
|
|
int32 DiffuseConvolutionSourceMip = INDEX_NONE;
|
|
FSceneRenderTargetItem* DiffuseConvolutionSource = NULL;
|
|
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMips);
|
|
// Downsample all the mips, each one reads from the mip above it
|
|
for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, DownsampleCubeMip);
|
|
const int32 SourceMipIndex = FMath::Max(MipIndex - 1, 0);
|
|
const int32 MipSize = 1 << (NumMips - MipIndex - 1);
|
|
|
|
FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(true, MipIndex);
|
|
FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(true, MipIndex);
|
|
check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture);
|
|
|
|
for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store);
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = CubeFace;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = MipIndex;
|
|
TransitionRenderPassTargets(RHICmdList, RPInfo);
|
|
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("DownsampleCubemap"));
|
|
{
|
|
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
|
|
const FIntRect ViewRect(0, 0, MipSize, MipSize);
|
|
RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f);
|
|
|
|
TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
|
|
TShaderMapRef<FMobileDownsamplePS> PixelShader(ShaderMap);
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
|
|
PixelShader->SetParameters(RHICmdList, CubeFace, SourceMipIndex, EffectiveSource);
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
FIntPoint(ViewRect.Width(), ViewRect.Height()),
|
|
FIntPoint(MipSize, MipSize),
|
|
VertexShader);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
FResolveParams ResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex);
|
|
ResolveParams.SourceAccessFinal = ERHIAccess::SRVMask;
|
|
ResolveParams.DestAccessFinal = ERHIAccess::SRVMask;
|
|
RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, ResolveParams);
|
|
}
|
|
|
|
if (DiffuseConvolutionSource == NULL && MipSize <= GDiffuseIrradianceCubemapSize)
|
|
{
|
|
DiffuseConvolutionSourceMip = MipIndex;
|
|
DiffuseConvolutionSource = &EffectiveRT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OutIrradianceEnvironmentMap)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, ComputeDiffuseIrradiance);
|
|
check(DiffuseConvolutionSource != NULL);
|
|
ComputeDiffuseIrradiance(RHICmdList, FeatureLevel, DiffuseConvolutionSource->ShaderResourceTexture, DiffuseConvolutionSourceMip, OutIrradianceEnvironmentMap);
|
|
}
|
|
|
|
if (bUseHQFiltering)
|
|
{
|
|
// When HQ filtering is enabled the filter shader requires access to all mips levels of the source cubemap.
|
|
// Here we ensure that GetEffectiveSourceTexture(0,false) will have a complete set of mips for this process.
|
|
SCOPED_DRAW_EVENT(RHICmdList, PrepareSourceCubemapMipsForHQFiltering);
|
|
for (int32 MipIndex = 1; MipIndex < NumMips; MipIndex += 2)
|
|
{
|
|
FSceneRenderTargetItem& SourceTarget = GetEffectiveRenderTarget(true, MipIndex);
|
|
FSceneRenderTargetItem& DestTarget = GetEffectiveSourceTexture(true, MipIndex);
|
|
check(DestTarget.TargetableTexture != SourceTarget.ShaderResourceTexture);
|
|
|
|
// Transition the textures once, so CopyToResolveTarget doesn't ping-pong uselessly between the copy and SRV states.
|
|
FRHITransitionInfo TransitionsBefore[] = {
|
|
FRHITransitionInfo(SourceTarget.ShaderResourceTexture, ERHIAccess::SRVMask, ERHIAccess::CopySrc),
|
|
FRHITransitionInfo(DestTarget.ShaderResourceTexture, ERHIAccess::SRVMask, ERHIAccess::CopyDest)
|
|
};
|
|
RHICmdList.Transition(MakeArrayView(TransitionsBefore, UE_ARRAY_COUNT(TransitionsBefore)));
|
|
|
|
// Tell CopyToResolveTarget to leave the textures in the copy state, because we'll transition them only once when we're done.
|
|
FResolveParams ResolveParams(FResolveRect(), CubeFace_PosX, MipIndex);
|
|
ResolveParams.SourceAccessFinal = ERHIAccess::CopySrc;
|
|
ResolveParams.DestAccessFinal = ERHIAccess::CopyDest;
|
|
|
|
for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
|
|
{
|
|
ResolveParams.CubeFace = (ECubeFace)CubeFace;
|
|
RHICmdList.CopyToResolveTarget(SourceTarget.ShaderResourceTexture, DestTarget.ShaderResourceTexture, ResolveParams);
|
|
}
|
|
|
|
// We're done copying, transition the textures back to SRV.
|
|
FRHITransitionInfo TransitionsAfter[] = {
|
|
FRHITransitionInfo(SourceTarget.ShaderResourceTexture, ERHIAccess::CopySrc, ERHIAccess::SRVMask),
|
|
FRHITransitionInfo(DestTarget.ShaderResourceTexture, ERHIAccess::CopyDest, ERHIAccess::SRVMask)
|
|
};
|
|
RHICmdList.Transition(MakeArrayView(TransitionsAfter, UE_ARRAY_COUNT(TransitionsAfter)));
|
|
}
|
|
}
|
|
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMap);
|
|
// Filter all the mips.
|
|
// in simple mobile bilin case each one reads from whichever scratch render target holds the downsampled contents, and writes to the destination cubemap.
|
|
// HQ case, all mips are contained in GetEffectiveSourceTexture(.., false,0) as it needs a complete mip chain.
|
|
for (int32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
SCOPED_DRAW_EVENT(RHICmdList, FilterCubeMip);
|
|
FSceneRenderTargetItem& EffectiveRT = GetEffectiveRenderTarget(false, bUseHQFiltering ? 0 : MipIndex);
|
|
FSceneRenderTargetItem& EffectiveSource = GetEffectiveSourceTexture(false, bUseHQFiltering ? 0 : MipIndex);
|
|
check(EffectiveRT.TargetableTexture != EffectiveSource.ShaderResourceTexture);
|
|
const int32 MipSize = 1 << (NumMips - MipIndex - 1);
|
|
|
|
for (int32 CubeFace = 0; CubeFace < CubeFace_MAX; CubeFace++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(EffectiveRT.TargetableTexture, ERenderTargetActions::Load_Store);
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = CubeFace;
|
|
RPInfo.ColorRenderTargets[0].MipIndex = MipIndex;
|
|
TransitionRenderPassTargets(RHICmdList, RPInfo);
|
|
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("FilterCubeMip"));
|
|
{
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<FM_Solid, CM_None>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<>::GetRHI();
|
|
|
|
const FIntRect ViewRect(0, 0, MipSize, MipSize);
|
|
RHICmdList.SetViewport(0, 0, 0.0f, MipSize, MipSize, 1.0f);
|
|
|
|
TShaderMapRef<FScreenVS> VertexShader(GetGlobalShaderMap(FeatureLevel));
|
|
|
|
TShaderMapRef<TCubeFilterPS<0>> HQFilterPixelShader(ShaderMap);
|
|
TShaderMapRef<FMobileDownsamplePS> BilinFilterPixelShader(ShaderMap);
|
|
FRHIPixelShader* PixelShaderRHI = bUseHQFiltering ? HQFilterPixelShader.GetPixelShader() : BilinFilterPixelShader.GetPixelShader();
|
|
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShaderRHI;
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
|
|
if (bUseHQFiltering)
|
|
{
|
|
SetShaderValue(RHICmdList, PixelShaderRHI, HQFilterPixelShader->CubeFace, CubeFace);
|
|
SetShaderValue(RHICmdList, PixelShaderRHI, HQFilterPixelShader->MipIndex, MipIndex);
|
|
SetShaderValue(RHICmdList, PixelShaderRHI, HQFilterPixelShader->NumMips, NumMips);
|
|
SetTextureParameter(
|
|
RHICmdList,
|
|
PixelShaderRHI,
|
|
HQFilterPixelShader->SourceCubemapTexture,
|
|
HQFilterPixelShader->SourceCubemapSampler,
|
|
TStaticSamplerState<SF_Trilinear, AM_Clamp, AM_Clamp, AM_Clamp>::GetRHI(),
|
|
EffectiveSource.ShaderResourceTexture);
|
|
}
|
|
else
|
|
{
|
|
BilinFilterPixelShader->SetParameters(RHICmdList, CubeFace, MipIndex, EffectiveSource);
|
|
}
|
|
|
|
DrawRectangle(
|
|
RHICmdList,
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
ViewRect.Min.X, ViewRect.Min.Y,
|
|
ViewRect.Width(), ViewRect.Height(),
|
|
FIntPoint(ViewRect.Width(), ViewRect.Height()),
|
|
FIntPoint(MipSize, MipSize),
|
|
VertexShader);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
|
|
FResolveParams ResolveParams(FResolveRect(), (ECubeFace)CubeFace, MipIndex);
|
|
ResolveParams.SourceAccessFinal = ERHIAccess::SRVMask;
|
|
ResolveParams.DestAccessFinal = ERHIAccess::SRVMask;
|
|
RHICmdList.CopyToResolveTarget(EffectiveRT.TargetableTexture, EffectiveRT.ShaderResourceTexture, ResolveParams);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|