2024-02-05 09:54:25 +08:00
|
|
|
|
---
|
|
|
|
|
title: 剖析虚幻渲染体系(08)- Shader体系
|
|
|
|
|
date: 2024-02-04 21:44:10
|
|
|
|
|
excerpt:
|
|
|
|
|
tags:
|
|
|
|
|
rating: ⭐
|
|
|
|
|
---
|
|
|
|
|
# 前言
|
2024-02-06 10:30:09 +08:00
|
|
|
|
原文地址:https://www.cnblogs.com/timlly/p/15092257.html
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# FShader
|
|
|
|
|
```c++
|
|
|
|
|
class FShader
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
// 在编译触发之前修改编译环境参数, 可由子类覆盖.
|
|
|
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment&) {}
|
|
|
|
|
|
|
|
|
|
// 是否需要编译指定的排列, 可由子类覆盖.
|
|
|
|
|
static bool ShouldCompilePermutation(const FShaderPermutationParameters&) { return true; }
|
|
|
|
|
|
|
|
|
|
// 检测编译结果是否有效, 可由子类覆盖.
|
|
|
|
|
static bool ValidateCompiledResult(EShaderPlatform InPlatform, const FShaderParameterMap& InParameterMap, TArray<FString>& OutError) { return true; }
|
|
|
|
|
|
|
|
|
|
// 取得RayTracingPayloadType
|
|
|
|
|
static ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId) { return static_cast<ERayTracingPayloadType>(0); }
|
|
|
|
|
|
|
|
|
|
// 获取各类数据的Hash的接口.
|
|
|
|
|
RENDERCORE_API const FSHAHash& GetHash() const;
|
|
|
|
|
RENDERCORE_API const FSHAHash& GetVertexFactoryHash() const;
|
|
|
|
|
RENDERCORE_API const FSHAHash& GetOutputHash() const;
|
|
|
|
|
|
|
|
|
|
/** Returns an identifier suitable for deterministic sorting of shaders between sessions. */
|
|
|
|
|
uint32 GetSortKey() const { return SortKey; }
|
|
|
|
|
// 保存并检测shader代码的编译结果.
|
|
|
|
|
RENDERCORE_API void Finalize(const FShaderMapResourceCode* Code);
|
|
|
|
|
|
|
|
|
|
// 数据获取接口.
|
|
|
|
|
inline FShaderType* GetType(const FShaderMapPointerTable& InPointerTable) const { return Type.Get(InPointerTable.ShaderTypes); }
|
|
|
|
|
inline FShaderType* GetType(const FPointerTableBase* InPointerTable) const { return Type.Get(InPointerTable); }
|
|
|
|
|
inline FVertexFactoryType* GetVertexFactoryType(const FShaderMapPointerTable& InPointerTable) const { return VFType.Get(InPointerTable.VFTypes); }
|
|
|
|
|
inline FVertexFactoryType* GetVertexFactoryType(const FPointerTableBase* InPointerTable) const { return VFType.Get(InPointerTable); }
|
|
|
|
|
inline FShaderType* GetTypeUnfrozen() const { return Type.GetUnfrozen(); }
|
|
|
|
|
inline int32 GetResourceIndex() const { checkSlow(ResourceIndex != INDEX_NONE); return ResourceIndex; }
|
|
|
|
|
inline EShaderPlatform GetShaderPlatform() const { return Target.GetPlatform(); }
|
|
|
|
|
inline EShaderFrequency GetFrequency() const { return Target.GetFrequency(); }
|
|
|
|
|
inline const FShaderTarget GetTarget() const { return Target; }
|
|
|
|
|
inline bool IsFrozen() const { return Type.IsFrozen(); }
|
|
|
|
|
inline uint32 GetNumInstructions() const { return NumInstructions; }
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
inline uint32 GetNumTextureSamplers() const { return NumTextureSamplers; }
|
|
|
|
|
inline uint32 GetCodeSize() const { return CodeSize; }
|
|
|
|
|
inline void SetNumInstructions(uint32 Value) { NumInstructions = Value; }
|
|
|
|
|
#else
|
|
|
|
|
inline uint32 GetNumTextureSamplers() const { return 0u; }
|
|
|
|
|
inline uint32 GetCodeSize() const { return 0u; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 尝试返回匹配指定类型的自动绑定的Uniform Buffer, 如果不存在则返回未绑定的.
|
|
|
|
|
template<typename UniformBufferStructType>
|
|
|
|
|
FORCEINLINE_DEBUGGABLE const TShaderUniformBufferParameter<UniformBufferStructType>& GetUniformBufferParameter() const
|
|
|
|
|
{
|
|
|
|
|
const FShaderUniformBufferParameter& FoundParameter = GetUniformBufferParameter(UniformBufferStructType::FTypeInfo::GetStructMetadata());
|
|
|
|
|
return static_cast<const TShaderUniformBufferParameter<UniformBufferStructType>&>(FoundParameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FORCEINLINE_DEBUGGABLE const FShaderUniformBufferParameter& GetUniformBufferParameter(const FShaderParametersMetadata* SearchStruct) const
|
|
|
|
|
{
|
|
|
|
|
const FHashedName SearchName = SearchStruct->GetShaderVariableHashedName();
|
|
|
|
|
|
|
|
|
|
return GetUniformBufferParameter(SearchName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FORCEINLINE_DEBUGGABLE const FShaderUniformBufferParameter& GetUniformBufferParameter(const FHashedName SearchName) const
|
|
|
|
|
{
|
|
|
|
|
int32 FoundIndex = INDEX_NONE;
|
|
|
|
|
TArrayView<const FHashedName> UniformBufferParameterStructsView(UniformBufferParameterStructs);
|
|
|
|
|
for (int32 StructIndex = 0, Count = UniformBufferParameterStructsView.Num(); StructIndex < Count; StructIndex++)
|
|
|
|
|
{
|
|
|
|
|
if (UniformBufferParameterStructsView[StructIndex] == SearchName)
|
|
|
|
|
{
|
|
|
|
|
FoundIndex = StructIndex;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FoundIndex != INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
const FShaderUniformBufferParameter& FoundParameter = UniformBufferParameters[FoundIndex];
|
|
|
|
|
return FoundParameter;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// This can happen if the uniform buffer was not bound
|
|
|
|
|
// There's no good way to distinguish not being bound due to temporary debugging / compiler optimizations or an actual code bug,
|
|
|
|
|
// Hence failing silently instead of an error message
|
|
|
|
|
static FShaderUniformBufferParameter UnboundParameter;
|
|
|
|
|
return UnboundParameter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RENDERCORE_API const FShaderParametersMetadata* FindAutomaticallyBoundUniformBufferStruct(int32 BaseIndex) const;
|
|
|
|
|
|
|
|
|
|
RENDERCORE_API void DumpDebugInfo(const FShaderMapPointerTable& InPtrTable);
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
RENDERCORE_API void SaveShaderStableKeys(const FShaderMapPointerTable& InPtrTable, EShaderPlatform TargetShaderPlatform, int32 PermutationId, const struct FStableShaderKeyAndValue& SaveKeyVal);
|
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
|
|
|
|
|
|
/** Returns the meta data for the root shader parameter struct. */
|
|
|
|
|
static inline const FShaderParametersMetadata* GetRootParametersMetadata()
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
RENDERCORE_API void BuildParameterMapInfo(const TMap<FString, FParameterAllocation>& ParameterMap);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// 着色器参数绑定.
|
|
|
|
|
LAYOUT_FIELD(FShaderParameterBindings, Bindings);
|
|
|
|
|
// 着色器参数绑定的映射信息.
|
|
|
|
|
LAYOUT_FIELD(FShaderParameterMapInfo, ParameterMapInfo);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
LAYOUT_FIELD(TMemoryImageArray<FHashedName>, UniformBufferParameterStructs);
|
|
|
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderUniformBufferParameter>, UniformBufferParameters);
|
|
|
|
|
|
|
|
|
|
// 下面3个是编辑器参数.
|
|
|
|
|
// 着色器的编译输出和结果参数映射的哈希值, 用于查找匹配的资源.
|
|
|
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, OutputHash);
|
|
|
|
|
// 顶点工厂资源哈希值
|
|
|
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, VFSourceHash);
|
|
|
|
|
// Shader资源哈希值.
|
|
|
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, SourceHash);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 着色器类型.
|
|
|
|
|
LAYOUT_FIELD(TIndexedPtr<FShaderType>, Type);
|
|
|
|
|
// 顶点工厂类型.
|
|
|
|
|
LAYOUT_FIELD(TIndexedPtr<FVertexFactoryType>, VFType);
|
2024-02-06 13:07:47 +08:00
|
|
|
|
// 目标平台和着色频率(frequency).
|
2024-02-06 10:30:09 +08:00
|
|
|
|
LAYOUT_FIELD(FShaderTarget, Target);
|
2024-02-06 13:07:47 +08:00
|
|
|
|
// 在FShaderMapResource的shader索引.
|
2024-02-06 10:30:09 +08:00
|
|
|
|
LAYOUT_FIELD(int32, ResourceIndex);
|
2024-02-06 13:07:47 +08:00
|
|
|
|
// shader指令数.
|
2024-02-06 10:30:09 +08:00
|
|
|
|
LAYOUT_FIELD(uint32, NumInstructions);
|
|
|
|
|
/** Truncated version of OutputHash, intended for sorting. Not suitable for unique shader identification. */
|
|
|
|
|
LAYOUT_FIELD(uint32, SortKey);
|
2024-02-06 13:07:47 +08:00
|
|
|
|
// 纹理采样器数量.
|
2024-02-06 10:30:09 +08:00
|
|
|
|
LAYOUT_FIELD_EDITORONLY(uint32, NumTextureSamplers);
|
2024-02-06 13:07:47 +08:00
|
|
|
|
// shader代码尺寸.
|
2024-02-06 10:30:09 +08:00
|
|
|
|
LAYOUT_FIELD_EDITORONLY(uint32, CodeSize);
|
|
|
|
|
};
|
2024-02-06 13:07:47 +08:00
|
|
|
|
```
|
|
|
|
|
以上可知,FShader存储着Shader关联的绑定参数、顶点工厂、编译后的各类资源等数据,并提供了编译器修改和检测接口,还有各类数据获取接口。
|
|
|
|
|
|
|
|
|
|
FShader实际上是个基础父类,它的子类有:
|
|
|
|
|
- **FGlobalShader**:全局着色器,它的子类在内存中只有唯一的实例,常用于屏幕方块绘制、后处理等。相比父类FShader,增加了SetParameters设置视图统一缓冲的接口。FGlobalShader包含了后处理、光照、工具类、可视化、地形、虚拟纹理等方面的Shader代码,可以是VS、PS、CS,但CS必然是FGlobalShader的子类
|
|
|
|
|
- **FMaterialShader**:材质着色器,由FMaterialShaderType指定的材质引用的着色器,是材质蓝图在实例化后的一个shader子集。FMaterialShader主要包含了模型、专用Pass、体素化等方面的Shader代码,可以是VS、PS、GS等,但不会有CS。
|
|
|
|
|
|
|
|
|
|
## Shader Parameter
|
|
|
|
|
位于`Engine\Source\Runtime\RenderCore\Public\ShaderParameters.h`。
|
|
|
|
|
- FShaderParameter:着色器的寄存器绑定参数, 它的类型可以是float1/2/3/4,数组等。
|
|
|
|
|
- FShaderResourceParameter:着色器资源绑定(纹理或采样器)。
|
|
|
|
|
- FRWShaderParameter:绑定了UAV或SRV资源的类型。
|
|
|
|
|
- FShaderUniformBufferParameter:着色器统一缓冲参数。
|
|
|
|
|
|
|
|
|
|
## Uniform Buffer
|
|
|
|
|
位于`Engine\Source\Runtime\RHI\Public\RHIResources.h`。
|
|
|
|
|
UE的Uniform Buffer涉及了几个核心的概念,最底层的是RHI层的FRHIUniformBuffer,封装了各种图形API的统一缓冲区(也叫Constant Buffer)。
|
|
|
|
|
```c++
|
|
|
|
|
class FRHIUniformBuffer : public FRHIResource
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
// 构造函数.
|
|
|
|
|
FRHIUniformBuffer(const FRHIUniformBufferLayout& InLayout);
|
|
|
|
|
|
|
|
|
|
// 引用计数操作.
|
|
|
|
|
uint32 AddRef() const;
|
|
|
|
|
uint32 Release() const;
|
|
|
|
|
|
|
|
|
|
// 数据获取接口.
|
|
|
|
|
uint32 GetSize() const;
|
|
|
|
|
const FRHIUniformBufferLayout& GetLayout() const;
|
|
|
|
|
bool IsGlobal() const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// RHI Uniform Buffer的布局.
|
|
|
|
|
const FRHIUniformBufferLayout* Layout;
|
|
|
|
|
// 缓冲区尺寸.
|
|
|
|
|
uint32 LayoutConstantBufferSize;
|
|
|
|
|
};
|
2024-02-06 10:30:09 +08:00
|
|
|
|
```
|