2704 lines
104 KiB
C++
2704 lines
104 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
Shader.h: Shader definitions.
|
|
=============================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "Algo/BinarySearch.h"
|
|
#include "Containers/Array.h"
|
|
#include "Containers/ArrayView.h"
|
|
#include "Containers/ContainersFwd.h"
|
|
#include "Containers/EnumAsByte.h"
|
|
#include "Containers/HashTable.h"
|
|
#include "Containers/List.h"
|
|
#include "Containers/Map.h"
|
|
#include "Containers/Set.h"
|
|
#include "Containers/StringFwd.h"
|
|
#include "Containers/UnrealString.h"
|
|
#include "CoreMinimal.h"
|
|
#include "CoreTypes.h"
|
|
#include "HAL/CriticalSection.h"
|
|
#include "HAL/PlatformCrt.h"
|
|
#include "HAL/ThreadSafeBool.h"
|
|
#include "HAL/UnrealMemory.h"
|
|
#include "Math/NumericLimits.h"
|
|
#include "Misc/AssertionMacros.h"
|
|
#include "Misc/CString.h"
|
|
#include "Misc/EnumClassFlags.h"
|
|
#include "Misc/ScopeLock.h"
|
|
#include "Misc/SecureHash.h"
|
|
#include "RHI.h"
|
|
#include "RHIDefinitions.h"
|
|
#include "RHIMemoryLayout.h"
|
|
#include "RenderResource.h"
|
|
#include "RenderDeferredCleanup.h"
|
|
#include "Serialization/Archive.h"
|
|
#include "Serialization/ArchiveProxy.h"
|
|
#include "Serialization/MemoryImage.h"
|
|
#include "Serialization/MemoryLayout.h"
|
|
#include "ShaderCore.h"
|
|
#include "ShaderParameterMetadata.h"
|
|
#include "ShaderParameters.h"
|
|
#include "ShaderPermutation.h"
|
|
#include "ShaderPermutationUtils.h"
|
|
#include "Templates/RefCounting.h"
|
|
#include "Templates/TypeHash.h"
|
|
#include "Templates/UniquePtr.h"
|
|
#include "Templates/UnrealTemplate.h"
|
|
#include "Templates/UnrealTypeTraits.h"
|
|
#include "UObject/NameTypes.h"
|
|
#include "UObject/RenderingObjectVersion.h"
|
|
|
|
#include <atomic>
|
|
|
|
// For FShaderUniformBufferParameter
|
|
|
|
#if WITH_EDITOR
|
|
#include "UObject/DebugSerializationFlags.h"
|
|
#endif
|
|
|
|
class ITargetPlatform;
|
|
class FCbFieldView;
|
|
class FCbWriter;
|
|
class FComputeKernelShaderType;
|
|
class FNNERuntimeIREEShaderType;
|
|
class FGlobalShaderType;
|
|
class FMaterialShaderType;
|
|
class FMemoryImageWriter;
|
|
class FMemoryUnfreezeContent;
|
|
class FMeshMaterialShaderType;
|
|
class FNiagaraShaderType;
|
|
class FOpenColorIOShaderType;
|
|
class FRHIComputeCommandList;
|
|
class FShader;
|
|
class FShaderKeyGenerator;
|
|
class FShaderMapBase;
|
|
class FShaderMapPointerTable;
|
|
class FShaderParametersMetadata;
|
|
class FShaderPipelineType;
|
|
class FShaderType;
|
|
class FVertexFactoryType;
|
|
class FRHIShaderBindingLayout;
|
|
struct FShaderCompiledShaderInitializerType;
|
|
struct FShaderCompileJobKey;
|
|
struct FShaderCompilerOutput;
|
|
struct FShaderSerializeContext;
|
|
using FShaderMapAssetPaths = TSet<FName>; // Copied from ShaderCodeLibrary.h
|
|
|
|
/** Define a shader permutation uniquely according to its type, and permutation id.*/
|
|
template<typename MetaShaderType>
|
|
struct TShaderTypePermutation
|
|
{
|
|
MetaShaderType* const Type;
|
|
const int32 PermutationId;
|
|
|
|
TShaderTypePermutation(MetaShaderType* InType, int32 InPermutationId)
|
|
: Type(InType)
|
|
, PermutationId(InPermutationId)
|
|
{
|
|
}
|
|
|
|
FORCEINLINE bool operator==(const TShaderTypePermutation& Other)const
|
|
{
|
|
return Type == Other.Type && PermutationId == Other.PermutationId;
|
|
}
|
|
|
|
FORCEINLINE bool operator!=(const TShaderTypePermutation& Other)const
|
|
{
|
|
return !(*this == Other);
|
|
}
|
|
|
|
friend FORCEINLINE uint32 GetTypeHash(const TShaderTypePermutation& Var)
|
|
{
|
|
return HashCombine(GetTypeHash(Var.Type), (uint32)Var.PermutationId);
|
|
}
|
|
};
|
|
|
|
using FShaderPermutation = TShaderTypePermutation<FShaderType>;
|
|
|
|
inline const int32 kUniqueShaderPermutationId = 0;
|
|
|
|
/** Used to compare order shader types permutation deterministically. */
|
|
template<typename MetaShaderType>
|
|
class TCompareShaderTypePermutation
|
|
{
|
|
public:
|
|
FORCEINLINE bool operator()(const TShaderTypePermutation<MetaShaderType>& A, const TShaderTypePermutation<MetaShaderType>& B) const
|
|
{
|
|
int32 AL = FCString::Strlen(A.Type->GetName());
|
|
int32 BL = FCString::Strlen(B.Type->GetName());
|
|
if (AL == BL)
|
|
{
|
|
int32 StrCmp = FCString::Strncmp(A.Type->GetName(), B.Type->GetName(), AL);
|
|
if (StrCmp != 0)
|
|
{
|
|
return StrCmp > 0;
|
|
}
|
|
return A.PermutationId > B.PermutationId;
|
|
}
|
|
return AL > BL;
|
|
}
|
|
};
|
|
|
|
class FShaderUniformBufferParameterInfo
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderUniformBufferParameterInfo, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
LAYOUT_FIELD(uint16, BaseIndex);
|
|
|
|
FShaderUniformBufferParameterInfo() = default;
|
|
|
|
FShaderUniformBufferParameterInfo(uint16 InBaseIndex)
|
|
{
|
|
BaseIndex = InBaseIndex;
|
|
checkf(BaseIndex == InBaseIndex, TEXT("Tweak FShaderUniformBufferParameterInfo type sizes"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FShaderUniformBufferParameterInfo& Info)
|
|
{
|
|
Ar << Info.BaseIndex;
|
|
return Ar;
|
|
}
|
|
|
|
inline bool operator==(const FShaderUniformBufferParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex == Rhs.BaseIndex;
|
|
}
|
|
|
|
inline bool operator<(const FShaderUniformBufferParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex < Rhs.BaseIndex;
|
|
}
|
|
};
|
|
|
|
class FShaderResourceParameterInfo
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderResourceParameterInfo, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
LAYOUT_FIELD(uint16, BaseIndex);
|
|
LAYOUT_FIELD(uint8, BufferIndex);
|
|
LAYOUT_FIELD(EShaderParameterType, Type);
|
|
|
|
FShaderResourceParameterInfo() = default;
|
|
|
|
FShaderResourceParameterInfo(uint16 InBaseIndex, uint8 InBufferIndex, EShaderParameterType InType)
|
|
{
|
|
BaseIndex = InBaseIndex;
|
|
BufferIndex = InBufferIndex;
|
|
Type = InType;
|
|
checkf(BaseIndex == InBaseIndex && BufferIndex == InBufferIndex && Type == InType, TEXT("Tweak FShaderResourceParameterInfo type sizes"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FShaderResourceParameterInfo& Info)
|
|
{
|
|
Ar << Info.BaseIndex;
|
|
Ar << Info.BufferIndex;
|
|
Ar << Info.Type;
|
|
return Ar;
|
|
}
|
|
|
|
inline bool operator==(const FShaderResourceParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex == Rhs.BaseIndex
|
|
&& BufferIndex == Rhs.BufferIndex
|
|
&& Type == Rhs.Type;
|
|
}
|
|
|
|
inline bool operator<(const FShaderResourceParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex < Rhs.BaseIndex;
|
|
}
|
|
};
|
|
|
|
class FShaderLooseParameterInfo
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderLooseParameterInfo, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
LAYOUT_FIELD(uint16, BaseIndex);
|
|
LAYOUT_FIELD(uint16, Size);
|
|
|
|
FShaderLooseParameterInfo() = default;
|
|
|
|
FShaderLooseParameterInfo(uint16 InBaseIndex, uint16 InSize)
|
|
{
|
|
BaseIndex = InBaseIndex;
|
|
Size = InSize;
|
|
checkf(BaseIndex == InBaseIndex && Size == InSize, TEXT("Tweak FShaderLooseParameterInfo type sizes"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FShaderLooseParameterInfo& Info)
|
|
{
|
|
Ar << Info.BaseIndex;
|
|
Ar << Info.Size;
|
|
return Ar;
|
|
}
|
|
|
|
inline bool operator==(const FShaderLooseParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex == Rhs.BaseIndex
|
|
&& Size == Rhs.Size;
|
|
}
|
|
|
|
inline bool operator<(const FShaderLooseParameterInfo& Rhs) const
|
|
{
|
|
return BaseIndex < Rhs.BaseIndex;
|
|
}
|
|
};
|
|
|
|
class FShaderLooseParameterBufferInfo
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderLooseParameterBufferInfo, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
LAYOUT_FIELD(uint16, BaseIndex);
|
|
LAYOUT_FIELD(uint16, Size);
|
|
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderLooseParameterInfo>, Parameters);
|
|
|
|
FShaderLooseParameterBufferInfo() {}
|
|
|
|
FShaderLooseParameterBufferInfo(uint16 InBufferIndex, uint16 InBufferSize)
|
|
{
|
|
BaseIndex = InBufferIndex;
|
|
Size = InBufferSize;
|
|
checkf(BaseIndex == InBufferIndex, TEXT("Tweak FShaderLooseParameterBufferInfo type sizes"));
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar,FShaderLooseParameterBufferInfo& Info)
|
|
{
|
|
Ar << Info.BaseIndex;
|
|
Ar << Info.Size;
|
|
Ar << Info.Parameters;
|
|
return Ar;
|
|
}
|
|
|
|
inline bool operator==(const FShaderLooseParameterBufferInfo& Rhs) const
|
|
{
|
|
return BaseIndex == Rhs.BaseIndex
|
|
&& Size == Rhs.Size
|
|
&& Parameters == Rhs.Parameters;
|
|
}
|
|
|
|
inline bool operator<(const FShaderLooseParameterBufferInfo& Rhs) const
|
|
{
|
|
return BaseIndex < Rhs.BaseIndex;
|
|
}
|
|
};
|
|
|
|
class FShaderParameterMapInfo
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderParameterMapInfo, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderUniformBufferParameterInfo>, UniformBuffers);
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderResourceParameterInfo>, TextureSamplers);
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderResourceParameterInfo>, SRVs);
|
|
LAYOUT_FIELD(TMemoryImageArray<FShaderLooseParameterBufferInfo>, LooseParameterBuffers);
|
|
LAYOUT_FIELD(uint64, Hash);
|
|
|
|
friend FArchive& operator<<(FArchive& Ar,FShaderParameterMapInfo& Info)
|
|
{
|
|
Ar << Info.UniformBuffers;
|
|
Ar << Info.TextureSamplers;
|
|
Ar << Info.SRVs;
|
|
Ar << Info.LooseParameterBuffers;
|
|
Ar << Info.Hash;
|
|
return Ar;
|
|
}
|
|
|
|
inline bool operator==(const FShaderParameterMapInfo& Rhs) const
|
|
{
|
|
return Hash == Rhs.Hash;
|
|
}
|
|
};
|
|
|
|
enum class ERayTracingPayloadType : uint32; // actual enum is defined in /Shaders/Shared/RayTracingPayloadType.h
|
|
typedef uint32(*TRaytracingPayloadSizeFunction)();
|
|
ENUM_CLASS_FLAGS(ERayTracingPayloadType);
|
|
|
|
RENDERCORE_API uint32 GetRayTracingPayloadTypeMaxSize(ERayTracingPayloadType PayloadType);
|
|
RENDERCORE_API void RegisterRayTracingPayloadType(ERayTracingPayloadType PayloadType, uint32 PayloadSize, TRaytracingPayloadSizeFunction PayloadSizeFunction);
|
|
|
|
struct FRegisterRayTracingPayloadTypeHelper
|
|
{
|
|
FRegisterRayTracingPayloadTypeHelper(ERayTracingPayloadType PayloadType, uint32 PayloadSize, TRaytracingPayloadSizeFunction PayloadSizeFunction)
|
|
{
|
|
RegisterRayTracingPayloadType(PayloadType, PayloadSize, PayloadSizeFunction);
|
|
}
|
|
};
|
|
|
|
#define IMPLEMENT_RT_PAYLOAD_TYPE_CONCAT2( x, y ) x##y
|
|
#define IMPLEMENT_RT_PAYLOAD_TYPE_CONCAT( x, y ) IMPLEMENT_RT_PAYLOAD_TYPE_CONCAT2( x, y )
|
|
#define IMPLEMENT_RT_PAYLOAD_TYPE(PayloadType, PayloadSize) static FRegisterRayTracingPayloadTypeHelper IMPLEMENT_RT_PAYLOAD_TYPE_CONCAT(PayloadHelper, __COUNTER__) = FRegisterRayTracingPayloadTypeHelper(PayloadType, PayloadSize, nullptr);
|
|
#define IMPLEMENT_RT_PAYLOAD_TYPE_FUNCTION(PayloadType, PayloadSizeFunction) static FRegisterRayTracingPayloadTypeHelper IMPLEMENT_RT_PAYLOAD_TYPE_CONCAT(PayloadHelper, __COUNTER__) = FRegisterRayTracingPayloadTypeHelper(PayloadType, 0u, PayloadSizeFunction);
|
|
|
|
class FShaderMapResource : public FRenderResource, public FDeferredCleanupInterface
|
|
{
|
|
public:
|
|
static RENDERCORE_API bool ArePlatformsCompatible(EShaderPlatform CurrentPlatform, EShaderPlatform TargetPlatform);
|
|
|
|
EShaderPlatform GetPlatform() const { return Platform; }
|
|
|
|
RENDERCORE_API void AddRef();
|
|
RENDERCORE_API void Release();
|
|
inline int32 GetNumRefs() const { return NumRefs.load(std::memory_order_relaxed); }
|
|
|
|
// FRenderResource interface.
|
|
RENDERCORE_API virtual void ReleaseRHI() override;
|
|
|
|
inline int32 GetNumShaders() const
|
|
{
|
|
return NumRHIShaders;
|
|
}
|
|
|
|
inline bool IsValidShaderIndex(int32 ShaderIndex) const
|
|
{
|
|
return static_cast<uint32>(ShaderIndex) < NumRHIShaders;
|
|
}
|
|
|
|
inline bool HasShader(int32 ShaderIndex) const
|
|
{
|
|
return RHIShaders[ShaderIndex].load(std::memory_order_acquire) != nullptr;
|
|
}
|
|
|
|
virtual uint32 GetShaderSizeBytes(int32 ShaderIndex) const;
|
|
|
|
virtual void PreloadShader(int32 ShaderIndex, FGraphEventArray& OutCompletionEvents)
|
|
{
|
|
/* no-op when not using shader library */
|
|
};
|
|
|
|
virtual void PreloadShaderMap(FGraphEventArray& OutCompletionEvents)
|
|
{
|
|
/* no-op when not using shader library */
|
|
};
|
|
|
|
virtual int32 GetGroupIndexForShader(int32 ShaderIndex) const
|
|
{
|
|
/* return invalid index when not using shader library */
|
|
return INDEX_NONE;
|
|
};
|
|
|
|
virtual int32 GetLibraryId() const
|
|
{
|
|
/* return invalid index when not using shader library */
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
virtual int32 GetLibraryShaderIndex(int32 ShaderIndex) const
|
|
{
|
|
/* return invalid index when not using shader library */
|
|
return INDEX_NONE;
|
|
}
|
|
|
|
inline bool ContainsAtLeastOneRHIShaderCreated() const
|
|
{
|
|
return bAtLeastOneRHIShaderCreated;
|
|
}
|
|
|
|
inline FRHIShader* GetShader(int32 ShaderIndex, bool bRequired = true)
|
|
{
|
|
// This is a double checked locking. This trickery arises from the fact that we're
|
|
// synchronizing two threads: one that takes a lock and another that doesn't.
|
|
// Without fences, there is a race between storing the shader pointer and accessing it
|
|
// on the other (lockless) thread.
|
|
FRHIShader* Shader = RHIShaders[ShaderIndex].load(std::memory_order_acquire);
|
|
if (UNLIKELY(Shader == nullptr))
|
|
{
|
|
Shader = CreateShaderOrCrash(ShaderIndex, bRequired);
|
|
}
|
|
return Shader;
|
|
}
|
|
|
|
/** Return shader hash for a particular shader without creating it. */
|
|
virtual FSHAHash GetShaderHash(int32 ShaderIndex) = 0;
|
|
|
|
RENDERCORE_API void BeginCreateAllShaders();
|
|
|
|
#if RHI_RAYTRACING
|
|
|
|
UE_DEPRECATED(5.6, "GetRayTracingHitGroupLibrary needs current EShaderPlatform")
|
|
static void GetRayTracingHitGroupLibrary(TArray<FRHIRayTracingShader*>& RayTracingHitGroupShaders, FRHIRayTracingShader* DefaultShader)
|
|
{
|
|
GetRayTracingHitGroupLibrary(GMaxRHIShaderPlatform, RayTracingHitGroupShaders, DefaultShader);
|
|
}
|
|
UE_DEPRECATED(5.6, "GetRayTracingCallableShaderLibrary needs current EShaderPlatform")
|
|
static void GetRayTracingCallableShaderLibrary(TArray<FRHIRayTracingShader*>& RayTracingCallableShaders, FRHIRayTracingShader* DefaultShader)
|
|
{
|
|
GetRayTracingCallableShaderLibrary(GMaxRHIShaderPlatform, RayTracingCallableShaders, DefaultShader);
|
|
}
|
|
UE_DEPRECATED(5.6, "GetRayTracingMissShaderLibrary needs current EShaderPlatform")
|
|
static void GetRayTracingMissShaderLibrary(TArray<FRHIRayTracingShader*>& RayTracingMissShaders, FRHIRayTracingShader* DefaultShader)
|
|
{
|
|
GetRayTracingMissShaderLibrary(GMaxRHIShaderPlatform, RayTracingMissShaders, DefaultShader);
|
|
}
|
|
|
|
static RENDERCORE_API void GetRayTracingHitGroupLibrary(EShaderPlatform ShaderPlatform, TArray<FRHIRayTracingShader*>& RayTracingHitGroupShaders, FRHIRayTracingShader* DefaultShader);
|
|
static RENDERCORE_API void GetRayTracingCallableShaderLibrary(EShaderPlatform ShaderPlatform, TArray<FRHIRayTracingShader*>& RayTracingCallableShaders, FRHIRayTracingShader* DefaultShader);
|
|
static RENDERCORE_API void GetRayTracingMissShaderLibrary(EShaderPlatform ShaderPlatform, TArray<FRHIRayTracingShader*>& RayTracingMissShaders, FRHIRayTracingShader* DefaultShader);
|
|
|
|
inline uint32 GetRayTracingHitGroupLibraryIndex(int32 ShaderIndex)
|
|
{
|
|
FRHIShader* Shader = GetShader(ShaderIndex); // make sure the shader is created
|
|
checkSlow(Shader->GetFrequency() == SF_RayHitGroup);
|
|
return RayTracingLibraryIndices[ShaderIndex];
|
|
}
|
|
|
|
inline uint32 GetRayTracingCallableShaderLibraryIndex(int32 ShaderIndex)
|
|
{
|
|
FRHIShader* Shader = GetShader(ShaderIndex); // make sure the shader is created
|
|
checkSlow(Shader->GetFrequency() == SF_RayCallable);
|
|
return RayTracingLibraryIndices[ShaderIndex];
|
|
}
|
|
|
|
inline uint32 GetRayTracingMissShaderLibraryIndex(int32 ShaderIndex)
|
|
{
|
|
FRHIShader* Shader = GetShader(ShaderIndex); // make sure the shader is created
|
|
checkSlow(Shader->GetFrequency() == SF_RayMiss);
|
|
return RayTracingLibraryIndices[ShaderIndex];
|
|
}
|
|
#endif // RHI_RAYTRACING
|
|
|
|
virtual uint32 GetSizeBytes() const = 0;
|
|
|
|
protected:
|
|
RENDERCORE_API explicit FShaderMapResource(EShaderPlatform InPlatform, int32 NumShaders);
|
|
RENDERCORE_API virtual ~FShaderMapResource();
|
|
|
|
SIZE_T GetAllocatedSize() const
|
|
{
|
|
SIZE_T Size = NumRHIShaders * sizeof(std::atomic<FRHIShader*>);
|
|
#if RHI_RAYTRACING
|
|
Size += RayTracingLibraryIndices.GetAllocatedSize();
|
|
#endif
|
|
return Size;
|
|
}
|
|
|
|
/** Creates RHI shader, with a reference (so the caller can release). Never returns nullptr (inability to create is Fatal) */
|
|
virtual FRHIShader* CreateRHIShaderOrCrash(int32 ShaderIndex, bool bRequired) = 0;
|
|
|
|
/** Signal the shader library that it can release compressed shader code for a shader that it keeps preloaded in memory. */
|
|
virtual void ReleasePreloadedShaderCode(int32 ShaderIndex) { /* no-op when not using shader library */ };
|
|
|
|
virtual bool TryRelease() { return true; }
|
|
|
|
RENDERCORE_API void ReleaseShaders();
|
|
|
|
private:
|
|
|
|
/** Creates an entry in RHIShaders array and registers it among the raytracing libs if needed. Created shader is returned. */
|
|
RENDERCORE_API FRHIShader* CreateShaderOrCrash(int32 ShaderIndex, bool bRequired);
|
|
|
|
/** This lock is to prevent two threads creating the same RHIShaders element. It is only taken if the element is to be created. */
|
|
FCriticalSection RHIShadersCreationGuard;
|
|
|
|
#if RHI_RAYTRACING
|
|
TArray<uint32> RayTracingLibraryIndices;
|
|
#endif // RHI_RAYTRACING
|
|
|
|
/** An array of shader pointers (refcount is managed manually). */
|
|
TUniquePtr<std::atomic<FRHIShader*>[]> RHIShaders;
|
|
|
|
/** Since the shaders are no longer a TArray, this is their count (the size of the RHIShaders array). This does not count actually created RHI shaders, just the size of the above array of pointers to them. */
|
|
uint32 NumRHIShaders : 31;
|
|
|
|
/** Whether we have at least one RHI shader created. */
|
|
uint32 bAtLeastOneRHIShaderCreated : 1;
|
|
|
|
EShaderPlatform Platform;
|
|
|
|
/** The number of references to this shader map. */
|
|
std::atomic<int32> NumRefs;
|
|
};
|
|
|
|
class FShaderMapResourceCode : public FThreadSafeRefCountedObject
|
|
{
|
|
public:
|
|
#if WITH_EDITORONLY_DATA
|
|
struct FShaderEditorOnlyDataEntry
|
|
{
|
|
UE_DEPRECATED(5.6, "Use SymbolBuffer")
|
|
TArray<uint8> PlatformDebugData;
|
|
|
|
// Sets the symbols for this entry to the given buffer if either unset or the hash of the new buffer is "less" than the hash of the stored buffer.
|
|
// This is done purely for determinism's sake (we always want to store the same copy of symbols in the editoronly data for any given shader bytecode).
|
|
void ConditionalSetSymbolBuffer(FCompressedBuffer InSymbols);
|
|
|
|
uint64 SymbolHash = 0u; // Used only to ensure the copy of symbols saved is stable for determinism's sake; does not need to be serialized.
|
|
FCompressedBuffer SymbolBuffer;
|
|
|
|
/** This field contains a debug string stored in a ShaderSymbols.info file when using r.Shaders.SymbolInfo=1
|
|
* Used to facilitate reverse lookup of a shader from a platform shader hash when no full shader symbol
|
|
* information is available */
|
|
FString DebugInfo;
|
|
|
|
/** A (deduplicated/sorted) array of all the compiler warnings that were emitted when all shaders resulting
|
|
* in the associated bytecode were compiled (i.e. if multiple shader sources have warnings but compile to
|
|
* the same code, all warnings for each unique source will be reported).
|
|
* Does not contain errors since if there were any errors, this object wouldn't exist. */
|
|
TArray<FString> CompilerWarnings;
|
|
|
|
/** An array of the hash of all FShaderType names which generate this particular shader (i.e. the return value
|
|
* of FShaderType::GetHashedName().GetHash()). */
|
|
TArray<uint64> ShaderTypeHashes;
|
|
|
|
/** Generic, data-driven key/value pairs of statistics. */
|
|
TArray<FGenericShaderStat> ShaderStatistics;
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, FShaderEditorOnlyDataEntry& Entry)
|
|
{
|
|
return Ar << Entry.DebugInfo << Entry.CompilerWarnings << Entry.ShaderTypeHashes << Entry.ShaderStatistics;
|
|
}
|
|
|
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
|
// Explicitly-defaulted copy/move ctors & assignment operators are needed temporarily due to deprecation
|
|
// of PlatformDebugData field. These can be removed once the deprecation window for said field ends.
|
|
FShaderEditorOnlyDataEntry() = default;
|
|
FShaderEditorOnlyDataEntry(FShaderEditorOnlyDataEntry&&) = default;
|
|
FShaderEditorOnlyDataEntry(const FShaderEditorOnlyDataEntry&) = default;
|
|
FShaderEditorOnlyDataEntry& operator=(FShaderEditorOnlyDataEntry&&) = default;
|
|
FShaderEditorOnlyDataEntry& operator=(const FShaderEditorOnlyDataEntry&) = default;
|
|
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
|
};
|
|
#endif // WITH_EDITORONLY_DATA
|
|
|
|
FShaderMapResourceCode() {}
|
|
RENDERCORE_API FShaderMapResourceCode(const FShaderMapResourceCode& Other);
|
|
RENDERCORE_API ~FShaderMapResourceCode();
|
|
|
|
RENDERCORE_API void Finalize();
|
|
|
|
RENDERCORE_API void Serialize(FShaderSerializeContext& Ctx);
|
|
#if WITH_EDITORONLY_DATA
|
|
RENDERCORE_API void NotifyShadersCompiled(FName FormatName);
|
|
#endif // WITH_EDITORONLY_DATA
|
|
|
|
RENDERCORE_API uint32 GetSizeBytes() const;
|
|
|
|
UE_DEPRECATED(5.6, "AddShaderCompilerOutput now accepts an FShaderCompileJobKey instead of DebugName")
|
|
inline void AddShaderCompilerOutput(const FShaderCompilerOutput& Output, const FString& DebugName = FString(), FString DebugInfo = FString()) {}
|
|
|
|
RENDERCORE_API void AddShaderCompilerOutput(const FShaderCompilerOutput& Output, const FShaderCompileJobKey& Key, FString DebugInfo = FString());
|
|
|
|
int32 FindShaderIndex(const FSHAHash& InHash) const;
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
void AddEditorOnlyData(int32 Index, const FString& DebugName, uint64 ShaderTypeHash, FCompressedBuffer InSymbols, TConstArrayView<FShaderCompilerError> InCompilerWarnings, TArray<FGenericShaderStat>&& ShaderStatistics, const FString& DebugInfo = FString());
|
|
void UpdateEditorOnlyData(int32 Index, const FString& DebugName, uint64 ShaderTypeHash, FCompressedBuffer InSymbols, TConstArrayView<FShaderCompilerError> InCompilerWarnings, const FString& DebugInfo);
|
|
|
|
RENDERCORE_API void LogShaderCompilerWarnings();
|
|
#endif
|
|
|
|
RENDERCORE_API void ToString(FStringBuilderBase& OutString) const;
|
|
|
|
/** A hash describing the total contents of *this. Constructed from the contents of ShaderHashes during Finalize. */
|
|
FSHAHash ResourceHash;
|
|
TArray<FSHAHash> ShaderHashes;
|
|
|
|
TArray<FShaderCodeResource> ShaderCodeResources;
|
|
#if WITH_EDITORONLY_DATA
|
|
// Optional array of editor-only data indexed in the same order as ShaderEntries (sorted by the shader hash)
|
|
// Empty in the cases where the editor-only data is not serialized.
|
|
TArray<FShaderEditorOnlyDataEntry> ShaderEditorOnlyDataEntries;
|
|
|
|
private:
|
|
// Given an existing shader entry and a new set of shader statistics determine if the shader stats match.
|
|
// This is to prevent non-determinism issues.
|
|
void ValidateShaderStatisticsEditorOnlyData(int32 Index, const TArray<FGenericShaderStat>& ShaderStatistics);
|
|
#endif // WITH_EDITORONLY_DATA
|
|
};
|
|
|
|
class FShaderMapResource_InlineCode : public FShaderMapResource
|
|
{
|
|
public:
|
|
FShaderMapResource_InlineCode(EShaderPlatform InPlatform, FShaderMapResourceCode* InCode)
|
|
: FShaderMapResource(InPlatform, InCode->ShaderCodeResources.Num())
|
|
, Code(InCode)
|
|
{}
|
|
|
|
// FShaderMapResource interface
|
|
RENDERCORE_API virtual FSHAHash GetShaderHash(int32 ShaderIndex) override;
|
|
RENDERCORE_API virtual FRHIShader* CreateRHIShaderOrCrash(int32 ShaderIndex, bool bRequired) override;
|
|
virtual FString GetFriendlyName() const override { return TEXT("InlineCode"); }
|
|
virtual uint32 GetSizeBytes() const override;
|
|
|
|
virtual uint32 GetShaderSizeBytes(int32 ShaderIndex) const override;
|
|
|
|
TRefCountPtr<FShaderMapResourceCode> Code;
|
|
};
|
|
|
|
class FShaderMapPointerTable : public FPointerTableBase
|
|
{
|
|
public:
|
|
RENDERCORE_API virtual int32 AddIndexedPointer(const FTypeLayoutDesc& TypeDesc, void* Ptr) override;
|
|
RENDERCORE_API virtual void* GetIndexedPointer(const FTypeLayoutDesc& TypeDesc, uint32 i) const override;
|
|
|
|
virtual FShaderMapPointerTable* Clone() const { return new FShaderMapPointerTable(*this); }
|
|
|
|
RENDERCORE_API virtual void SaveToArchive(FArchive& Ar, const FPlatformTypeLayoutParameters& LayoutParams, const void* FrozenObject) const override;
|
|
RENDERCORE_API virtual bool LoadFromArchive(FArchive& Ar, const FPlatformTypeLayoutParameters& LayoutParams, void* FrozenObject) override;
|
|
|
|
TPtrTable<FShaderType> ShaderTypes;
|
|
TPtrTable<FVertexFactoryType> VFTypes;
|
|
};
|
|
|
|
/** Encapsulates information about a shader's serialization behavior, used to detect when C++ serialization changes to auto-recompile. */
|
|
|
|
class FShaderKey
|
|
{
|
|
public:
|
|
inline FShaderKey(const FSHAHash& InMaterialShaderMapHash, const FShaderPipelineType* InShaderPipeline, FVertexFactoryType* InVertexFactoryType, int32 PermutationId, EShaderPlatform InPlatform)
|
|
: VertexFactoryType(InVertexFactoryType)
|
|
, ShaderPipeline(InShaderPipeline)
|
|
, MaterialShaderMapHash(InMaterialShaderMapHash)
|
|
, PermutationId(PermutationId)
|
|
, Platform(InPlatform)
|
|
{}
|
|
|
|
friend inline uint32 GetTypeHash(const FShaderKey& Id)
|
|
{
|
|
return
|
|
HashCombine(
|
|
HashCombine(*(uint32*)&Id.MaterialShaderMapHash, GetTypeHash(Id.Platform)),
|
|
HashCombine(GetTypeHash(Id.VertexFactoryType), uint32(Id.PermutationId)));
|
|
}
|
|
|
|
friend bool operator==(const FShaderKey& X, const FShaderKey& Y)
|
|
{
|
|
return X.MaterialShaderMapHash == Y.MaterialShaderMapHash
|
|
&& X.ShaderPipeline == Y.ShaderPipeline
|
|
&& X.VertexFactoryType == Y.VertexFactoryType
|
|
&& X.PermutationId == Y.PermutationId
|
|
&& X.Platform == Y.Platform;
|
|
}
|
|
|
|
RENDERCORE_API friend FArchive& operator<<(FArchive& Ar, FShaderKey& Ref);
|
|
|
|
FVertexFactoryType* VertexFactoryType;
|
|
const FShaderPipelineType* ShaderPipeline;
|
|
FSHAHash MaterialShaderMapHash;
|
|
int32 PermutationId;
|
|
uint32 Platform : SP_NumBits;
|
|
};
|
|
|
|
/**
|
|
* Uniquely identifies an FShader instance.
|
|
* Used to link FMaterialShaderMaps and FShaders on load.
|
|
*/
|
|
class FShaderId
|
|
{
|
|
public:
|
|
inline FShaderId() {}
|
|
inline FShaderId(const FShaderType* InType, const FSHAHash& InMaterialShaderMapHash, const FHashedName& InShaderPipeline, const FVertexFactoryType* InVertexFactoryType, int32 InPermutationId, EShaderPlatform InPlatform)
|
|
: Type(InType)
|
|
, VFType(InVertexFactoryType)
|
|
, ShaderPipelineName(InShaderPipeline)
|
|
, MaterialShaderMapHash(InMaterialShaderMapHash)
|
|
, PermutationId(InPermutationId)
|
|
, Platform(InPlatform)
|
|
{}
|
|
|
|
const FShaderType* Type;
|
|
const FVertexFactoryType* VFType;
|
|
FHashedName ShaderPipelineName;
|
|
FSHAHash MaterialShaderMapHash;
|
|
int32 PermutationId;
|
|
uint32 Platform : SP_NumBits;
|
|
|
|
friend inline uint32 GetTypeHash( const FShaderId& Id )
|
|
{
|
|
return HashCombine(
|
|
GetTypeHash(Id.Type),
|
|
HashCombine(GetTypeHash(Id.VFType),
|
|
HashCombine(GetTypeHash(Id.ShaderPipelineName),
|
|
HashCombine(GetTypeHash(Id.MaterialShaderMapHash),
|
|
HashCombine(GetTypeHash(Id.PermutationId), GetTypeHash(Id.Platform))))));
|
|
}
|
|
|
|
friend bool operator==(const FShaderId& X, const FShaderId& Y)
|
|
{
|
|
return X.Type == Y.Type
|
|
&& X.MaterialShaderMapHash == Y.MaterialShaderMapHash
|
|
&& X.ShaderPipelineName == Y.ShaderPipelineName
|
|
&& X.VFType == Y.VFType
|
|
&& X.PermutationId == Y.PermutationId
|
|
&& X.Platform == Y.Platform;
|
|
}
|
|
|
|
friend bool operator!=(const FShaderId& X, const FShaderId& Y)
|
|
{
|
|
return !(X == Y);
|
|
}
|
|
};
|
|
|
|
class FMaterial;
|
|
|
|
/**
|
|
* Stores all shader parameter bindings and their corresponding offset and size in the shader's parameters struct.
|
|
*/
|
|
class FShaderParameterBindings
|
|
{
|
|
public:
|
|
struct FParameter
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FParameter, NonVirtual);
|
|
|
|
LAYOUT_FIELD(uint16, BufferIndex);
|
|
LAYOUT_FIELD(uint16, BaseIndex);
|
|
LAYOUT_FIELD(uint16, ByteOffset);
|
|
LAYOUT_FIELD(uint16, ByteSize);
|
|
};
|
|
|
|
struct FResourceParameter
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FResourceParameter, NonVirtual);
|
|
LAYOUT_FIELD(uint16, ByteOffset);
|
|
LAYOUT_FIELD(uint8, BaseIndex);
|
|
LAYOUT_FIELD(EUniformBufferBaseType, BaseType);
|
|
};
|
|
|
|
struct FBindlessResourceParameter
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FBindlessResourceParameter, NonVirtual);
|
|
LAYOUT_FIELD(uint16, ByteOffset);
|
|
LAYOUT_FIELD(uint16, GlobalConstantOffset);
|
|
LAYOUT_FIELD(EUniformBufferBaseType, BaseType);
|
|
};
|
|
|
|
struct FParameterStructReference
|
|
{
|
|
DECLARE_INLINE_TYPE_LAYOUT(FParameterStructReference, NonVirtual);
|
|
LAYOUT_FIELD(uint16, BufferIndex);
|
|
LAYOUT_FIELD(uint16, ByteOffset);
|
|
};
|
|
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderParameterBindings, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
static constexpr uint16 kInvalidBufferIndex = 0xFFFF;
|
|
|
|
RENDERCORE_API void BindForLegacyShaderParameters(const FShader* Shader, int32 PermutationId, const FShaderParameterMap& ParameterMaps, const FShaderParametersMetadata& StructMetaData, bool bShouldBindEverything = false);
|
|
RENDERCORE_API void BindForRootShaderParameters(const FShader* Shader, int32 PermutationId, const FShaderParameterMap& ParameterMaps);
|
|
|
|
LAYOUT_FIELD(TMemoryImageArray<FParameter>, Parameters);
|
|
LAYOUT_FIELD(TMemoryImageArray<FResourceParameter>, ResourceParameters);
|
|
LAYOUT_FIELD(TMemoryImageArray<FBindlessResourceParameter>, BindlessResourceParameters);
|
|
LAYOUT_FIELD(TMemoryImageArray<FParameterStructReference>, GraphUniformBuffers);
|
|
LAYOUT_FIELD(TMemoryImageArray<FParameterStructReference>, ParameterReferences);
|
|
|
|
// Hash of the shader parameter structure when doing the binding.
|
|
LAYOUT_FIELD_INITIALIZED(uint32, StructureLayoutHash, 0);
|
|
|
|
// Buffer index of FShaderParametersMetadata::kRootUniformBufferBindingName
|
|
LAYOUT_FIELD_INITIALIZED(uint16, RootParameterBufferIndex, FShaderParameterBindings::kInvalidBufferIndex);
|
|
|
|
}; // FShaderParameterBindings
|
|
|
|
inline int16 GetParameterIndex(const FShaderParameterBindings::FResourceParameter& Parameter) { return Parameter.BaseIndex; }
|
|
inline int16 GetParameterIndex(const FShaderParameterBindings::FBindlessResourceParameter& Parameter) { return Parameter.GlobalConstantOffset; }
|
|
inline int16 GetParameterIndex(const FShaderParameterBindings::FParameterStructReference& Parameter) { return Parameter.BufferIndex; }
|
|
|
|
enum class EShaderPermutationPrecacheRequest : uint8
|
|
{
|
|
Precached, //< Permutation should be precached because it can be used at runtime
|
|
NotPrecached, //< Permutation doesn't have to be precached (debug feature only for example)
|
|
NotUsed, //< Permutation is not used with current cvar/configuration/feature level
|
|
};
|
|
|
|
/** Get the shader permutation flags associated with a platform layout. */
|
|
RENDERCORE_API EShaderPermutationFlags GetShaderPermutationFlags(const FPlatformTypeLayoutParameters& LayoutParams);
|
|
/** Set global additional flags that are always added in GetShaderPermutationFlags(). Expected to be called once at startup. */
|
|
RENDERCORE_API void SetAdditionalShaderPermutationFlags(EShaderPermutationFlags AdditionalFlags);
|
|
|
|
namespace Freeze
|
|
{
|
|
RENDERCORE_API void IntrinsicToString(const TIndexedPtr<FShaderType>& Object, const FTypeLayoutDesc& TypeDesc, const FPlatformTypeLayoutParameters& LayoutParams, FMemoryToStringContext& OutContext);
|
|
RENDERCORE_API void IntrinsicToString(const TIndexedPtr<FVertexFactoryType>& Object, const FTypeLayoutDesc& TypeDesc, const FPlatformTypeLayoutParameters& LayoutParams, FMemoryToStringContext& OutContext);
|
|
}
|
|
|
|
DECLARE_EXPORTED_TEMPLATE_INTRINSIC_TYPE_LAYOUT(template<>, TIndexedPtr<FShaderType>, RENDERCORE_API);
|
|
DECLARE_EXPORTED_TEMPLATE_INTRINSIC_TYPE_LAYOUT(template<>, TIndexedPtr<FVertexFactoryType>, RENDERCORE_API);
|
|
|
|
/** A compiled shader and its parameter bindings. */
|
|
class FShader
|
|
{
|
|
friend class FShaderType;
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShader, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
using FPermutationDomain = FShaderPermutationNone;
|
|
using FPermutationParameters = FShaderPermutationParameters;
|
|
using CompiledShaderInitializerType = FShaderCompiledShaderInitializerType;
|
|
using ShaderMetaType = FShaderType;
|
|
using ShaderStatKeyType = FMemoryImageName;
|
|
using FShaderStatisticMap = TMemoryImageMap<ShaderStatKeyType, FShaderStatVariant>;
|
|
|
|
/**
|
|
* Used to construct a shader for deserialization.
|
|
* This still needs to initialize members to safe values since FShaderType::GenerateSerializationHistory uses this constructor.
|
|
*/
|
|
RENDERCORE_API FShader();
|
|
|
|
/**
|
|
* Construct a shader from shader compiler output.
|
|
*/
|
|
RENDERCORE_API FShader(const CompiledShaderInitializerType& Initializer);
|
|
|
|
RENDERCORE_API ~FShader();
|
|
|
|
/** Can be overridden by FShader subclasses to modify their compile environment just before compilation occurs. */
|
|
static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment&) {}
|
|
|
|
/** Get shader binding layout used by the shader */
|
|
static const FShaderBindingLayout* GetShaderBindingLayout(const FShaderPermutationParameters&) { return nullptr; }
|
|
|
|
/** Can be overridden by FShader subclasses to determine whether a specific permutation should be compiled. */
|
|
static bool ShouldCompilePermutation(const FShaderPermutationParameters&) { return true; }
|
|
|
|
/** Can be overridden by FShader subclasses to determine whether a specific permutation should be precached. */
|
|
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FShaderPermutationParameters& Parameters) { return EShaderPermutationPrecacheRequest::Precached; }
|
|
|
|
/** Can be overridden by FShader subclasses to determine whether compilation is valid. */
|
|
static bool ValidateCompiledResult(EShaderPlatform InPlatform, const FShaderParameterMap& InParameterMap, TArray<FString>& OutError) { return true; }
|
|
|
|
/** Can be overridden by FShader subclasses to set a custom job priority (EShaderCompileJobPriority)
|
|
or EShaderCompileJobPriority::None to ignore custom priority. This can only increase priority. */
|
|
static EShaderCompileJobPriority GetOverrideJobPriority() { return EShaderCompileJobPriority::None; }
|
|
|
|
/** Can be overriden by FShader subclasses to specify which raytracing payload should be used. This method is only called for raytracing shaders. */
|
|
static ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId) { return static_cast<ERayTracingPayloadType>(0); }
|
|
|
|
/** Returns the hash of the shader file that this shader was compiled with. */
|
|
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; }
|
|
|
|
RENDERCORE_API void Finalize(const FShaderMapResourceCode* Code);
|
|
|
|
// Accessors.
|
|
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(); }
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
inline uint32 GetNumInstructions() const { return NumInstructions; }
|
|
inline uint32 GetNumTextureSamplers() const { return NumTextureSamplers; }
|
|
inline uint32 GetCodeSize() const { return CodeSize; }
|
|
inline void SetNumInstructions(uint32 Value) { NumInstructions = Value; }
|
|
#else
|
|
inline uint32 GetNumInstructions() const { return 0u; }
|
|
inline uint32 GetNumTextureSamplers() const { return 0u; }
|
|
inline uint32 GetCodeSize() const { return 0u; }
|
|
inline void SetNumInstructions(uint32 Value) { }
|
|
#endif
|
|
|
|
/** Finds an automatically bound uniform buffer matching the given uniform buffer type if one exists, or returns an unbound parameter. */
|
|
template<typename UniformBufferStructType>
|
|
FORCEINLINE_DEBUGGABLE const TShaderUniformBufferParameter<UniformBufferStructType>& GetUniformBufferParameter() const
|
|
{
|
|
const FShaderUniformBufferParameter& FoundParameter = GetUniformBufferParameter(UniformBufferStructType::FTypeInfo::GetStructMetadata());
|
|
return static_cast<const TShaderUniformBufferParameter<UniformBufferStructType>&>(FoundParameter);
|
|
}
|
|
|
|
/** Finds an automatically bound uniform buffer matching the given uniform buffer struct if one exists, or returns an unbound parameter. */
|
|
FORCEINLINE_DEBUGGABLE const FShaderUniformBufferParameter& GetUniformBufferParameter(const FShaderParametersMetadata* SearchStruct) const
|
|
{
|
|
const FHashedName SearchName = SearchStruct->GetShaderVariableHashedName();
|
|
|
|
return GetUniformBufferParameter(SearchName);
|
|
}
|
|
|
|
/** Finds an automatically bound uniform buffer matching the HashedName if one exists, or returns an unbound parameter. */
|
|
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);
|
|
|
|
/**
|
|
* Hash of the compiled output from this shader and the resulting parameter map.
|
|
* This is used to find a matching resource.
|
|
*/
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, OutputHash);
|
|
|
|
/** Vertex factory source hash, stored so that an FShaderId can be constructed from this shader. */
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, VFSourceHash);
|
|
|
|
/** Hash of this shader's source files generated at compile time, and stored to allow creating an FShaderId. */
|
|
LAYOUT_FIELD_EDITORONLY(FSHAHash, SourceHash);
|
|
|
|
private:
|
|
LAYOUT_FIELD(TIndexedPtr<FShaderType>, Type);
|
|
|
|
LAYOUT_FIELD(TIndexedPtr<FVertexFactoryType>, VFType);
|
|
|
|
/** Target platform and frequency. */
|
|
LAYOUT_FIELD(FShaderTarget, Target);
|
|
|
|
/** Index of this shader within the FShaderMapResource */
|
|
LAYOUT_FIELD(int32, ResourceIndex);
|
|
|
|
/** The number of instructions the shader takes to execute. */
|
|
LAYOUT_FIELD_EDITORONLY(uint32, NumInstructions);
|
|
|
|
/** Truncated version of OutputHash, intended for sorting. Not suitable for unique shader identification. */
|
|
LAYOUT_FIELD(uint32, SortKey);
|
|
|
|
/** Number of texture samplers the shader uses. */
|
|
LAYOUT_FIELD_EDITORONLY(uint32, NumTextureSamplers);
|
|
|
|
/** Size of shader's compiled code */
|
|
LAYOUT_FIELD_EDITORONLY(uint32, CodeSize);
|
|
};
|
|
|
|
RENDERCORE_API const FTypeLayoutDesc& GetTypeLayoutDesc(const FPointerTableBase* PtrTable, const FShader& Shader);
|
|
|
|
template<typename ShaderType, typename PointerTableType>
|
|
class TShaderRefBase
|
|
{
|
|
public:
|
|
TShaderRefBase() : ShaderContent(nullptr), ShaderMap(nullptr) {}
|
|
TShaderRefBase(ShaderType* InShader, const FShaderMapBase& InShaderMap) : ShaderContent(InShader), ShaderMap(&InShaderMap) { checkSlow(InShader); }
|
|
TShaderRefBase(const TShaderRefBase&) = default;
|
|
|
|
template<typename OtherShaderType, typename OtherPointerTableType>
|
|
TShaderRefBase(const TShaderRefBase<OtherShaderType, OtherPointerTableType>& Rhs) : ShaderContent(Rhs.GetShader()), ShaderMap(Rhs.GetShaderMap()) {}
|
|
|
|
TShaderRefBase& operator=(const TShaderRefBase&) = default;
|
|
|
|
template<typename OtherShaderType, typename OtherPointerTableType>
|
|
TShaderRefBase& operator=(const TShaderRefBase<OtherShaderType, OtherPointerTableType>& Rhs)
|
|
{
|
|
ShaderContent = Rhs.GetShader();
|
|
ShaderMap = Rhs.GetShaderMap();
|
|
return *this;
|
|
}
|
|
|
|
template<typename OtherShaderType, typename OtherPointerTableType>
|
|
static TShaderRefBase<ShaderType, PointerTableType> Cast(const TShaderRefBase<OtherShaderType, OtherPointerTableType>& Rhs)
|
|
{
|
|
return TShaderRefBase<ShaderType, PointerTableType>(static_cast<ShaderType*>(Rhs.GetShader()), Rhs.GetShaderMap());
|
|
}
|
|
|
|
template<typename OtherShaderType, typename OtherPointerTableType>
|
|
static TShaderRefBase<ShaderType, PointerTableType> ReinterpretCast(const TShaderRefBase<OtherShaderType, OtherPointerTableType>& Rhs)
|
|
{
|
|
return TShaderRefBase<ShaderType, PointerTableType>(reinterpret_cast<ShaderType*>(Rhs.GetShader()), Rhs.GetShaderMap());
|
|
}
|
|
|
|
inline bool IsValid() const { return ShaderContent != nullptr; }
|
|
inline bool IsNull() const { return ShaderContent == nullptr; }
|
|
|
|
inline void Reset() { ShaderContent = nullptr; ShaderMap = nullptr; }
|
|
|
|
inline ShaderType* GetShader() const { return ShaderContent; }
|
|
inline const FShaderMapBase* GetShaderMap() const { return ShaderMap; }
|
|
inline const FShaderMapBase& GetShaderMapChecked() const { check(ShaderMap); return *ShaderMap; }
|
|
inline FShaderType* GetType() const { return ShaderContent->GetType(GetPointerTable()); }
|
|
inline FVertexFactoryType* GetVertexFactoryType() const { return ShaderContent->GetVertexFactoryType(GetPointerTable()); }
|
|
inline FShaderMapResource& GetResourceChecked() const { FShaderMapResource* Resource = GetResource(); check(Resource); return *Resource; }
|
|
const PointerTableType& GetPointerTable() const;
|
|
FShaderMapResource* GetResource() const;
|
|
|
|
inline ShaderType* operator->() const { return ShaderContent; }
|
|
|
|
inline FRHIShader* GetRHIShaderBase(EShaderFrequency Frequency, bool bRequired = true) const
|
|
{
|
|
FRHIShader* RHIShader = nullptr;
|
|
if(ShaderContent)
|
|
{
|
|
checkSlow(ShaderContent->GetFrequency() == Frequency);
|
|
RHIShader = GetResourceChecked().GetShader(ShaderContent->GetResourceIndex(), bRequired);
|
|
if (RHIShader == nullptr)
|
|
{
|
|
UE_LOG(LogShaders, Log, TEXT("Failed to create shader for type %s with resource index %d."), GetType()->GetName(), ShaderContent->GetResourceIndex());
|
|
return nullptr;
|
|
}
|
|
checkSlow(RHIShader->GetFrequency() == Frequency);
|
|
}
|
|
return RHIShader;
|
|
}
|
|
|
|
inline FRHIGraphicsShader* GetGraphicsShader(bool bRequired = true) const
|
|
{
|
|
FRHIGraphicsShader* RHIShader = nullptr;
|
|
if(ShaderContent)
|
|
{
|
|
checkSlow(IsValidGraphicsFrequency(ShaderContent->GetFrequency()));
|
|
RHIShader = static_cast<FRHIGraphicsShader*>(GetResourceChecked().GetShader(ShaderContent->GetResourceIndex(), bRequired));
|
|
if (RHIShader == nullptr)
|
|
{
|
|
UE_LOG(LogShaders, Log, TEXT("Failed to create shader for type %s with resource index %d."), GetType()->GetName(), ShaderContent->GetResourceIndex());
|
|
return nullptr;
|
|
}
|
|
checkSlow(IsValidGraphicsFrequency(RHIShader->GetFrequency()));
|
|
}
|
|
return RHIShader;
|
|
}
|
|
|
|
/** @return the shader's vertex shader */
|
|
inline FRHIVertexShader* GetVertexShader(bool bRequired = true) const
|
|
{
|
|
return static_cast<FRHIVertexShader*>(GetRHIShaderBase(SF_Vertex, bRequired));
|
|
}
|
|
/** @return the shader's mesh shader */
|
|
inline FRHIMeshShader* GetMeshShader() const
|
|
{
|
|
return static_cast<FRHIMeshShader*>(GetRHIShaderBase(SF_Mesh));
|
|
}
|
|
/** @return the shader's aplification shader */
|
|
inline FRHIAmplificationShader* GetAmplificationShader() const
|
|
{
|
|
return static_cast<FRHIAmplificationShader*>(GetRHIShaderBase(SF_Amplification));
|
|
}
|
|
/** @return the shader's pixel shader */
|
|
inline FRHIPixelShader* GetPixelShader(bool bRequired = true) const
|
|
{
|
|
return static_cast<FRHIPixelShader*>(GetRHIShaderBase(SF_Pixel, bRequired));
|
|
}
|
|
/** @return the shader's geometry shader */
|
|
inline FRHIGeometryShader* GetGeometryShader() const
|
|
{
|
|
return static_cast<FRHIGeometryShader*>(GetRHIShaderBase(SF_Geometry));
|
|
}
|
|
/** @return the shader's compute shader */
|
|
inline FRHIComputeShader* GetComputeShader() const
|
|
{
|
|
return static_cast<FRHIComputeShader*>(GetRHIShaderBase(SF_Compute));
|
|
}
|
|
/** @return the shader's work graph shader */
|
|
inline FRHIWorkGraphShader* GetWorkGraphShader() const
|
|
{
|
|
FRHIWorkGraphShader* RHIShader = nullptr;
|
|
if (ShaderContent)
|
|
{
|
|
const EShaderFrequency Frequency = ShaderContent->GetFrequency();
|
|
checkSlow(IsWorkGraphShaderFrequency(Frequency));
|
|
RHIShader = static_cast<FRHIWorkGraphShader*>(GetRHIShaderBase(Frequency));
|
|
}
|
|
return RHIShader;
|
|
}
|
|
|
|
#if RHI_RAYTRACING
|
|
inline FRHIRayTracingShader* GetRayTracingShader() const
|
|
{
|
|
FRHIRayTracingShader* RHIShader = nullptr;
|
|
if(ShaderContent)
|
|
{
|
|
const EShaderFrequency Frequency = ShaderContent->GetFrequency();
|
|
checkSlow(Frequency == SF_RayGen
|
|
|| Frequency == SF_RayMiss
|
|
|| Frequency == SF_RayHitGroup
|
|
|| Frequency == SF_RayCallable);
|
|
RHIShader = static_cast<FRHIRayTracingShader*>(GetResourceChecked().GetShader(ShaderContent->GetResourceIndex()));
|
|
checkSlow(RHIShader->GetFrequency() == Frequency);
|
|
}
|
|
return RHIShader;
|
|
}
|
|
|
|
UE_DEPRECATED(5.1, "GetRayTracingMaterialLibraryIndex is deprecated. Use GetRayTracingHitGroupLibraryIndex instead.")
|
|
inline uint32 GetRayTracingMaterialLibraryIndex() const
|
|
{
|
|
return GetRayTracingHitGroupLibraryIndex();
|
|
}
|
|
|
|
inline uint32 GetRayTracingHitGroupLibraryIndex() const
|
|
{
|
|
checkSlow(ShaderContent);
|
|
checkSlow(ShaderContent->GetFrequency() == SF_RayHitGroup);
|
|
return GetResourceChecked().GetRayTracingHitGroupLibraryIndex(ShaderContent->GetResourceIndex());
|
|
}
|
|
|
|
inline uint32 GetRayTracingCallableShaderLibraryIndex() const
|
|
{
|
|
checkSlow(ShaderContent);
|
|
checkSlow(ShaderContent->GetFrequency() == SF_RayCallable);
|
|
return GetResourceChecked().GetRayTracingCallableShaderLibraryIndex(ShaderContent->GetResourceIndex());
|
|
}
|
|
|
|
inline uint32 GetRayTracingMissShaderLibraryIndex() const
|
|
{
|
|
checkSlow(ShaderContent);
|
|
checkSlow(ShaderContent->GetFrequency() == SF_RayMiss);
|
|
return GetResourceChecked().GetRayTracingMissShaderLibraryIndex(ShaderContent->GetResourceIndex());
|
|
}
|
|
#endif // RHI_RAYTRACING
|
|
|
|
private:
|
|
TShaderRefBase(ShaderType* InShader, const FShaderMapBase* InShaderMap)
|
|
: ShaderContent(InShader), ShaderMap(InShaderMap)
|
|
{
|
|
checkSlow((!InShader && !InShaderMap) || (InShader && InShaderMap));
|
|
}
|
|
|
|
ShaderType* ShaderContent;
|
|
const FShaderMapBase* ShaderMap;
|
|
|
|
template<typename ShaderType1>
|
|
friend inline bool operator==(const TShaderRefBase& Lhs, const TShaderRefBase<ShaderType1, PointerTableType>& Rhs)
|
|
{
|
|
if (Lhs.GetShader() == Rhs.GetShader())
|
|
{
|
|
check(Lhs.GetShaderMap() == Rhs.GetShaderMap());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename ShaderType1>
|
|
friend inline bool operator!=(const TShaderRefBase& Lhs, const TShaderRefBase<ShaderType1, PointerTableType>& Rhs)
|
|
{
|
|
return !operator==(Lhs, Rhs);
|
|
}
|
|
|
|
};
|
|
|
|
template<typename ShaderType>
|
|
using TShaderRef = TShaderRefBase<ShaderType, FShaderMapPointerTable>;
|
|
|
|
#define SHADER_TYPE_LIST \
|
|
SHADER_TYPE_ENTRY(Global), \
|
|
SHADER_TYPE_ENTRY(Material), \
|
|
SHADER_TYPE_ENTRY(MeshMaterial), \
|
|
SHADER_TYPE_ENTRY(Niagara), \
|
|
SHADER_TYPE_ENTRY(OCIO), \
|
|
SHADER_TYPE_ENTRY(ComputeKernel), \
|
|
SHADER_TYPE_ENTRY(NNERuntimeIREE),
|
|
|
|
/**
|
|
* An object which is used to serialize/deserialize, compile, and cache a particular shader class.
|
|
*
|
|
* A shader type can manage multiple instance of FShader across mutiple dimensions such as EShaderPlatform, or permutation id.
|
|
* The number of permutation of a shader type is simply given by GetPermutationCount().
|
|
*/
|
|
class FShaderType
|
|
{
|
|
public:
|
|
#define SHADER_TYPE_ENTRY(Name) Name
|
|
enum class EShaderTypeForDynamicCast : uint32
|
|
{
|
|
SHADER_TYPE_LIST
|
|
NumShaderTypes,
|
|
};
|
|
#undef SHADER_TYPE_ENTRY
|
|
|
|
/**
|
|
* Derived FShaderTypes should derive from this class to pass params to FShader constructor
|
|
*/
|
|
class FParameters
|
|
{
|
|
public:
|
|
virtual ~FParameters(){}
|
|
};
|
|
|
|
typedef class FShader* (*ConstructSerializedType)();
|
|
typedef FShader* (*ConstructCompiledType)(const FShader::CompiledShaderInitializerType& Initializer);
|
|
typedef bool (*ShouldCompilePermutationType)(const FShaderPermutationParameters&);
|
|
typedef EShaderPermutationPrecacheRequest (*ShouldPrecachePermutationType)(const FShaderPermutationParameters&);
|
|
typedef ERayTracingPayloadType(*GetRayTracingPayloadTypeType)(const int32 PermutationId);
|
|
typedef const FShaderBindingLayout*(*GetShaderBindingLayoutType)(const FShaderPermutationParameters&);
|
|
#if WITH_EDITOR
|
|
typedef void (*ModifyCompilationEnvironmentType)(const FShaderPermutationParameters&, FShaderCompilerEnvironment&);
|
|
typedef bool (*ValidateCompiledResultType)(EShaderPlatform, const FShaderParameterMap&, TArray<FString>&);
|
|
typedef EShaderCompileJobPriority(*GetOverrideJobPriorityType)();
|
|
typedef void (*GetPermutationIdStringType)(int32 PermutationId, FString&, bool);
|
|
#endif // WITH_EDITOR
|
|
|
|
/** @return The global shader factory list. */
|
|
static RENDERCORE_API TLinkedList<FShaderType*>*& GetTypeList();
|
|
|
|
static RENDERCORE_API FShaderType* GetShaderTypeByName(const TCHAR* Name);
|
|
static RENDERCORE_API TArray<const FShaderType*> GetShaderTypesByFilename(const TCHAR* Filename, bool bSearchAsRegexFilter = false);
|
|
static RENDERCORE_API TArray<const FShaderType*> GetShaderTypesByFilenameFilter(const TFunction<bool(const TCHAR*)>& InFilenameFilter);
|
|
|
|
/** @return The global shader name to type map */
|
|
static RENDERCORE_API TMap<FHashedName, FShaderType*>& GetNameToTypeMap();
|
|
|
|
static RENDERCORE_API const TArray<FShaderType*>& GetSortedTypes(EShaderTypeForDynamicCast Type);
|
|
|
|
/** Initialize FShaderType static members, this must be called before any shader types are created. */
|
|
static RENDERCORE_API void Initialize(const TMap<FString, TArray<const TCHAR*> >& ShaderFileToUniformBufferVariables);
|
|
|
|
/** Uninitializes FShaderType cached data. */
|
|
static RENDERCORE_API void Uninitialize();
|
|
|
|
/** Minimal initialization constructor. */
|
|
RENDERCORE_API FShaderType(
|
|
EShaderTypeForDynamicCast InShaderTypeForDynamicCast,
|
|
FTypeLayoutDesc& InTypeLayout,
|
|
const TCHAR* InName,
|
|
const TCHAR* InSourceFilename,
|
|
const TCHAR* InFunctionName,
|
|
uint32 InFrequency,
|
|
int32 TotalPermutationCount,
|
|
ConstructSerializedType InConstructSerializedRef,
|
|
ConstructCompiledType InConstructCompiledRef,
|
|
ShouldCompilePermutationType InShouldCompilePermutationRef,
|
|
ShouldPrecachePermutationType InShouldPrecachePermutationRef,
|
|
GetRayTracingPayloadTypeType InGetRayTracingPayloadTypeRef,
|
|
GetShaderBindingLayoutType InGetShaderBindingLayoutTypeRef,
|
|
#if WITH_EDITOR
|
|
ModifyCompilationEnvironmentType InModifyCompilationEnvironmentRef,
|
|
ValidateCompiledResultType InValidateCompiledResultRef,
|
|
GetOverrideJobPriorityType InGetOverrideJobPriorityRef,
|
|
#endif // WITH_EDITOR
|
|
uint32 InTypeSize,
|
|
const FShaderParametersMetadata* InRootParametersMetadata
|
|
#if WITH_EDITOR
|
|
, GetPermutationIdStringType InGetPermutationIdStringRef = nullptr
|
|
#endif
|
|
|
|
);
|
|
|
|
RENDERCORE_API virtual ~FShaderType();
|
|
|
|
/** Constructs a new instance of the shader type for deserialization. */
|
|
RENDERCORE_API FShader* ConstructForDeserialization() const;
|
|
RENDERCORE_API FShader* ConstructCompiled(const FShader::CompiledShaderInitializerType& Initializer) const;
|
|
|
|
RENDERCORE_API bool ShouldCompilePermutation(const FShaderPermutationParameters& Parameters) const;
|
|
RENDERCORE_API EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FShaderPermutationParameters& Parameters) const;
|
|
RENDERCORE_API const FShaderBindingLayout* GetShaderBindingLayout(const FShaderPermutationParameters& Parameters) const;
|
|
|
|
#if WITH_EDITOR
|
|
RENDERCORE_API void ModifyCompilationEnvironment(const FShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) const;
|
|
|
|
/**
|
|
* Checks if the shader type should pass compilation for a particular set of parameters.
|
|
* @param Platform - Platform to validate.
|
|
* @param ParameterMap - Shader parameters to validate.
|
|
* @param OutError - List for appending validation errors.
|
|
*/
|
|
RENDERCORE_API bool ValidateCompiledResult(EShaderPlatform Platform, const FShaderParameterMap& ParameterMap, TArray<FString>& OutError) const;
|
|
|
|
/** Returns a custom compile job priority or EShaderCompileJobPriority::None to ignore the customization. */
|
|
RENDERCORE_API EShaderCompileJobPriority GetOverrideJobPriority() const;
|
|
|
|
/**
|
|
* Returns a string representation for the specified permutation Id.
|
|
* @param PermutationId Zero based index in the half-open range [0, GetPermutationCount()).
|
|
* @param bFullNames Specifies whether the full shader defines are meant to be included. If false, a short form is returned as comma-separated integers.
|
|
*/
|
|
RENDERCORE_API FString GetPermutationIdString(int32 PermutationId, bool bFullNames) const;
|
|
#endif // WITH_EDITOR
|
|
|
|
RENDERCORE_API ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId) const;
|
|
|
|
/** Calculates a Hash based on this shader type's source code and includes */
|
|
RENDERCORE_API const FSHAHash& GetSourceHash(EShaderPlatform ShaderPlatform) const;
|
|
|
|
/** Serializes a shader type reference by name. */
|
|
RENDERCORE_API friend FArchive& operator<<(FArchive& Ar,FShaderType*& Ref);
|
|
|
|
/** Hashes a pointer to a shader type. */
|
|
friend uint32 GetTypeHash(FShaderType* Ref)
|
|
{
|
|
return Ref ? GetTypeHash(Ref->HashedName) : 0u;
|
|
}
|
|
|
|
// Dynamic casts.
|
|
FORCEINLINE FGlobalShaderType* GetGlobalShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Global) ? reinterpret_cast<FGlobalShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FGlobalShaderType* GetGlobalShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Global) ? reinterpret_cast<const FGlobalShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FMaterialShaderType* GetMaterialShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Material) ? reinterpret_cast<FMaterialShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FMaterialShaderType* GetMaterialShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Material) ? reinterpret_cast<const FMaterialShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FMeshMaterialShaderType* GetMeshMaterialShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::MeshMaterial) ? reinterpret_cast<FMeshMaterialShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FMeshMaterialShaderType* GetMeshMaterialShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::MeshMaterial) ? reinterpret_cast<const FMeshMaterialShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FNiagaraShaderType* GetNiagaraShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Niagara) ? reinterpret_cast<const FNiagaraShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FNiagaraShaderType* GetNiagaraShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Niagara) ? reinterpret_cast<FNiagaraShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FOpenColorIOShaderType* GetOpenColorIOShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::OCIO) ? reinterpret_cast<const FOpenColorIOShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FOpenColorIOShaderType* GetOpenColorIOShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::OCIO) ? reinterpret_cast<FOpenColorIOShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FComputeKernelShaderType* GetComputeKernelShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::ComputeKernel) ? reinterpret_cast<const FComputeKernelShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FComputeKernelShaderType* GetComputeKernelShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::ComputeKernel) ? reinterpret_cast<FComputeKernelShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE const FNNERuntimeIREEShaderType* GetNNERuntimeIREEShaderType() const
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::NNERuntimeIREE) ? reinterpret_cast<const FNNERuntimeIREEShaderType*>(this) : nullptr;
|
|
}
|
|
FORCEINLINE FNNERuntimeIREEShaderType* GetNNERuntimeIREEShaderType()
|
|
{
|
|
return (ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::NNERuntimeIREE) ? reinterpret_cast<FNNERuntimeIREEShaderType*>(this) : nullptr;
|
|
}
|
|
|
|
FORCEINLINE const FGlobalShaderType* AsGlobalShaderType() const
|
|
{
|
|
checkf(ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Global, TEXT("ShaderType %s is not Global"), GetName());
|
|
return reinterpret_cast<const FGlobalShaderType*>(this);
|
|
}
|
|
|
|
FORCEINLINE const FMaterialShaderType* AsMaterialShaderType() const
|
|
{
|
|
checkf(ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Material, TEXT("ShaderType %s is not Material"), GetName());
|
|
return reinterpret_cast<const FMaterialShaderType*>(this);
|
|
}
|
|
|
|
FORCEINLINE const FMeshMaterialShaderType* AsMeshMaterialShaderType() const
|
|
{
|
|
checkf(ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::MeshMaterial, TEXT("ShaderType %s is not MeshMaterial"), GetName());
|
|
return reinterpret_cast<const FMeshMaterialShaderType*>(this);
|
|
}
|
|
|
|
FORCEINLINE const FNiagaraShaderType* AsNiagaraShaderType() const
|
|
{
|
|
checkf(ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::Niagara, TEXT("ShaderType %s is not Niagara"), GetName());
|
|
return reinterpret_cast<const FNiagaraShaderType*>(this);
|
|
}
|
|
|
|
FORCEINLINE const FOpenColorIOShaderType* AsOpenColorIOShaderType() const
|
|
{
|
|
checkf(ShaderTypeForDynamicCast == EShaderTypeForDynamicCast::OCIO, TEXT("ShaderType %s is not OCIO"), GetName());
|
|
return reinterpret_cast<const FOpenColorIOShaderType*>(this);
|
|
}
|
|
|
|
inline EShaderTypeForDynamicCast GetTypeForDynamicCast() const
|
|
{
|
|
return ShaderTypeForDynamicCast;
|
|
}
|
|
|
|
// Accessors.
|
|
inline const FTypeLayoutDesc& GetLayout() const
|
|
{
|
|
return *TypeLayout;
|
|
}
|
|
inline EShaderFrequency GetFrequency() const
|
|
{
|
|
return (EShaderFrequency)Frequency;
|
|
}
|
|
inline const TCHAR* GetName() const
|
|
{
|
|
return Name;
|
|
}
|
|
inline const FName& GetFName() const
|
|
{
|
|
return TypeName;
|
|
}
|
|
inline const FHashedName& GetHashedName() const
|
|
{
|
|
return HashedName;
|
|
}
|
|
inline const TCHAR* GetShaderFilename() const
|
|
{
|
|
return SourceFilename;
|
|
}
|
|
inline const FHashedName& GetHashedShaderFilename() const
|
|
{
|
|
return HashedSourceFilename;
|
|
}
|
|
inline const TCHAR* GetFunctionName() const
|
|
{
|
|
return FunctionName;
|
|
}
|
|
inline uint32 GetTypeSize() const
|
|
{
|
|
return TypeSize;
|
|
}
|
|
|
|
inline int32 GetNumShaders() const
|
|
{
|
|
// TODO count this
|
|
return 0;
|
|
}
|
|
|
|
inline int32 GetPermutationCount() const
|
|
{
|
|
return TotalPermutationCount;
|
|
}
|
|
|
|
/** Returns the meta data for the root shader parameter struct. */
|
|
inline const FShaderParametersMetadata* GetRootParametersMetadata() const
|
|
{
|
|
return RootParametersMetadata;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
const TSet<const FShaderParametersMetadata*>& GetReferencedUniformBuffers() const
|
|
{
|
|
return ReferencedUniformBuffers;
|
|
}
|
|
|
|
/** Adds include statements for uniform buffers that this shader type references. */
|
|
RENDERCORE_API void AddUniformBufferIncludesToEnvironment(FShaderCompilerEnvironment& OutEnvironment, EShaderPlatform Platform) const;
|
|
|
|
RENDERCORE_API void UpdateReferencedUniformBufferNames(const TMap<FString, TArray<const TCHAR*>>& ShaderFileToUniformBufferVariables);
|
|
|
|
RENDERCORE_API void GetShaderStableKeyParts(struct FStableShaderKeyAndValue& SaveKeyVal);
|
|
#endif // WITH_EDITOR
|
|
|
|
RENDERCORE_API void DumpDebugInfo();
|
|
|
|
private:
|
|
EShaderTypeForDynamicCast ShaderTypeForDynamicCast;
|
|
const FTypeLayoutDesc* TypeLayout;
|
|
const TCHAR* Name;
|
|
FName TypeName;
|
|
FHashedName HashedName;
|
|
FHashedName HashedSourceFilename;
|
|
const TCHAR* SourceFilename;
|
|
const TCHAR* FunctionName;
|
|
uint32 Frequency;
|
|
uint32 TypeSize;
|
|
int32 TotalPermutationCount;
|
|
|
|
ConstructSerializedType ConstructSerializedRef;
|
|
ConstructCompiledType ConstructCompiledRef;
|
|
ShouldCompilePermutationType ShouldCompilePermutationRef;
|
|
ShouldPrecachePermutationType ShouldPrecachePermutationRef;
|
|
GetRayTracingPayloadTypeType GetRayTracingPayloadTypeRef;
|
|
GetShaderBindingLayoutType GetShaderBindingLayoutTypeRef;
|
|
#if WITH_EDITOR
|
|
ModifyCompilationEnvironmentType ModifyCompilationEnvironmentRef;
|
|
ValidateCompiledResultType ValidateCompiledResultRef;
|
|
GetOverrideJobPriorityType GetOverrideJobPriorityRef;
|
|
GetPermutationIdStringType GetPermutationIdStringRef;
|
|
#endif
|
|
const FShaderParametersMetadata* const RootParametersMetadata;
|
|
|
|
TLinkedList<FShaderType*> GlobalListLink;
|
|
|
|
friend void RENDERCORE_API DumpShaderStats( EShaderPlatform Platform, EShaderFrequency Frequency );
|
|
|
|
#if WITH_EDITOR
|
|
protected:
|
|
/**
|
|
* Cache of referenced uniform buffer structs.
|
|
* These are derived from source files so they need to be flushed when editing and recompiling shaders on the fly.
|
|
* FShaderType::Initialize will add the referenced uniform buffers, but this set may be updated by FlushShaderFileCache.
|
|
*/
|
|
TSet<const FShaderParametersMetadata*> ReferencedUniformBuffers;
|
|
#endif // WITH_EDITOR
|
|
};
|
|
|
|
inline FString LexToString(FShaderType::EShaderTypeForDynamicCast ShaderType)
|
|
{
|
|
#define SHADER_TYPE_ENTRY(Name) TEXT(#Name)
|
|
static const TCHAR* TypeStrings[] =
|
|
{
|
|
SHADER_TYPE_LIST
|
|
};
|
|
#undef SHADER_TYPE_ENTRY
|
|
checkf(ShaderType < FShaderType::EShaderTypeForDynamicCast::NumShaderTypes, TEXT("Invalid shader type"));
|
|
static_assert((sizeof(TypeStrings) / sizeof(TCHAR*)) == (int)FShaderType::EShaderTypeForDynamicCast::NumShaderTypes);
|
|
return TypeStrings[static_cast<uint32>(ShaderType)];
|
|
}
|
|
|
|
/**
|
|
* Registers a shader type in various systems. Should be created as a static field/global.
|
|
*
|
|
* Each shader type is collected here, not as an instance but as an accessor, so the actual construction can be deferred.
|
|
* The collection happens during static init, the actual construction happens later during launch.
|
|
* The purpose of collecting the types is the CommitAll function, called in LaunchEngineLoop, to ensure all type instances are constructed and registered before other systems start iterating them.
|
|
*/
|
|
class FShaderTypeRegistration
|
|
{
|
|
public:
|
|
FShaderTypeRegistration(TFunctionRef<FShaderType& ()> LazyShaderTypeAccessor)
|
|
: LazyShaderTypeAccessor(LazyShaderTypeAccessor)
|
|
{
|
|
checkf(!AreShaderTypesInitialized(), TEXT("Shader type was loaded too late, use ELoadingPhase::PostConfigInit on your module to cause it to load earlier. This shader will not be compiled or function. The module and shader will appear in the callstack of this assert."));
|
|
GetInstances().Add(this);
|
|
}
|
|
|
|
static RENDERCORE_API TArray<const FShaderTypeRegistration*>& GetInstances();
|
|
|
|
// Actually register all the types and clear the array
|
|
static RENDERCORE_API void CommitAll();
|
|
static RENDERCORE_API bool AreShaderTypesInitialized();
|
|
|
|
private:
|
|
static bool bShaderTypesInitialized;
|
|
TFunctionRef<FShaderType& ()> LazyShaderTypeAccessor;
|
|
};
|
|
|
|
struct FShaderCompiledShaderInitializerType
|
|
{
|
|
const FShaderType* Type;
|
|
const FShaderType::FParameters* Parameters;
|
|
FShaderTarget Target;
|
|
TConstArrayView<uint8> Code;
|
|
const FShaderParameterMap& ParameterMap;
|
|
const FSHAHash& OutputHash;
|
|
FSHAHash MaterialShaderMapHash;
|
|
const FShaderPipelineType* ShaderPipeline;
|
|
const FVertexFactoryType* VertexFactoryType;
|
|
uint32 NumInstructions;
|
|
uint32 NumTextureSamplers;
|
|
uint32 CodeSize;
|
|
int32 PermutationId;
|
|
TArray<FGenericShaderStat> ShaderStatistics;
|
|
|
|
RENDERCORE_API FShaderCompiledShaderInitializerType(
|
|
const FShaderType* InType,
|
|
const FShaderType::FParameters* InParameters,
|
|
int32 InPermutationId,
|
|
const FShaderCompilerOutput& CompilerOutput,
|
|
const FSHAHash& InMaterialShaderMapHash,
|
|
const FShaderPipelineType* InShaderPipeline,
|
|
const FVertexFactoryType* InVertexFactoryType
|
|
);
|
|
};
|
|
|
|
#if WITH_EDITOR
|
|
#define SHADER_DECLARE_EDITOR_VTABLE(ShaderClass) \
|
|
static void ModifyCompilationEnvironmentImpl(const FShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) \
|
|
{ \
|
|
const typename ShaderClass::FPermutationDomain PermutationVector(Parameters.PermutationId); \
|
|
PermutationVector.ModifyCompilationEnvironment(OutEnvironment); \
|
|
ShaderClass::ModifyCompilationEnvironment(static_cast<const typename ShaderClass::FPermutationParameters&>(Parameters), OutEnvironment); \
|
|
} \
|
|
static void GetPermutationIdStringImpl(int32 PermutationId, FString& OutString, bool bFullNames) \
|
|
{ \
|
|
const typename ShaderClass::FPermutationDomain PermutationVector(PermutationId); \
|
|
UE::ShaderPermutationUtils::FormatPermutationDomain(PermutationVector, OutString, bFullNames, nullptr); \
|
|
}
|
|
#else
|
|
#define SHADER_DECLARE_EDITOR_VTABLE(ShaderClass)
|
|
#endif // WITH_EDITOR
|
|
|
|
#define SHADER_DECLARE_VTABLE(ShaderClass) \
|
|
static FShader* ConstructSerializedInstance() { return new ShaderClass(); } \
|
|
static FShader* ConstructCompiledInstance(const typename FShader::CompiledShaderInitializerType& Initializer) \
|
|
{ return new ShaderClass(static_cast<const typename ShaderMetaType::CompiledShaderInitializerType&>(Initializer)); }\
|
|
static bool ShouldCompilePermutationImpl(const FShaderPermutationParameters& Parameters) \
|
|
{ return ShaderClass::ShouldCompilePermutation(static_cast<const typename ShaderClass::FPermutationParameters&>(Parameters)); } \
|
|
static EShaderPermutationPrecacheRequest ShouldPrecachePermutationImpl(const FShaderPermutationParameters& Parameters) \
|
|
{ return ShaderClass::ShouldPrecachePermutation(static_cast<const typename ShaderClass::FPermutationParameters&>(Parameters)); } \
|
|
SHADER_DECLARE_EDITOR_VTABLE(ShaderClass)
|
|
|
|
|
|
#define INTERNAL_DECLARE_SHADER_TYPE_COMMON(ShaderClass,ShaderMetaTypeShortcut,RequiredAPI) \
|
|
public: \
|
|
using ShaderMetaType = F##ShaderMetaTypeShortcut##ShaderType; \
|
|
using ShaderMapType = F##ShaderMetaTypeShortcut##ShaderMap; \
|
|
\
|
|
static RequiredAPI ShaderMetaType& GetStaticType(); \
|
|
private: \
|
|
static FShaderTypeRegistration ShaderTypeRegistration; \
|
|
public: \
|
|
\
|
|
SHADER_DECLARE_VTABLE(ShaderClass)
|
|
|
|
/**
|
|
* A macro to declare a new shader type. This should be called in the class body of the new shader type.
|
|
* @param ShaderClass - The name of the class representing an instance of the shader type.
|
|
* @param ShaderMetaTypeShortcut - The shortcut for the shader meta type: simple, material, meshmaterial, etc. The shader meta type
|
|
* controls
|
|
*/
|
|
#define DECLARE_EXPORTED_SHADER_TYPE(ShaderClass,ShaderMetaTypeShortcut,RequiredAPI, ...) \
|
|
INTERNAL_DECLARE_SHADER_TYPE_COMMON(ShaderClass, ShaderMetaTypeShortcut, RequiredAPI); \
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(ShaderClass, RequiredAPI, NonVirtual); \
|
|
public:
|
|
|
|
#define DECLARE_SHADER_TYPE(ShaderClass,ShaderMetaTypeShortcut,...) \
|
|
DECLARE_EXPORTED_SHADER_TYPE(ShaderClass,ShaderMetaTypeShortcut,, ##__VA_ARGS__)
|
|
|
|
#define DECLARE_SHADER_TYPE_EXPLICIT_BASES(ShaderClass,ShaderMetaTypeShortcut,...) \
|
|
INTERNAL_DECLARE_SHADER_TYPE_COMMON(ShaderClass, ShaderMetaTypeShortcut,); \
|
|
DECLARE_EXPORTED_TYPE_LAYOUT_EXPLICIT_BASES(ShaderClass,, NonVirtual, __VA_ARGS__); \
|
|
public:
|
|
|
|
#if WITH_EDITOR
|
|
|
|
#define SHADER_TYPE_EDITOR_VTABLE(ShaderClass) \
|
|
, ShaderClass::ModifyCompilationEnvironmentImpl \
|
|
, ShaderClass::ValidateCompiledResult \
|
|
, ShaderClass::GetOverrideJobPriority
|
|
|
|
#define SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
, ShaderClass::GetPermutationIdStringImpl
|
|
|
|
#else
|
|
|
|
#define SHADER_TYPE_EDITOR_VTABLE(ShaderClass)
|
|
#define SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass)
|
|
|
|
#endif
|
|
|
|
#define SHADER_TYPE_VTABLE(ShaderClass) \
|
|
ShaderClass::ConstructSerializedInstance, \
|
|
ShaderClass::ConstructCompiledInstance, \
|
|
ShaderClass::ShouldCompilePermutationImpl, \
|
|
ShaderClass::ShouldPrecachePermutationImpl, \
|
|
ShaderClass::GetRayTracingPayloadType, \
|
|
ShaderClass::GetShaderBindingLayout \
|
|
SHADER_TYPE_EDITOR_VTABLE(ShaderClass)
|
|
|
|
#if !UE_BUILD_DOCS
|
|
/** A macro to implement a shader type. */
|
|
#define IMPLEMENT_SHADER_TYPE(TemplatePrefix,ShaderClass,SourceFilename,FunctionName,Frequency) \
|
|
IMPLEMENT_UNREGISTERED_TEMPLATE_TYPE_LAYOUT(TemplatePrefix, ShaderClass); \
|
|
TemplatePrefix \
|
|
ShaderClass::ShaderMetaType& ShaderClass::GetStaticType() \
|
|
{ \
|
|
static ShaderClass::ShaderMetaType StaticType( \
|
|
ShaderClass::StaticGetTypeLayout(), \
|
|
TEXT(#ShaderClass), \
|
|
SourceFilename, \
|
|
FunctionName, \
|
|
Frequency, \
|
|
ShaderClass::FPermutationDomain::PermutationCount, \
|
|
SHADER_TYPE_VTABLE(ShaderClass), \
|
|
sizeof(ShaderClass), \
|
|
ShaderClass::GetRootParametersMetadata() \
|
|
SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
); \
|
|
return StaticType; \
|
|
} \
|
|
TemplatePrefix FShaderTypeRegistration ShaderClass::ShaderTypeRegistration{TFunctionRef<::FShaderType&()>{ShaderClass::GetStaticType}};
|
|
|
|
/** A macro to implement a shader type. Shader name is got from GetDebugName(), which is helpful for templated shaders. */
|
|
#define IMPLEMENT_SHADER_TYPE_WITH_DEBUG_NAME(TemplatePrefix,ShaderClass,SourceFilename,FunctionName,Frequency) \
|
|
IMPLEMENT_UNREGISTERED_TEMPLATE_TYPE_LAYOUT(TemplatePrefix, ShaderClass); \
|
|
TemplatePrefix \
|
|
typename ShaderClass::ShaderMetaType& ShaderClass::GetStaticType() \
|
|
{ \
|
|
static typename ShaderClass::ShaderMetaType StaticType( \
|
|
ShaderClass::StaticGetTypeLayout(), \
|
|
ShaderClass::GetDebugName(), \
|
|
SourceFilename, \
|
|
FunctionName, \
|
|
Frequency, \
|
|
ShaderClass::FPermutationDomain::PermutationCount, \
|
|
SHADER_TYPE_VTABLE(ShaderClass), \
|
|
sizeof(ShaderClass), \
|
|
ShaderClass::GetRootParametersMetadata() \
|
|
SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
); \
|
|
return StaticType; \
|
|
} \
|
|
TemplatePrefix FShaderTypeRegistration ShaderClass::ShaderTypeRegistration{TFunctionRef<::FShaderType&()>{ShaderClass::GetStaticType}};
|
|
|
|
/** A macro to implement a templated shader type, the function name and the source filename comes from the class. */
|
|
#define IMPLEMENT_SHADER_TYPE2_WITH_TEMPLATE_PREFIX(TemplatePrefix,ShaderClass,Frequency) \
|
|
IMPLEMENT_UNREGISTERED_TEMPLATE_TYPE_LAYOUT(TemplatePrefix, ShaderClass); \
|
|
TemplatePrefix \
|
|
ShaderClass::ShaderMetaType& ShaderClass::GetStaticType() \
|
|
{ \
|
|
static ShaderClass::ShaderMetaType StaticType( \
|
|
ShaderClass::StaticGetTypeLayout(), \
|
|
TEXT(#ShaderClass), \
|
|
ShaderClass::GetSourceFilename(), \
|
|
ShaderClass::GetFunctionName(), \
|
|
Frequency, \
|
|
ShaderClass::FPermutationDomain::PermutationCount, \
|
|
SHADER_TYPE_VTABLE(ShaderClass), \
|
|
sizeof(ShaderClass), \
|
|
ShaderClass::GetRootParametersMetadata() \
|
|
SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
); \
|
|
return StaticType; \
|
|
} \
|
|
TemplatePrefix FShaderTypeRegistration ShaderClass::ShaderTypeRegistration{TFunctionRef<::FShaderType&()>{ShaderClass::GetStaticType}};
|
|
|
|
#define IMPLEMENT_SHADER_TYPE2(ShaderClass,Frequency) \
|
|
IMPLEMENT_SHADER_TYPE2_WITH_TEMPLATE_PREFIX(template<>, ShaderClass, Frequency)
|
|
|
|
/** todo: this should replace IMPLEMENT_SHADER_TYPE */
|
|
#define IMPLEMENT_SHADER_TYPE3(ShaderClass,Frequency) \
|
|
IMPLEMENT_UNREGISTERED_TEMPLATE_TYPE_LAYOUT(,ShaderClass); \
|
|
ShaderClass::ShaderMetaType& ShaderClass::GetStaticType() \
|
|
{ \
|
|
static ShaderClass::ShaderMetaType StaticType( \
|
|
ShaderClass::StaticGetTypeLayout(), \
|
|
TEXT(#ShaderClass), \
|
|
ShaderClass::GetSourceFilename(), \
|
|
ShaderClass::GetFunctionName(), \
|
|
Frequency, \
|
|
ShaderClass::FPermutationDomain::PermutationCount, \
|
|
SHADER_TYPE_VTABLE(ShaderClass), \
|
|
sizeof(ShaderClass), \
|
|
ShaderClass::GetRootParametersMetadata() \
|
|
SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
); \
|
|
return StaticType; \
|
|
} \
|
|
FShaderTypeRegistration ShaderClass::ShaderTypeRegistration{TFunctionRef<::FShaderType&()>{ShaderClass::GetStaticType}};
|
|
#endif // !UE_BUILD_DOCS
|
|
|
|
#define IMPLEMENT_SHADER_TYPE4_WITH_TEMPLATE_PREFIX(TemplatePrefix,RequiredAPI,ShaderClass,Frequency) \
|
|
IMPLEMENT_UNREGISTERED_TEMPLATE_TYPE_LAYOUT(TemplatePrefix, ShaderClass); \
|
|
TemplatePrefix RequiredAPI \
|
|
ShaderClass::ShaderMetaType& ShaderClass::GetStaticType() \
|
|
{ \
|
|
static ShaderClass::ShaderMetaType StaticType( \
|
|
ShaderClass::StaticGetTypeLayout(), \
|
|
TEXT(#ShaderClass), \
|
|
ShaderClass::GetSourceFilename(), \
|
|
ShaderClass::GetFunctionName(), \
|
|
Frequency, \
|
|
ShaderClass::FPermutationDomain::PermutationCount, \
|
|
SHADER_TYPE_VTABLE(ShaderClass), \
|
|
sizeof(ShaderClass), \
|
|
ShaderClass::GetRootParametersMetadata() \
|
|
SHADER_TYPE_EDITOR_PERMUTATION_METADATA(ShaderClass) \
|
|
); \
|
|
return StaticType; \
|
|
} \
|
|
TemplatePrefix FShaderTypeRegistration ShaderClass::ShaderTypeRegistration{TFunctionRef<::FShaderType&()>{ShaderClass::GetStaticType}};
|
|
|
|
#if WITH_EDITOR
|
|
|
|
#define IMPLEMENT_SHADER_TYPE_CONSTRUCTOR(ShaderClass, InShaderTypeForDynamicCast, InShaderClassUserFriendlyName) \
|
|
ShaderClass( \
|
|
FTypeLayoutDesc& InTypeLayout, \
|
|
const TCHAR* InName, \
|
|
const TCHAR* InSourceFilename, \
|
|
const TCHAR* InFunctionName, \
|
|
uint32 InFrequency, \
|
|
int32 InTotalPermutationCount, \
|
|
ConstructSerializedType InConstructSerializedRef, \
|
|
ConstructCompiledType InConstructCompiledRef, \
|
|
ShouldCompilePermutationType InShouldCompilePermutationRef, \
|
|
ShouldPrecachePermutationType InShouldPrecachePermutationRef, \
|
|
GetRayTracingPayloadTypeType InGetRayTracingPayloadTypeRef, \
|
|
GetShaderBindingLayoutType InGetShaderBindingLayoutTypeRef, \
|
|
ModifyCompilationEnvironmentType InModifyCompilationEnvironmentRef, \
|
|
ValidateCompiledResultType InValidateCompiledResultRef, \
|
|
GetOverrideJobPriorityType InGetOverrideJobPriorityRef, \
|
|
uint32 InTypeSize, \
|
|
const FShaderParametersMetadata* InRootParametersMetadata = nullptr, \
|
|
GetPermutationIdStringType InGetPermutationIdStringRef = nullptr \
|
|
): \
|
|
FShaderType( \
|
|
InShaderTypeForDynamicCast, \
|
|
InTypeLayout, \
|
|
InName, \
|
|
InSourceFilename, \
|
|
InFunctionName, \
|
|
InFrequency, \
|
|
InTotalPermutationCount, \
|
|
InConstructSerializedRef, \
|
|
InConstructCompiledRef, \
|
|
InShouldCompilePermutationRef, \
|
|
InShouldPrecachePermutationRef, \
|
|
InGetRayTracingPayloadTypeRef, \
|
|
InGetShaderBindingLayoutTypeRef, \
|
|
InModifyCompilationEnvironmentRef, \
|
|
InValidateCompiledResultRef, \
|
|
InGetOverrideJobPriorityRef, \
|
|
InTypeSize, \
|
|
InRootParametersMetadata, \
|
|
InGetPermutationIdStringRef \
|
|
) \
|
|
{ \
|
|
checkf(FPaths::GetExtension(InSourceFilename) == TEXT("usf"), \
|
|
TEXT("Incorrect virtual shader path extension for %s '%s': Only .usf files should be compiled."), \
|
|
InShaderClassUserFriendlyName, InSourceFilename); \
|
|
}
|
|
|
|
#else
|
|
|
|
#define IMPLEMENT_SHADER_TYPE_CONSTRUCTOR(ShaderClass, InShaderTypeForDynamicCast, InShaderClassUserFriendlyName) \
|
|
ShaderClass( \
|
|
FTypeLayoutDesc& InTypeLayout, \
|
|
const TCHAR* InName, \
|
|
const TCHAR* InSourceFilename, \
|
|
const TCHAR* InFunctionName, \
|
|
uint32 InFrequency, \
|
|
int32 InTotalPermutationCount, \
|
|
ConstructSerializedType InConstructSerializedRef, \
|
|
ConstructCompiledType InConstructCompiledRef, \
|
|
ShouldCompilePermutationType InShouldCompilePermutationRef, \
|
|
ShouldPrecachePermutationType InShouldPrecachePermutationRef, \
|
|
GetRayTracingPayloadTypeType InGetRayTracingPayloadTypeRef, \
|
|
GetShaderBindingLayoutType InGetShaderBindingLayoutTypeRef, \
|
|
uint32 InTypeSize, \
|
|
const FShaderParametersMetadata* InRootParametersMetadata = nullptr \
|
|
): \
|
|
FShaderType( \
|
|
InShaderTypeForDynamicCast, \
|
|
InTypeLayout, \
|
|
InName, \
|
|
InSourceFilename, \
|
|
InFunctionName, \
|
|
InFrequency, \
|
|
InTotalPermutationCount, \
|
|
InConstructSerializedRef, \
|
|
InConstructCompiledRef, \
|
|
InShouldCompilePermutationRef, \
|
|
InShouldPrecachePermutationRef, \
|
|
InGetRayTracingPayloadTypeRef, \
|
|
InGetShaderBindingLayoutTypeRef, \
|
|
InTypeSize, \
|
|
InRootParametersMetadata \
|
|
) \
|
|
{ \
|
|
checkf(FPaths::GetExtension(InSourceFilename) == TEXT("usf"), \
|
|
TEXT("Incorrect virtual shader path extension for %s '%s': Only .usf files should be compiled."), \
|
|
InShaderClassUserFriendlyName, InSourceFilename); \
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|
|
|
|
// Binding of a set of shader stages in a single pipeline
|
|
class FShaderPipelineType
|
|
{
|
|
public:
|
|
// Set bShouldOptimizeUnusedOutputs to true if we want unique FShaders for each shader pipeline
|
|
// Set bShouldOptimizeUnusedOutputs to false if the FShaders will point to the individual shaders in the map
|
|
RENDERCORE_API FShaderPipelineType(
|
|
const TCHAR* InName,
|
|
const FShaderType* InVertexOrMeshShader,
|
|
const FShaderType* InGeometryOrAmplificationShader,
|
|
const FShaderType* InPixelShader,
|
|
bool bInIsMeshPipeline,
|
|
bool bInShouldOptimizeUnusedOutputs);
|
|
RENDERCORE_API ~FShaderPipelineType();
|
|
|
|
FORCEINLINE bool HasMeshShader() const { return AllStages[SF_Mesh] != nullptr; }
|
|
FORCEINLINE bool HasGeometry() const { return AllStages[SF_Geometry] != nullptr; }
|
|
FORCEINLINE bool HasPixelShader() const { return AllStages[SF_Pixel] != nullptr; }
|
|
|
|
FORCEINLINE const FShaderType* GetShader(EShaderFrequency Frequency) const
|
|
{
|
|
check(Frequency < SF_NumFrequencies);
|
|
return AllStages[Frequency];
|
|
}
|
|
|
|
FORCEINLINE FName GetFName() const { return TypeName; }
|
|
FORCEINLINE TCHAR const* GetName() const { return Name; }
|
|
FORCEINLINE const FHashedName& GetHashedName() const { return HashedName; }
|
|
FORCEINLINE const FHashedName& GetHashedPrimaryShaderFilename() const { return HashedPrimaryShaderFilename; }
|
|
|
|
// Returns an array of valid stages, sorted from PS->GS->DS->HS->VS, no gaps if missing stages
|
|
FORCEINLINE const TArray<const FShaderType*>& GetStages() const { return Stages; }
|
|
|
|
static RENDERCORE_API TLinkedList<FShaderPipelineType*>*& GetTypeList();
|
|
|
|
static RENDERCORE_API const TArray<FShaderPipelineType*>& GetSortedTypes(FShaderType::EShaderTypeForDynamicCast Type);
|
|
|
|
/** @return The global shader pipeline name to type map */
|
|
static RENDERCORE_API TMap<FHashedName, FShaderPipelineType*>& GetNameToTypeMap();
|
|
static RENDERCORE_API const FShaderPipelineType* GetShaderPipelineTypeByName(const FHashedName& Name);
|
|
|
|
/** Initialize static members, this must be called before any shader types are created. */
|
|
static RENDERCORE_API void Initialize();
|
|
|
|
static RENDERCORE_API TArray<const FShaderPipelineType*> GetShaderPipelineTypesByFilename(const TCHAR* Filename, bool bSearchAsRegexFilter = false);
|
|
static RENDERCORE_API TArray<const FShaderPipelineType*> GetShaderPipelineTypesByFilenameFilter(const TFunction<bool(const TCHAR*)>& InFilenameFilter);
|
|
|
|
/** Serializes a shader type reference by name. */
|
|
RENDERCORE_API friend FArchive& operator<<(FArchive& Ar, const FShaderPipelineType*& Ref);
|
|
|
|
/** Hashes a pointer to a shader type. */
|
|
friend uint32 GetTypeHash(FShaderPipelineType* Ref) { return Ref ? Ref->HashIndex : 0; }
|
|
friend uint32 GetTypeHash(const FShaderPipelineType* Ref) { return Ref ? Ref->HashIndex : 0; }
|
|
|
|
// Check if this pipeline is built of specific types
|
|
bool IsGlobalTypePipeline() const { return Stages[0]->GetGlobalShaderType() != nullptr; }
|
|
bool IsMaterialTypePipeline() const { return Stages[0]->GetMaterialShaderType() != nullptr; }
|
|
bool IsMeshMaterialTypePipeline() const { return Stages[0]->GetMeshMaterialShaderType() != nullptr; }
|
|
|
|
RENDERCORE_API bool ShouldOptimizeUnusedOutputs(EShaderPlatform Platform) const;
|
|
|
|
/** Calculates a Hash based on this shader pipeline type stages' source code and includes */
|
|
RENDERCORE_API const FSHAHash& GetSourceHash(EShaderPlatform ShaderPlatform) const;
|
|
|
|
RENDERCORE_API bool ShouldCompilePermutation(const FShaderPermutationParameters& Parameters) const;
|
|
|
|
RENDERCORE_API EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FShaderPermutationParameters& Parameters) const;
|
|
|
|
protected:
|
|
const TCHAR* const Name;
|
|
FName TypeName;
|
|
FHashedName HashedName;
|
|
FHashedName HashedPrimaryShaderFilename;
|
|
|
|
// Pipeline Stages, ordered from lowest (usually PS) to highest (VS). Guaranteed at least one stage (for VS).
|
|
TArray<const FShaderType*> Stages;
|
|
|
|
const FShaderType* AllStages[SF_NumFrequencies];
|
|
|
|
TLinkedList<FShaderPipelineType*> GlobalListLink;
|
|
|
|
uint32 HashIndex;
|
|
bool bShouldOptimizeUnusedOutputs;
|
|
|
|
static RENDERCORE_API bool bInitialized;
|
|
};
|
|
|
|
#if !UE_BUILD_DOCS
|
|
// Vertex+Pixel
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_VSPS(PipelineName, VertexShaderType, PixelShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &VertexShaderType::GetStaticType(), nullptr, &PixelShaderType::GetStaticType(), false, bRemoveUnused);
|
|
// Only VS
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_VS(PipelineName, VertexShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &VertexShaderType::GetStaticType(), nullptr, nullptr, false, bRemoveUnused);
|
|
// Vertex+Geometry+Pixel
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_VSGSPS(PipelineName, VertexShaderType, GeometryShaderType, PixelShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &VertexShaderType::GetStaticType(), &GeometryShaderType::GetStaticType(), &PixelShaderType::GetStaticType(), false, bRemoveUnused);
|
|
// Vertex+Geometry
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_VSGS(PipelineName, VertexShaderType, GeometryShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &VertexShaderType::GetStaticType(), &GeometryShaderType::GetStaticType(), nullptr, false, bRemoveUnused);
|
|
|
|
// Mesh+Pixel
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_MSPS(PipelineName, MeshShaderType, PixelShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &MeshShaderType::GetStaticType(), nullptr, &PixelShaderType::GetStaticType(), true, bRemoveUnused);
|
|
// Mesh+Amplification+Pixel
|
|
#define IMPLEMENT_SHADERPIPELINE_TYPE_MSASPS(PipelineName, MeshShaderType, AmplificationShaderType, PixelShaderType, bRemoveUnused) \
|
|
static FShaderPipelineType PipelineName(TEXT(PREPROCESSOR_TO_STRING(PipelineName)), &MeshShaderType::GetStaticType(), &AmplificationShaderType::GetStaticType(), &PixelShaderType::GetStaticType(), true, bRemoveUnused);
|
|
#endif
|
|
|
|
/** Encapsulates a dependency on a shader type and saved state from that shader type. */
|
|
class FShaderTypeDependency
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderTypeDependency, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
|
|
FShaderTypeDependency()
|
|
: PermutationId(0)
|
|
{}
|
|
|
|
FShaderTypeDependency(FShaderType* InShaderType, EShaderPlatform ShaderPlatform)
|
|
: ShaderTypeName(InShaderType->GetHashedName())
|
|
, PermutationId(0)
|
|
{
|
|
if (InShaderType)
|
|
{
|
|
SourceHash = InShaderType->GetSourceHash(ShaderPlatform);
|
|
}
|
|
}
|
|
|
|
friend FArchive& operator<<(FArchive& Ar,class FShaderTypeDependency& Ref)
|
|
{
|
|
Ar.UsingCustomVersion(FRenderingObjectVersion::GUID);
|
|
|
|
Ar << Ref.ShaderTypeName;
|
|
Ar << Ref.SourceHash;
|
|
|
|
if (Ar.CustomVer(FRenderingObjectVersion::GUID) >= FRenderingObjectVersion::ShaderPermutationId)
|
|
{
|
|
Ar << Ref.PermutationId;
|
|
}
|
|
|
|
return Ar;
|
|
}
|
|
|
|
bool operator==(const FShaderTypeDependency& Reference) const
|
|
{
|
|
return ShaderTypeName == Reference.ShaderTypeName && PermutationId == Reference.PermutationId && SourceHash == Reference.SourceHash;
|
|
}
|
|
|
|
bool operator!=(const FShaderTypeDependency& Reference) const
|
|
{
|
|
return !(*this == Reference);
|
|
}
|
|
|
|
/** Call GetShaderFileHash to get the cached value for the filename's hash in the current process. */
|
|
RENDERCORE_API void RefreshCachedSourceHash(EShaderPlatform ShaderPlatform);
|
|
|
|
/** Shader type */
|
|
LAYOUT_FIELD(FHashedName, ShaderTypeName);
|
|
|
|
/** Unique permutation identifier of the global shader type. */
|
|
LAYOUT_FIELD(int32, PermutationId);
|
|
|
|
/** Used to detect changes to the shader source files. This is always present, as this type is sometimes frozen. */
|
|
LAYOUT_FIELD(FSHAHash, SourceHash);
|
|
|
|
private:
|
|
#if WITH_EDITOR
|
|
// Compact binary API with hidden friend operator<<
|
|
RENDERCORE_API void Save(FCbWriter& Writer) const;
|
|
bool TryLoad(FCbFieldView Field);
|
|
friend inline FCbWriter& operator<<(FCbWriter& Writer, const FShaderTypeDependency& Value)
|
|
{
|
|
Value.Save(Writer);
|
|
return Writer;
|
|
}
|
|
friend RENDERCORE_API bool LoadFromCompactBinary(FCbFieldView Field, FShaderTypeDependency& OutValue);
|
|
#endif
|
|
};
|
|
|
|
|
|
class FShaderPipelineTypeDependency
|
|
{
|
|
public:
|
|
FShaderPipelineTypeDependency() {}
|
|
FShaderPipelineTypeDependency(const FShaderPipelineType* InShaderPipelineType, EShaderPlatform ShaderPlatform) :
|
|
ShaderPipelineTypeName(InShaderPipelineType->GetHashedName())
|
|
{
|
|
if (InShaderPipelineType)
|
|
{
|
|
StagesSourceHash = InShaderPipelineType->GetSourceHash(ShaderPlatform);
|
|
}
|
|
}
|
|
|
|
/** Shader Pipeline type */
|
|
FHashedName ShaderPipelineTypeName;
|
|
|
|
/** Used to detect changes to the shader source files. */
|
|
FSHAHash StagesSourceHash;
|
|
|
|
friend FArchive& operator<<(FArchive& Ar, class FShaderPipelineTypeDependency& Ref)
|
|
{
|
|
Ar << Ref.ShaderPipelineTypeName;
|
|
Ar << Ref.StagesSourceHash;
|
|
return Ar;
|
|
}
|
|
|
|
bool operator==(const FShaderPipelineTypeDependency& Reference) const
|
|
{
|
|
return ShaderPipelineTypeName == Reference.ShaderPipelineTypeName && StagesSourceHash == Reference.StagesSourceHash;
|
|
}
|
|
|
|
bool operator!=(const FShaderPipelineTypeDependency& Reference) const
|
|
{
|
|
return !(*this == Reference);
|
|
}
|
|
|
|
/** Call GetShaderFileHash to get the cached value for the filename's hash in the current process. */
|
|
RENDERCORE_API void RefreshCachedSourceHash(EShaderPlatform ShaderPlatform);
|
|
|
|
private:
|
|
#if WITH_EDITOR
|
|
// Compact binary API with hidden friend operator<<
|
|
RENDERCORE_API void Save(FCbWriter& Writer) const;
|
|
bool TryLoad(FCbFieldView Field);
|
|
friend inline FCbWriter& operator<<(FCbWriter& Writer, const FShaderPipelineTypeDependency& Value)
|
|
{
|
|
Value.Save(Writer);
|
|
return Writer;
|
|
}
|
|
friend RENDERCORE_API bool LoadFromCompactBinary(FCbFieldView Field, FShaderPipelineTypeDependency& OutValue);
|
|
#endif
|
|
};
|
|
|
|
/** Used to compare two shader types by name. */
|
|
class FCompareShaderTypes
|
|
{
|
|
public:
|
|
FORCEINLINE bool operator()(const FShaderType& A, const FShaderType& B ) const
|
|
{
|
|
int32 AL = FCString::Strlen(A.GetName());
|
|
int32 BL = FCString::Strlen(B.GetName());
|
|
if ( AL == BL )
|
|
{
|
|
return FCString::Strncmp(A.GetName(), B.GetName(), AL) > 0;
|
|
}
|
|
return AL > BL;
|
|
}
|
|
};
|
|
|
|
|
|
// A Shader Pipeline instance with compiled stages
|
|
class FShaderPipeline
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderPipeline, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
explicit FShaderPipeline(const FShaderPipelineType* InType) : TypeName(InType->GetHashedName()) { FMemory::Memzero(&PermutationIds, sizeof(PermutationIds)); }
|
|
RENDERCORE_API ~FShaderPipeline();
|
|
|
|
RENDERCORE_API void AddShader(FShader* Shader, int32 PermutationId);
|
|
RENDERCORE_API FShader* FindOrAddShader(FShader* Shader, int32 PermutationId);
|
|
|
|
inline uint32 GetNumShaders() const
|
|
{
|
|
uint32 NumShaders = 0u;
|
|
for (uint32 i = 0u; i < SF_NumGraphicsFrequencies; ++i)
|
|
{
|
|
if (Shaders[i].IsValid())
|
|
{
|
|
++NumShaders;
|
|
}
|
|
}
|
|
return NumShaders;
|
|
}
|
|
|
|
// Find a shader inside the pipeline
|
|
template<typename ShaderType>
|
|
ShaderType* GetShader(const FShaderMapPointerTable& InPtrTable)
|
|
{
|
|
const FShaderType& Type = ShaderType::GetStaticType();
|
|
const EShaderFrequency Frequency = Type.GetFrequency();
|
|
if (Frequency < SF_NumGraphicsFrequencies && Shaders[Frequency].IsValid())
|
|
{
|
|
FShader* Shader = Shaders[Frequency].GetChecked();
|
|
if (Shader->GetType(InPtrTable) == &Type)
|
|
{
|
|
return static_cast<ShaderType*>(Shader);
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
FShader* GetShader(EShaderFrequency Frequency)
|
|
{
|
|
check(Frequency < SF_NumGraphicsFrequencies);
|
|
return Shaders[Frequency];
|
|
}
|
|
|
|
const FShader* GetShader(EShaderFrequency Frequency) const
|
|
{
|
|
check(Frequency < SF_NumGraphicsFrequencies);
|
|
return Shaders[Frequency];
|
|
}
|
|
|
|
inline TArray<TShaderRef<FShader>> GetShaders(const FShaderMapBase& InShaderMap) const
|
|
{
|
|
TArray<TShaderRef<FShader>> Result;
|
|
for (uint32 i = 0u; i < SF_NumGraphicsFrequencies; ++i)
|
|
{
|
|
if (Shaders[i].IsValid())
|
|
{
|
|
Result.Add(TShaderRef<FShader>(Shaders[i].GetChecked(), InShaderMap));
|
|
}
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
RENDERCORE_API void Validate(const FShaderPipelineType* InPipelineType) const;
|
|
|
|
RENDERCORE_API void Finalize(const FShaderMapResourceCode* Code);
|
|
|
|
enum EFilter
|
|
{
|
|
EAll, // All pipelines
|
|
EOnlyShared, // Only pipelines with shared shaders
|
|
EOnlyUnique, // Only pipelines with unique shaders
|
|
};
|
|
|
|
/** Saves stable keys for the shaders in the pipeline */
|
|
#if WITH_EDITOR
|
|
RENDERCORE_API void SaveShaderStableKeys(const FShaderMapPointerTable& InPtrTable, EShaderPlatform TargetShaderPlatform, const struct FStableShaderKeyAndValue& SaveKeyVal) const;
|
|
#endif // WITH_EDITOR
|
|
|
|
LAYOUT_FIELD(FHashedName, TypeName);
|
|
LAYOUT_ARRAY(TMemoryImagePtr<FShader>, Shaders, SF_NumGraphicsFrequencies);
|
|
LAYOUT_ARRAY(int32, PermutationIds, SF_NumGraphicsFrequencies);
|
|
};
|
|
|
|
inline bool operator<(const FShaderPipeline& Lhs, const FShaderPipeline& Rhs)
|
|
{
|
|
return Lhs.TypeName.GetHash() < Rhs.TypeName.GetHash();
|
|
}
|
|
|
|
class FShaderPipelineRef
|
|
{
|
|
public:
|
|
FShaderPipelineRef() : ShaderPipeline(nullptr), ShaderMap(nullptr) {}
|
|
FShaderPipelineRef(FShaderPipeline* InPipeline, const FShaderMapBase& InShaderMap) : ShaderPipeline(InPipeline), ShaderMap(&InShaderMap) { checkSlow(InPipeline); }
|
|
|
|
inline bool IsValid() const { return ShaderPipeline != nullptr; }
|
|
inline bool IsNull() const { return ShaderPipeline == nullptr; }
|
|
|
|
template<typename ShaderType>
|
|
TShaderRef<ShaderType> GetShader() const
|
|
{
|
|
return TShaderRef<ShaderType>(ShaderPipeline->GetShader<ShaderType>(GetPointerTable()), *ShaderMap);
|
|
}
|
|
|
|
TShaderRef<FShader> GetShader(EShaderFrequency Frequency) const
|
|
{
|
|
return TShaderRef<FShader>(ShaderPipeline->GetShader(Frequency), *ShaderMap);
|
|
}
|
|
|
|
inline TArray<TShaderRef<FShader>> GetShaders() const
|
|
{
|
|
return ShaderPipeline->GetShaders(*ShaderMap);
|
|
}
|
|
|
|
inline FShaderPipeline* GetPipeline() const { return ShaderPipeline; }
|
|
FShaderMapResource* GetResource() const;
|
|
const FShaderMapPointerTable& GetPointerTable() const;
|
|
|
|
inline FShaderPipeline* operator->() const { check(ShaderPipeline); return ShaderPipeline; }
|
|
|
|
private:
|
|
FShaderPipeline* ShaderPipeline;
|
|
const FShaderMapBase* ShaderMap;
|
|
};
|
|
|
|
DECLARE_DELEGATE_EightParams(FShaderListReport, const TCHAR*, const TCHAR*, const TCHAR*, const TCHAR*, uint32, uint32, const TCHAR*, void*);
|
|
|
|
/** A collection of shaders of different types */
|
|
class FShaderMapContent
|
|
{
|
|
DECLARE_EXPORTED_TYPE_LAYOUT(FShaderMapContent, RENDERCORE_API, NonVirtual);
|
|
public:
|
|
struct FProjectShaderPipelineToKey
|
|
{
|
|
inline FHashedName operator()(const FShaderPipeline* InShaderPipeline) { return InShaderPipeline->TypeName; }
|
|
};
|
|
|
|
/** Default constructor. */
|
|
RENDERCORE_API explicit FShaderMapContent(EShaderPlatform InPlatform);
|
|
|
|
/** Destructor ensures pipelines cleared up. */
|
|
RENDERCORE_API ~FShaderMapContent();
|
|
|
|
RENDERCORE_API EShaderPlatform GetShaderPlatform() const;
|
|
|
|
RENDERCORE_API void Validate(const FShaderMapBase& InShaderMap) const;
|
|
|
|
/** Finds the shader with the given type. Asserts on failure. */
|
|
template<typename ShaderType>
|
|
ShaderType* GetShader(int32 PermutationId = 0) const
|
|
{
|
|
FShader* Shader = GetShader(&ShaderType::GetStaticType(), PermutationId);
|
|
checkf(Shader != nullptr, TEXT("Failed to find shader type %s in Platform %s"), ShaderType::GetStaticType().GetName(), *LegacyShaderPlatformToShaderFormat(GetShaderPlatform()).ToString());
|
|
return static_cast<ShaderType*>(Shader);
|
|
}
|
|
|
|
/** Finds the shader with the given type. Asserts on failure. */
|
|
template<typename ShaderType>
|
|
ShaderType* GetShader( const typename ShaderType::FPermutationDomain& PermutationVector ) const
|
|
{
|
|
return GetShader<ShaderType>( PermutationVector.ToDimensionValueId() );
|
|
}
|
|
|
|
/** Finds the shader with the given type. May return NULL. */
|
|
FShader* GetShader(const FShaderType* ShaderType, int32 PermutationId = 0) const
|
|
{
|
|
return GetShader(ShaderType->GetHashedName(), PermutationId);
|
|
}
|
|
|
|
/** Finds the shader with the given type name. May return NULL. */
|
|
RENDERCORE_API FShader* GetShader(const FHashedName& TypeName, int32 PermutationId = 0) const;
|
|
|
|
/** Finds the shader with the given type. */
|
|
bool HasShader(const FHashedName& TypeName, int32 PermutationId) const
|
|
{
|
|
const FShader* Shader = GetShader(TypeName, PermutationId);
|
|
return Shader != nullptr;
|
|
}
|
|
|
|
bool HasShader(const FShaderType* Type, int32 PermutationId) const
|
|
{
|
|
return HasShader(Type->GetHashedName(), PermutationId);
|
|
}
|
|
|
|
inline TArrayView<const TMemoryImagePtr<FShader>> GetShaders() const
|
|
{
|
|
return Shaders;
|
|
}
|
|
|
|
inline TArrayView<const TMemoryImagePtr<FShaderPipeline>> GetShaderPipelines() const
|
|
{
|
|
return ShaderPipelines;
|
|
}
|
|
|
|
RENDERCORE_API void AddShader(const FHashedName& TypeName, int32 PermutationId, FShader* Shader);
|
|
|
|
RENDERCORE_API FShader* FindOrAddShader(const FHashedName& TypeName, int32 PermutationId, FShader* Shader);
|
|
|
|
RENDERCORE_API void AddShaderPipeline(FShaderPipeline* Pipeline);
|
|
|
|
RENDERCORE_API FShaderPipeline* FindOrAddShaderPipeline(FShaderPipeline* Pipeline);
|
|
|
|
/**
|
|
* Removes the shader of the given type from the shader map
|
|
* @param Type Shader type to remove the entry for
|
|
*/
|
|
RENDERCORE_API void RemoveShaderTypePermutaion(const FHashedName& TypeName, int32 PermutationId);
|
|
|
|
inline void RemoveShaderTypePermutaion(const FShaderType* Type, int32 PermutationId)
|
|
{
|
|
RemoveShaderTypePermutaion(Type->GetHashedName(), PermutationId);
|
|
}
|
|
|
|
RENDERCORE_API void RemoveShaderPipelineType(const FShaderPipelineType* ShaderPipelineType);
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
RENDERCORE_API void DumpShaderList(const FShaderMapBase& InShaderMap, FShaderListReport& Out) const;
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
/** Builds a list of the shaders in a shader map. */
|
|
RENDERCORE_API void GetShaderList(const FShaderMapBase& InShaderMap, const FSHAHash& InMaterialShaderMapHash, TMap<FShaderId, TShaderRef<FShader>>& OutShaders) const;
|
|
|
|
/** Builds a list of the shaders in a shader map. Key is FShaderType::TypeName */
|
|
RENDERCORE_API void GetShaderList(const FShaderMapBase& InShaderMap, TMap<FHashedName, TShaderRef<FShader>>& OutShaders) const;
|
|
|
|
/** Builds a list of the shader pipelines in a shader map. */
|
|
RENDERCORE_API void GetShaderPipelineList(const FShaderMapBase& InShaderMap, TArray<FShaderPipelineRef>& OutShaderPipelines, FShaderPipeline::EFilter Filter) const;
|
|
|
|
#if WITH_EDITOR
|
|
RENDERCORE_API uint32 GetMaxTextureSamplersShaderMap(const FShaderMapBase& InShaderMap) const;
|
|
|
|
RENDERCORE_API void GetOutdatedTypes(const FShaderMapBase& InShaderMap, TArray<const FShaderType*>& OutdatedShaderTypes, TArray<const FShaderPipelineType*>& OutdatedShaderPipelineTypes, TArray<const FVertexFactoryType*>& OutdatedFactoryTypes) const;
|
|
|
|
RENDERCORE_API void SaveShaderStableKeys(const FShaderMapBase& InShaderMap, EShaderPlatform TargetShaderPlatform, const struct FStableShaderKeyAndValue& SaveKeyVal);
|
|
#endif // WITH_EDITOR
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
RENDERCORE_API TArray<FGenericShaderStat> GetShaderStatistics(const FShaderMapBase& InShaderMap, FShaderType* ShaderType) const;
|
|
#endif // WITH_EDITORONLY_DATA
|
|
|
|
/** @return true if the map is empty */
|
|
inline bool IsEmpty() const
|
|
{
|
|
return Shaders.Num() == 0;
|
|
}
|
|
|
|
/** @return The number of shaders in the map. */
|
|
RENDERCORE_API uint32 GetNumShaders() const;
|
|
|
|
/** @return The number of shader pipelines in the map. */
|
|
inline uint32 GetNumShaderPipelines() const
|
|
{
|
|
return ShaderPipelines.Num();
|
|
}
|
|
|
|
/** clears out all shaders and deletes shader pipelines held in the map */
|
|
RENDERCORE_API void Empty();
|
|
|
|
inline FShaderPipeline* GetShaderPipeline(const FHashedName& PipelineTypeName) const
|
|
{
|
|
const int32 Index = Algo::BinarySearchBy(ShaderPipelines, PipelineTypeName, FProjectShaderPipelineToKey());
|
|
return (Index != INDEX_NONE) ? ShaderPipelines[Index].Get() : nullptr;
|
|
}
|
|
|
|
inline FShaderPipeline* GetShaderPipeline(const FShaderPipelineType* PipelineType) const
|
|
{
|
|
return GetShaderPipeline(PipelineType->GetHashedName());
|
|
}
|
|
|
|
inline bool HasShaderPipeline(const FHashedName& PipelineTypeName) const { return GetShaderPipeline(PipelineTypeName) != nullptr; }
|
|
inline bool HasShaderPipeline(const FShaderPipelineType* PipelineType) const { return (GetShaderPipeline(PipelineType) != nullptr); }
|
|
|
|
RENDERCORE_API uint32 GetMaxNumInstructionsForShader(const FShaderMapBase& InShaderMap, FShaderType* ShaderType) const;
|
|
|
|
RENDERCORE_API void Finalize(const FShaderMapResourceCode* Code);
|
|
|
|
RENDERCORE_API void UpdateHash(FSHA1& Hasher) const;
|
|
|
|
protected:
|
|
RENDERCORE_API void EmptyShaderPipelines();
|
|
|
|
using FMemoryImageHashTable = THashTable<FMemoryImageAllocator>;
|
|
|
|
LAYOUT_FIELD(FMemoryImageHashTable, ShaderHash);
|
|
LAYOUT_FIELD(TMemoryImageArray<FHashedName>, ShaderTypes);
|
|
LAYOUT_FIELD(TMemoryImageArray<int32>, ShaderPermutations);
|
|
LAYOUT_FIELD(TMemoryImageArray<TMemoryImagePtr<FShader>>, Shaders);
|
|
LAYOUT_FIELD(TMemoryImageArray<TMemoryImagePtr<FShaderPipeline>>, ShaderPipelines);
|
|
/** The ShaderPlatform Name this shader map was compiled with */
|
|
LAYOUT_FIELD(FMemoryImageName, ShaderPlatformName);
|
|
};
|
|
|
|
class FShaderMapBase
|
|
{
|
|
public:
|
|
RENDERCORE_API virtual ~FShaderMapBase();
|
|
|
|
RENDERCORE_API FShaderMapResourceCode* GetResourceCode();
|
|
|
|
inline FShaderMapResource* GetResource() const { return Resource; }
|
|
inline FShaderMapResource* GetResourceChecked() const { check(Resource); return Resource; }
|
|
inline const FShaderMapPointerTable& GetPointerTable() const { check(PointerTable); return *PointerTable; }
|
|
inline const FShaderMapContent* GetContent() const { return Content.Object; }
|
|
inline FShaderMapContent* GetMutableContent()
|
|
{
|
|
UnfreezeContent();
|
|
return Content.Object;
|
|
}
|
|
/** Builds a list of the shaders in a shader map. Key is FShaderType::TypeName */
|
|
virtual void GetShaderList(TMap<FHashedName, TShaderRef<FShader>>& OutShaders) const = 0;
|
|
virtual void GetShaderPipelineList(TArray<FShaderPipelineRef>& OutShaderPipelines) const = 0;
|
|
|
|
#if !UE_BUILD_SHIPPING
|
|
virtual void DumpShaderList(FShaderListReport& Out) const
|
|
{
|
|
GetContent()->DumpShaderList(*this, Out);
|
|
}
|
|
#endif // !UE_BUILD_SHIPPING
|
|
|
|
inline EShaderPlatform GetShaderPlatform() const { return Content.Object ? Content.Object->GetShaderPlatform() : SP_NumPlatforms; }
|
|
inline uint32 GetFrozenContentSize() const { return Content.FrozenSize; }
|
|
|
|
RENDERCORE_API void AssignContent(TMemoryImageObject<FShaderMapContent> InContent);
|
|
|
|
RENDERCORE_API void FinalizeContent();
|
|
RENDERCORE_API void UnfreezeContent();
|
|
RENDERCORE_API bool Serialize(FShaderSerializeContext& Ctx);
|
|
|
|
EShaderPermutationFlags GetPermutationFlags() const
|
|
{
|
|
return PermutationFlags;
|
|
}
|
|
|
|
RENDERCORE_API FString ToString() const;
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
RENDERCORE_API TArray<FGenericShaderStat> GetShaderStatistics(FShaderType* ShaderType) const;
|
|
RENDERCORE_API TArray<FGenericShaderStat> GetShaderStatistics(FShader& Shader) const;
|
|
#endif
|
|
|
|
#if WITH_EDITOR
|
|
inline void GetOutdatedTypes(TArray<const FShaderType*>& OutdatedShaderTypes, TArray<const FShaderPipelineType*>& OutdatedShaderPipelineTypes, TArray<const FVertexFactoryType*>& OutdatedFactoryTypes) const
|
|
{
|
|
Content.Object->GetOutdatedTypes(*this, OutdatedShaderTypes, OutdatedShaderPipelineTypes, OutdatedFactoryTypes);
|
|
}
|
|
void SaveShaderStableKeys(EShaderPlatform TargetShaderPlatform, const struct FStableShaderKeyAndValue& SaveKeyVal)
|
|
{
|
|
Content.Object->SaveShaderStableKeys(*this, TargetShaderPlatform, SaveKeyVal);
|
|
}
|
|
|
|
/** Associates a shadermap with an asset (note: one shadermap can be used by several assets, e.g. MIs).
|
|
* This helps cooker lay out the shadermaps (and shaders) in the file open order, if provided. Maps not associated with any assets
|
|
* may be placed after all maps associated with known assets. Global shadermaps need to be associated with a "Global" asset */
|
|
void AssociateWithAsset(const FName& AssetPath)
|
|
{
|
|
AssociatedAssets.Add(AssetPath);
|
|
}
|
|
|
|
void AssociateWithAssets(const FShaderMapAssetPaths& AssetPaths)
|
|
{
|
|
AssociatedAssets.Append(AssetPaths);
|
|
}
|
|
|
|
const FShaderMapAssetPaths& GetAssociatedAssets() const
|
|
{
|
|
return AssociatedAssets;
|
|
}
|
|
#endif // WITH_EDITOR
|
|
|
|
protected:
|
|
RENDERCORE_API FShaderMapBase();
|
|
|
|
RENDERCORE_API void AssignCopy(const FShaderMapBase& Source);
|
|
|
|
RENDERCORE_API void InitResource();
|
|
RENDERCORE_API void DestroyContent();
|
|
|
|
protected:
|
|
virtual const FTypeLayoutDesc& GetContentTypeDesc() const = 0;
|
|
virtual FShaderMapPointerTable* CreatePointerTable() const = 0;
|
|
virtual void PostFinalizeContent() { }
|
|
|
|
private:
|
|
#if WITH_EDITOR
|
|
/** List of the assets that are using this shadermap. This is only available in the editor (cooker) to influence ordering of shader libraries. */
|
|
FShaderMapAssetPaths AssociatedAssets;
|
|
#endif
|
|
TRefCountPtr<FShaderMapResource> Resource;
|
|
TRefCountPtr<FShaderMapResourceCode> Code;
|
|
FShaderMapPointerTable* PointerTable;
|
|
TMemoryImageObject<FShaderMapContent> Content;
|
|
uint32 NumFrozenShaders;
|
|
EShaderPermutationFlags PermutationFlags;
|
|
};
|
|
|
|
template<typename ContentType, typename PointerTableType = FShaderMapPointerTable>
|
|
class TShaderMap : public FShaderMapBase
|
|
{
|
|
public:
|
|
inline const PointerTableType& GetPointerTable() const { return static_cast<const PointerTableType&>(FShaderMapBase::GetPointerTable()); }
|
|
inline const ContentType* GetContent() const { return static_cast<const ContentType*>(FShaderMapBase::GetContent()); }
|
|
inline ContentType* GetMutableContent() { return static_cast<ContentType*>(FShaderMapBase::GetMutableContent()); }
|
|
|
|
void FinalizeContent()
|
|
{
|
|
ContentType* LocalContent = this->GetMutableContent();
|
|
check(LocalContent);
|
|
LocalContent->Finalize(this->GetResourceCode());
|
|
LocalContent->Validate(*this);
|
|
FShaderMapBase::FinalizeContent();
|
|
}
|
|
|
|
protected:
|
|
virtual const FTypeLayoutDesc& GetContentTypeDesc() const final override { return StaticGetTypeLayoutDesc<ContentType>(); }
|
|
virtual FShaderMapPointerTable* CreatePointerTable() const final override { return new PointerTableType(); }
|
|
};
|
|
|
|
template<typename ShaderType, typename PointerTableType>
|
|
inline const PointerTableType& TShaderRefBase<ShaderType, PointerTableType>::GetPointerTable() const
|
|
{
|
|
checkSlow(ShaderMap);
|
|
return static_cast<const PointerTableType&>(ShaderMap->GetPointerTable());
|
|
}
|
|
|
|
template<typename ShaderType, typename PointerTableType>
|
|
inline FShaderMapResource* TShaderRefBase<ShaderType, PointerTableType>::GetResource() const
|
|
{
|
|
checkSlow(ShaderMap);
|
|
return ShaderMap->GetResource();
|
|
}
|
|
|
|
inline const FShaderMapPointerTable& FShaderPipelineRef::GetPointerTable() const
|
|
{
|
|
checkSlow(ShaderMap);
|
|
return ShaderMap->GetPointerTable();
|
|
}
|
|
|
|
inline FShaderMapResource* FShaderPipelineRef::GetResource() const
|
|
{
|
|
checkSlow(ShaderMap);
|
|
return ShaderMap->GetResource();
|
|
}
|
|
|
|
/** A reference which is initialized with the requested shader type from a shader map. */
|
|
template<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(
|
|
std::is_same_v<typename ShaderType::FPermutationDomain, FShaderPermutationNone>,
|
|
"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
|
|
{ }
|
|
};
|
|
|
|
/** A reference to an optional shader, initialized with a shader type from a shader map if it is available or nullptr if it is not. */
|
|
template<typename ShaderType>
|
|
class TOptionalShaderMapRef : public TShaderRef<ShaderType>
|
|
{
|
|
public:
|
|
TOptionalShaderMapRef(const typename ShaderType::ShaderMapType* ShaderIndex):
|
|
TShaderRef<ShaderType>(TShaderRef<ShaderType>::Cast(ShaderIndex->GetShader(&ShaderType::GetStaticType()))) // gcc3 needs the template quantifier so it knows the < is not a less-than
|
|
{}
|
|
};
|
|
|
|
/**
|
|
* Dumps shader stats to the log. Will also print some shader pipeline information.
|
|
* @param Platform - Platform to dump shader info for, use SP_NumPlatforms for all
|
|
* @param Frequency - Whether to dump PS or VS info, use SF_NumFrequencies to dump both
|
|
*/
|
|
extern RENDERCORE_API void DumpShaderStats( EShaderPlatform Platform, EShaderFrequency Frequency );
|
|
|
|
/**
|
|
* Dumps shader pipeline stats to the log. Does not include material (eg shader pipeline instance) information.
|
|
* @param Platform - Platform to dump shader info for, use SP_NumPlatforms for all
|
|
*/
|
|
extern RENDERCORE_API void DumpShaderPipelineStats(EShaderPlatform Platform);
|
|
|
|
/**
|
|
* Finds the shader type with a given name.
|
|
* @param ShaderTypeName - The name of the shader type to find.
|
|
* @return The shader type, or NULL if none matched.
|
|
*/
|
|
extern RENDERCORE_API FShaderType* FindShaderTypeByName(const FHashedName& ShaderTypeName);
|
|
|
|
/** Helper function to dispatch a compute shader while checking that parameters have been set correctly. */
|
|
extern RENDERCORE_API void DispatchComputeShader(
|
|
FRHIComputeCommandList& RHICmdList,
|
|
FShader* Shader,
|
|
uint32 ThreadGroupCountX,
|
|
uint32 ThreadGroupCountY,
|
|
uint32 ThreadGroupCountZ);
|
|
|
|
/** Helper function to dispatch a compute shader indirectly while checking that parameters have been set correctly. */
|
|
extern RENDERCORE_API void DispatchIndirectComputeShader(
|
|
FRHIComputeCommandList& RHICmdList,
|
|
FShader* Shader,
|
|
FRHIBuffer* ArgumentBuffer,
|
|
uint32 ArgumentOffset);
|
|
|
|
inline void DispatchComputeShader(
|
|
FRHIComputeCommandList& RHICmdList,
|
|
const TShaderRef<FShader>& Shader,
|
|
uint32 ThreadGroupCountX,
|
|
uint32 ThreadGroupCountY,
|
|
uint32 ThreadGroupCountZ)
|
|
{
|
|
DispatchComputeShader(RHICmdList, Shader.GetShader(), ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ);
|
|
}
|
|
|
|
/** Returns whether the platform is using emulated uniform buffers */
|
|
extern RENDERCORE_API bool IsUsingEmulatedUniformBuffers(EShaderPlatform Platform);
|
|
|
|
/** Returns whether DirectXShaderCompiler (DXC) is enabled for the specified shader platform. See console variables "r.OpenGL.ForceDXC", "r.D3D.ForceDXC". */
|
|
extern RENDERCORE_API bool IsDxcEnabledForPlatform(EShaderPlatform Platform, bool bHlslVersion2021 = false);
|
|
|
|
/** Appends to KeyString for all shaders. */
|
|
extern RENDERCORE_API void ShaderMapAppendKeyString(EShaderPlatform Platform, FString& KeyString);
|
|
extern RENDERCORE_API void ShaderMapAppendKey(EShaderPlatform Platform, FShaderKeyGenerator& KeyGen);
|