2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-05-30 14:48:02 -04:00
# include "GenerateMips.h"
# include "RenderGraphUtils.h"
2019-11-18 18:19:05 -05:00
# include "ShaderParameterUtils.h"
2020-09-24 00:43:27 -04:00
# include "PipelineStateCache.h"
# include "GlobalShader.h"
# include "CommonRenderResources.h"
# include "RHIStaticStates.h"
2019-05-30 14:48:02 -04:00
class FGenerateMipsCS : public FGlobalShader
{
2019-11-04 19:42:39 -05:00
public :
2020-09-24 00:43:27 -04:00
DECLARE_GLOBAL_SHADER ( FGenerateMipsCS )
SHADER_USE_PARAMETER_STRUCT ( FGenerateMipsCS , FGlobalShader )
2019-11-05 10:01:21 -05:00
class FGenMipsSRGB : SHADER_PERMUTATION_BOOL ( " GENMIPS_SRGB " ) ;
2019-11-18 18:19:05 -05:00
class FGenMipsSwizzle : SHADER_PERMUTATION_BOOL ( " GENMIPS_SWIZZLE " ) ;
using FPermutationDomain = TShaderPermutationDomain < FGenMipsSRGB , FGenMipsSwizzle > ;
2019-11-05 10:01:21 -05:00
2019-05-30 14:48:02 -04:00
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER ( FVector2D , TexelSize )
SHADER_PARAMETER_RDG_TEXTURE_SRV ( Texture2D , MipInSRV )
SHADER_PARAMETER_RDG_TEXTURE_UAV ( RWTexture2D , MipOutUAV )
SHADER_PARAMETER_SAMPLER ( SamplerState , MipSampler )
END_SHADER_PARAMETER_STRUCT ( )
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
2019-11-07 20:02:54 -05:00
return RHISupportsComputeShaders ( Parameters . Platform ) ;
2019-05-30 14:48:02 -04:00
}
2020-09-24 00:43:27 -04:00
static void ModifyCompilationEnvironment ( const FShaderPermutationParameters & , FShaderCompilerEnvironment & OutEnvironment )
{
OutEnvironment . SetDefine ( TEXT ( " GENMIPS_COMPUTE " ) , 1 ) ;
}
2019-05-30 14:48:02 -04:00
} ;
2020-09-24 00:43:27 -04:00
2019-05-30 14:48:02 -04:00
IMPLEMENT_GLOBAL_SHADER ( FGenerateMipsCS , " /Engine/Private/ComputeGenerateMips.usf " , " MainCS " , SF_Compute ) ;
2020-09-24 00:43:27 -04:00
class FGenerateMipsVS : public FGlobalShader
2019-11-18 18:19:05 -05:00
{
public :
2020-09-24 00:43:27 -04:00
DECLARE_GLOBAL_SHADER ( FGenerateMipsVS ) ;
SHADER_USE_PARAMETER_STRUCT ( FGenerateMipsVS , FGlobalShader ) ;
using FParameters = FEmptyShaderParameters ;
2019-11-18 18:19:05 -05:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
2020-02-12 13:27:19 -05:00
return IsFeatureLevelSupported ( Parameters . Platform , ERHIFeatureLevel : : ES3_1 ) ;
2019-11-18 18:19:05 -05:00
}
2020-09-24 00:43:27 -04:00
static void ModifyCompilationEnvironment ( const FShaderPermutationParameters & , FShaderCompilerEnvironment & OutEnvironment )
{
OutEnvironment . SetDefine ( TEXT ( " GENMIPS_COMPUTE " ) , 0 ) ;
}
2019-11-18 18:19:05 -05:00
} ;
2020-09-24 00:43:27 -04:00
IMPLEMENT_GLOBAL_SHADER ( FGenerateMipsVS , " /Engine/Private/ComputeGenerateMips.usf " , " MainVS " , SF_Vertex ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
class FGenerateMipsPS : public FGlobalShader
2019-11-18 18:19:05 -05:00
{
public :
2020-09-24 00:43:27 -04:00
DECLARE_GLOBAL_SHADER ( FGenerateMipsPS ) ;
SHADER_USE_PARAMETER_STRUCT ( FGenerateMipsPS , FGlobalShader ) ;
BEGIN_SHADER_PARAMETER_STRUCT ( FParameters , )
SHADER_PARAMETER ( FVector2D , HalfTexelSize )
SHADER_PARAMETER ( float , Level )
SHADER_PARAMETER_RDG_TEXTURE_SRV ( Texture2D , MipInSRV )
SHADER_PARAMETER_SAMPLER ( SamplerState , MipSampler )
RENDER_TARGET_BINDING_SLOTS ( )
END_SHADER_PARAMETER_STRUCT ( )
2019-11-18 18:19:05 -05:00
static bool ShouldCompilePermutation ( const FGlobalShaderPermutationParameters & Parameters )
{
2020-02-12 13:27:19 -05:00
return IsFeatureLevelSupported ( Parameters . Platform , ERHIFeatureLevel : : ES3_1 ) ;
2019-11-18 18:19:05 -05:00
}
2020-09-24 00:43:27 -04:00
static void ModifyCompilationEnvironment ( const FShaderPermutationParameters & , FShaderCompilerEnvironment & OutEnvironment )
2019-11-18 18:19:05 -05:00
{
2020-09-24 00:43:27 -04:00
OutEnvironment . SetDefine ( TEXT ( " GENMIPS_COMPUTE " ) , 0 ) ;
2019-11-18 18:19:05 -05:00
}
} ;
2020-09-24 00:43:27 -04:00
IMPLEMENT_GLOBAL_SHADER ( FGenerateMipsPS , " /Engine/Private/ComputeGenerateMips.usf " , " MainPS " , SF_Pixel ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
void FGenerateMips : : ExecuteRaster ( FRDGBuilder & GraphBuilder , FRDGTextureRef Texture , FRHISamplerState * Sampler )
2019-11-18 18:19:05 -05:00
{
2020-09-24 00:43:27 -04:00
check ( Texture ) ;
check ( Sampler ) ;
2019-11-18 18:19:05 -05:00
auto ShaderMap = GetGlobalShaderMap ( GMaxRHIFeatureLevel ) ;
2020-09-24 00:43:27 -04:00
TShaderMapRef < FGenerateMipsVS > VertexShader ( ShaderMap ) ;
TShaderMapRef < FGenerateMipsPS > PixelShader ( ShaderMap ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
const FRDGTextureDesc & TextureDesc = Texture - > Desc ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
for ( uint32 MipLevel = 1 , MipCount = TextureDesc . NumMips ; MipLevel < MipCount ; + + MipLevel )
2019-11-18 18:19:05 -05:00
{
2020-09-24 00:43:27 -04:00
const uint32 InputMipLevel = MipLevel - 1 ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
const FIntPoint DestTextureSize (
FMath : : Max ( TextureDesc . Extent . X > > MipLevel , 1 ) ,
FMath : : Max ( TextureDesc . Extent . Y > > MipLevel , 1 ) ) ;
FGenerateMipsPS : : FParameters * PassParameters = GraphBuilder . AllocParameters < FGenerateMipsPS : : FParameters > ( ) ;
PassParameters - > HalfTexelSize = FVector2D ( 0.5f / DestTextureSize . X , 0.5f / DestTextureSize . Y ) ;
PassParameters - > Level = InputMipLevel ;
PassParameters - > MipInSRV = GraphBuilder . CreateSRV ( FRDGTextureSRVDesc : : CreateForMipLevel ( Texture , InputMipLevel ) ) ;
PassParameters - > MipSampler = Sampler ;
PassParameters - > RenderTargets [ 0 ] = FRenderTargetBinding ( Texture , ERenderTargetLoadAction : : ELoad , MipLevel ) ;
GraphBuilder . AddPass (
RDG_EVENT_NAME ( " GenerateMips DestMipLevel=%d " , MipLevel ) ,
PassParameters ,
ERDGPassFlags : : Raster ,
[ VertexShader , PixelShader , DestTextureSize ] ( FRHICommandList & RHICmdList )
2019-11-18 18:19:05 -05:00
{
2020-09-24 00:43:27 -04:00
RHICmdList . SetViewport ( 0.0f , 0.0f , 0.0f , ( float ) DestTextureSize . X , ( float ) DestTextureSize . Y , 1.0f ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
FGraphicsPipelineStateInitializer GraphicsPSOInit ;
GraphicsPSOInit . DepthStencilState = TStaticDepthStencilState < false , CF_Always > : : GetRHI ( ) ;
GraphicsPSOInit . RasterizerState = TStaticRasterizerState < > : : GetRHI ( ) ;
GraphicsPSOInit . BlendState = TStaticBlendStateWriteMask < CW_RGBA , CW_NONE , CW_NONE , CW_NONE , CW_NONE , CW_NONE , CW_NONE , CW_NONE > : : GetRHI ( ) ;
GraphicsPSOInit . PrimitiveType = PT_TriangleStrip ;
GraphicsPSOInit . BoundShaderState . VertexDeclarationRHI = GFilterVertexDeclaration . VertexDeclarationRHI ;
GraphicsPSOInit . BoundShaderState . VertexShaderRHI = VertexShader . GetVertexShader ( ) ;
GraphicsPSOInit . BoundShaderState . PixelShaderRHI = PixelShader . GetPixelShader ( ) ;
RHICmdList . ApplyCachedRenderTargets ( GraphicsPSOInit ) ;
SetGraphicsPipelineState ( RHICmdList , GraphicsPSOInit ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
RHICmdList . SetStreamSource ( 0 , GScreenRectangleVertexBuffer . VertexBufferRHI , 0 ) ;
RHICmdList . DrawPrimitive ( 0 , 2 , 1 ) ;
} ) ;
2019-11-18 18:19:05 -05:00
}
}
2020-09-24 00:43:27 -04:00
void FGenerateMips : : ExecuteCompute ( FRDGBuilder & GraphBuilder , FRDGTextureRef Texture , FRHISamplerState * Sampler )
2019-05-30 14:48:02 -04:00
{
2020-09-24 00:43:27 -04:00
check ( Texture ) ;
check ( Sampler ) ;
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
const FRDGTextureDesc & TextureDesc = Texture - > Desc ;
2019-05-30 14:48:02 -04:00
2020-09-24 00:43:27 -04:00
// Select compute shader variant (normal vs. sRGB etc.)
2019-11-18 18:19:05 -05:00
# if PLATFORM_ANDROID
const bool bIsUsingVulkan = FAndroidMisc : : ShouldUseVulkan ( ) ;
# else
const bool bIsUsingVulkan = false ;
# endif
2020-02-12 13:27:19 -05:00
2019-11-05 10:01:21 -05:00
FGenerateMipsCS : : FPermutationDomain PermutationVector ;
2020-09-24 00:43:27 -04:00
PermutationVector . Set < FGenerateMipsCS : : FGenMipsSRGB > ( EnumHasAnyFlags ( TextureDesc . Flags , TexCreate_SRGB ) ) ;
PermutationVector . Set < FGenerateMipsCS : : FGenMipsSwizzle > ( bIsUsingVulkan ) ; // On Vulkan we experience RGB being swizzled around, this little switch circumvents the issue.
2019-11-07 20:02:54 -05:00
TShaderMapRef < FGenerateMipsCS > ComputeShader ( GetGlobalShaderMap ( GMaxRHIFeatureLevel ) , PermutationVector ) ;
2019-05-30 14:48:02 -04:00
2020-09-24 00:43:27 -04:00
// Loop through each level of the mips that require creation and add a dispatch pass per level.
for ( uint32 MipLevel = 1 , MipCount = TextureDesc . NumMips ; MipLevel < MipCount ; + + MipLevel )
2019-05-30 14:48:02 -04:00
{
2020-09-24 00:43:27 -04:00
const FIntPoint DestTextureSize (
FMath : : Max ( TextureDesc . Extent . X > > MipLevel , 1 ) ,
FMath : : Max ( TextureDesc . Extent . Y > > MipLevel , 1 ) ) ;
2019-05-30 14:48:02 -04:00
FGenerateMipsCS : : FParameters * PassParameters = GraphBuilder . AllocParameters < FGenerateMipsCS : : FParameters > ( ) ;
2020-09-24 00:43:27 -04:00
PassParameters - > TexelSize = FVector2D ( 1.0f / DestTextureSize . X , 1.0f / DestTextureSize . Y ) ;
PassParameters - > MipInSRV = GraphBuilder . CreateSRV ( FRDGTextureSRVDesc : : CreateForMipLevel ( Texture , MipLevel - 1 ) ) ;
PassParameters - > MipOutUAV = GraphBuilder . CreateUAV ( FRDGTextureUAVDesc ( Texture , MipLevel ) ) ;
PassParameters - > MipSampler = Sampler ;
2019-05-30 14:48:02 -04:00
2020-09-24 00:43:27 -04:00
FComputeShaderUtils : : AddPass (
GraphBuilder ,
RDG_EVENT_NAME ( " GenerateMips DestMipLevel=%d " , MipLevel ) ,
ComputeShader ,
2019-05-30 14:48:02 -04:00
PassParameters ,
2020-09-24 00:43:27 -04:00
FComputeShaderUtils : : GetGroupCount ( DestTextureSize , FComputeShaderUtils : : kGolden2DGroupSize ) ) ;
2019-05-30 14:48:02 -04:00
}
}
2020-09-24 00:43:27 -04:00
BEGIN_SHADER_PARAMETER_STRUCT ( FCopyDestParameters , )
RDG_TEXTURE_ACCESS ( Texture , ERHIAccess : : CopyDest )
END_SHADER_PARAMETER_STRUCT ( )
2019-11-18 18:19:05 -05:00
2020-09-24 00:43:27 -04:00
void FGenerateMips : : Execute ( FRDGBuilder & GraphBuilder , FRDGTextureRef Texture , FGenerateMipsParams Params , EGenerateMipsPass Pass )
2019-05-30 14:48:02 -04:00
{
2020-09-24 00:43:27 -04:00
if ( Texture - > Desc . NumMips > 1 )
2019-05-30 14:48:02 -04:00
{
if ( RHIRequiresComputeGenerateMips ( ) )
{
2021-01-21 16:22:06 -04:00
FSamplerStateInitializerRHI SamplerInit ( Params . Filter , Params . AddressU , Params . AddressV , Params . AddressW ) ;
2020-09-24 00:43:27 -04:00
Execute ( GraphBuilder , Texture , RHICreateSamplerState ( SamplerInit ) , Pass ) ;
2019-11-18 18:19:05 -05:00
}
else
{
2020-09-24 00:43:27 -04:00
FCopyDestParameters * PassParameters = GraphBuilder . AllocParameters < FCopyDestParameters > ( ) ;
PassParameters - > Texture = Texture ;
GraphBuilder . AddPass (
RDG_EVENT_NAME ( " GenerateMipsTexture " ) ,
PassParameters ,
ERDGPassFlags : : Copy ,
[ Texture ] ( FRHICommandListImmediate & RHICmdList )
{
RHICmdList . GenerateMips ( Texture - > GetRHI ( ) ) ;
} ) ;
2019-05-30 14:48:02 -04:00
}
}
2019-09-14 09:45:25 -04:00
}
2020-09-24 00:43:27 -04:00
void FGenerateMips : : Execute ( FRHICommandListImmediate & RHICmdList , FRHITexture * Texture , TSharedPtr < FGenerateMipsStruct > & ExternalMipsStructCache , FGenerateMipsParams Params , bool bAllowRenderBasedGeneration )
2019-09-14 09:45:25 -04:00
{
2020-09-24 00:43:27 -04:00
TRefCountPtr < IPooledRenderTarget > PooledRenderTarget = CreateRenderTarget ( Texture , TEXT ( " MipGeneration " ) ) ;
2019-09-14 09:45:25 -04:00
2020-09-24 00:43:27 -04:00
FRDGBuilder GraphBuilder ( RHICmdList ) ;
Execute ( GraphBuilder , GraphBuilder . RegisterExternalTexture ( PooledRenderTarget ) , Params , bAllowRenderBasedGeneration ? EGenerateMipsPass : : Raster : EGenerateMipsPass : : Compute ) ;
GraphBuilder . Execute ( ) ;
}
void FGenerateMips : : Execute ( FRHICommandListImmediate & RHICmdList , FRHITexture * Texture , FGenerateMipsParams Params , bool bAllowRenderBasedGeneration )
{
TRefCountPtr < IPooledRenderTarget > PooledRenderTarget = CreateRenderTarget ( Texture , TEXT ( " MipGeneration " ) ) ;
FRDGBuilder GraphBuilder ( RHICmdList ) ;
Execute ( GraphBuilder , GraphBuilder . RegisterExternalTexture ( PooledRenderTarget ) , Params , bAllowRenderBasedGeneration ? EGenerateMipsPass : : Raster : EGenerateMipsPass : : Compute ) ;
GraphBuilder . Execute ( ) ;
2019-09-14 09:45:25 -04:00
}