196 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 剖析虚幻渲染体系08- Shader体系
date: 2024-02-04 21:44:10
excerpt:
tags:
rating: ⭐
---
# 前言
原文地址: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);
// 目标平台和着色频率(frequency).
LAYOUT_FIELD(FShaderTarget, Target);
// 在FShaderMapResource的shader索引.
LAYOUT_FIELD(int32, ResourceIndex);
// shader指令数.
LAYOUT_FIELD(uint32, NumInstructions);
/** Truncated version of OutputHash, intended for sorting. Not suitable for unique shader identification. */
LAYOUT_FIELD(uint32, SortKey);
// 纹理采样器数量.
LAYOUT_FIELD_EDITORONLY(uint32, NumTextureSamplers);
// shader代码尺寸.
LAYOUT_FIELD_EDITORONLY(uint32, CodeSize);
};
```
以上可知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;
};
```