ue4系列: shader
简单记录一下ue中global shader的注册、编译和使用。ue的shader里面各种宏乱飞,不得不说,宏是各种引擎里面,最恶心的地方了,尤其是uber shader的大一统写法,不过也算是有舍有得。
本文以PostProcessSubsurface.cpp/PostProcessSubsurface.usf的MainIndirectDispatchCS为例。
- global shader中宏的声明
MainIndirectDispatchCS中使用的宏都在这里定义,利用ShaderPermutation.h把每一个宏包装为一个单独的类。
1
2
3
4
5
6
7
8
9class FSubsurfacePassFunction : SHADER_PERMUTATION_ENUM_CLASS("SUBSURFACE_PASS", ESubsurfacePass);
class FDimensionQuality : SHADER_PERMUTATION_ENUM_CLASS("SUBSURFACE_QUALITY", EQuality);
class FBilateralFilterKernelFunctionType : SHADER_PERMUTATION_ENUM_CLASS("BILATERAL_FILTER_KERNEL_FUNCTION_TYPE", EBilateralFilterKernelFunctionType);
class FSubsurfaceType : SHADER_PERMUTATION_ENUM_CLASS("SUBSURFACE_TYPE", ESubsurfaceType);
class FDimensionHalfRes : SHADER_PERMUTATION_BOOL("SUBSURFACE_HALF_RES");
class FRunningInSeparable : SHADER_PERMUTATION_BOOL("SUBSURFACE_FORCE_SEPARABLE");
class FDimensionEnableProfileIDCache : SHADER_PERMUTATION_BOOL("ENABLE_PROFILE_ID_CACHE");
using FPermutationDomain = TShaderPermutationDomain<FSubsurfacePassFunction, FDimensionQuality,
FBilateralFilterKernelFunctionType, FSubsurfaceType, FDimensionHalfRes, FRunningInSeparable, FDimensionEnableProfileIDCache>;
- shader permutation
1 | IMPLEMENT_GLOBAL_SHADER(FSubsurfaceIndirectDispatchCS, "/Engine/Private/PostProcessSubsurface.usf", "MainIndirectDispatchCS", SF_Compute); |
ue里面各种宏,看的眼晕。IMPLEMENT_GLOBAL_SHADER实例化一个静态对象(通过IMPLEMENT_SHADER_TYPE),渲染模块加载(FEngineLoop::LoadPreInitModules)时候就会执行,在FShaderType::FShaderType的构造(shader.cpp)中调用GlobalListLink.LinkHead把当前类型注册到全局shader链表中,并通过CompileGlobalShaderMap、VerifyGlobalShaders(遍历shader permutation)、FGlobalShaderTypeCompiler::BeginCompileShader编译。
- 使用
Engine/Source/Runtime/RenderCore/Public/Shader.h L2105~L2122
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18template<typename ShaderType>
class TShaderMapRef : public TShaderRef<ShaderType>
{
public:
TShaderMapRef(const typename ShaderType::ShaderMapType* ShaderIndex)
: TShaderRef<ShaderType>(ShaderIndex->template GetShader<ShaderType>(/* PermutationId = */ 0)) // gcc3 needs the template quantifier so it knows the < is not a less-than
{
static_assert(
TIsSame<typename ShaderType::FPermutationDomain, FShaderPermutationNone>::Value,
"Missing permutation vector argument for shader that have a permutation domain.");
}
TShaderMapRef(
const typename ShaderType::ShaderMapType* ShaderIndex,
const typename ShaderType::FPermutationDomain& PermutationVector)
: TShaderRef<ShaderType>(ShaderIndex->template GetShader<ShaderType>(PermutationVector.ToDimensionValueId())) // gcc3 needs the template quantifier so it knows the < is not a less-than
{ }
};
1 | SHADER::FPermutationDomain ComputeShaderPermutationVector; |
TShaderMapRef