--- 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& OutError) { return true; } // 取得RayTracingPayloadType static ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId) { return static_cast(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 FORCEINLINE_DEBUGGABLE const TShaderUniformBufferParameter& GetUniformBufferParameter() const { const FShaderUniformBufferParameter& FoundParameter = GetUniformBufferParameter(UniformBufferStructType::FTypeInfo::GetStructMetadata()); return static_cast&>(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 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& ParameterMap); public: // 着色器参数绑定. LAYOUT_FIELD(FShaderParameterBindings, Bindings); // 着色器参数绑定的映射信息. LAYOUT_FIELD(FShaderParameterMapInfo, ParameterMapInfo); protected: LAYOUT_FIELD(TMemoryImageArray, UniformBufferParameterStructs); LAYOUT_FIELD(TMemoryImageArray, UniformBufferParameters); // 下面3个是编辑器参数. // 着色器的编译输出和结果参数映射的哈希值, 用于查找匹配的资源. LAYOUT_FIELD_EDITORONLY(FSHAHash, OutputHash); // 顶点工厂资源哈希值 LAYOUT_FIELD_EDITORONLY(FSHAHash, VFSourceHash); // Shader资源哈希值. LAYOUT_FIELD_EDITORONLY(FSHAHash, SourceHash); private: // 着色器类型. LAYOUT_FIELD(TIndexedPtr, Type); // 顶点工厂类型. LAYOUT_FIELD(TIndexedPtr, 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; }; ```