Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Public/ShaderCodeLibrary.h
Arciel Rekman f6b2c6df54 Make shader library determinism optional per platform.
#rb Josh.Adams, Ben.Woodhouse
#rnx


#ROBOMERGE-OWNER: Arciel.Rekman
#ROBOMERGE-AUTHOR: arciel.rekman
#ROBOMERGE-SOURCE: CL 11450810 via CL 11452365 via CL 11452390 via CL 11452432
#ROBOMERGE-BOT: (v654-11333218)

[CL 11456136 by Arciel Rekman in Main branch]
2020-02-15 10:16:44 -05:00

228 lines
8.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
ShaderCodeLibrary.h:
=============================================================================*/
#pragma once
#include "CoreMinimal.h"
#include "Containers/ArrayView.h"
#include "RHI.h"
DECLARE_LOG_CATEGORY_EXTERN(LogShaderLibrary, Log, All);
class FAnsiStringBuilderBase;
class FShaderPipeline;
class FStringView;
class FShaderMapResource;
class FShaderMapResourceCode;
struct RENDERCORE_API FShaderCodeLibraryPipeline
{
FSHAHash VertexShader;
FSHAHash PixelShader;
FSHAHash GeometryShader;
FSHAHash HullShader;
FSHAHash DomainShader;
mutable uint32 Hash;
/** Fills the hashes from the pipeline stage shaders */
void Initialize(const FShaderPipeline* Pipeline);
FShaderCodeLibraryPipeline() : Hash(0) {}
friend bool operator ==(const FShaderCodeLibraryPipeline& A,const FShaderCodeLibraryPipeline& B)
{
return A.VertexShader == B.VertexShader && A.PixelShader == B.PixelShader && A.GeometryShader == B.GeometryShader && A.HullShader == B.HullShader && A.DomainShader == B.DomainShader;
}
friend uint32 GetTypeHash(const FShaderCodeLibraryPipeline &Key)
{
if(!Key.Hash)
{
Key.Hash = FCrc::MemCrc32(Key.VertexShader.Hash, sizeof(Key.VertexShader.Hash));
Key.Hash = FCrc::MemCrc32(Key.PixelShader.Hash, sizeof(Key.PixelShader.Hash), Key.Hash);
Key.Hash = FCrc::MemCrc32(Key.GeometryShader.Hash, sizeof(Key.GeometryShader.Hash), Key.Hash);
Key.Hash = FCrc::MemCrc32(Key.HullShader.Hash, sizeof(Key.HullShader.Hash), Key.Hash);
Key.Hash = FCrc::MemCrc32(Key.DomainShader.Hash, sizeof(Key.DomainShader.Hash), Key.Hash);
}
return Key.Hash;
}
/** Computes a longer hash that uniquely identifies the whole pipeline, used in FStableShaderKeyAndValue */
void GetPipelineHash(FSHAHash& Output);
friend FArchive& operator<<( FArchive& Ar, FShaderCodeLibraryPipeline& Info )
{
return Ar << Info.VertexShader << Info.PixelShader << Info.GeometryShader << Info.HullShader << Info.DomainShader << Info.Hash;
}
};
struct RENDERCORE_API FCompactFullName
{
TArray<FName, TInlineAllocator<16>> ObjectClassAndPath;
bool operator==(const FCompactFullName& Other) const
{
return ObjectClassAndPath == Other.ObjectClassAndPath;
}
FString ToString() const;
void AppendString(FStringBuilderBase& Out) const;
void AppendString(FAnsiStringBuilderBase& Out) const;
void ParseFromString(const FStringView& Src);
friend RENDERCORE_API uint32 GetTypeHash(const FCompactFullName& A);
};
struct RENDERCORE_API FStableShaderKeyAndValue
{
FCompactFullName ClassNameAndObjectPath;
FName ShaderType;
FName ShaderClass;
FName MaterialDomain;
FName FeatureLevel;
FName QualityLevel;
FName TargetFrequency;
FName TargetPlatform;
FName VFType;
FName PermutationId;
FSHAHash PipelineHash;
uint32 KeyHash;
FSHAHash OutputHash;
FStableShaderKeyAndValue()
: KeyHash(0)
{
}
void ComputeKeyHash();
void ParseFromString(const FStringView& Src);
void ParseFromStringCached(const FStringView& Src, class TMap<uint32, FName>& NameCache);
FString ToString() const;
void ToString(FString& OutResult) const;
void AppendString(FAnsiStringBuilderBase& Out) const;
static FString HeaderLine();
/** Computes pipeline hash from the passed pipeline. Pass nullptr to clear */
void SetPipelineHash(const FShaderPipeline* Pipeline);
friend bool operator ==(const FStableShaderKeyAndValue& A, const FStableShaderKeyAndValue& B)
{
return
A.ClassNameAndObjectPath == B.ClassNameAndObjectPath &&
A.ShaderType == B.ShaderType &&
A.ShaderClass == B.ShaderClass &&
A.MaterialDomain == B.MaterialDomain &&
A.FeatureLevel == B.FeatureLevel &&
A.QualityLevel == B.QualityLevel &&
A.TargetFrequency == B.TargetFrequency &&
A.TargetPlatform == B.TargetPlatform &&
A.VFType == B.VFType &&
A.PermutationId == B.PermutationId &&
A.PipelineHash == B.PipelineHash;
}
friend uint32 GetTypeHash(const FStableShaderKeyAndValue &Key)
{
return Key.KeyHash;
}
};
DECLARE_MULTICAST_DELEGATE_TwoParams(FSharedShaderCodeRequest, const FSHAHash&, FArchive*);
DECLARE_MULTICAST_DELEGATE_OneParam(FSharedShaderCodeRelease, const FSHAHash&);
// Collection of unique shader code
// Populated at cook time
struct RENDERCORE_API FShaderCodeLibrary
{
static void InitForRuntime(EShaderPlatform ShaderPlatform);
static void Shutdown();
static bool IsEnabled();
// Open a named library.
// For cooking this will place all added shaders & pipelines into the library file with this name.
// At runtime this will open the shader library with this name.
static bool OpenLibrary(FString const& Name, FString const& Directory);
// Close a named library.
// For cooking, after this point any AddShaderCode/AddShaderPipeline calls will be invalid until OpenLibrary is called again.
// At runtime this will release the library data and further requests for shaders from this library will fail.
static void CloseLibrary(FString const& Name);
static bool ContainsShaderCode(const FSHAHash& Hash);
static TRefCountPtr<FShaderMapResource> LoadResource(const FSHAHash& Hash, FArchive* Ar);
static bool PreloadShader(const FSHAHash& Hash, FArchive* Ar);
static FVertexShaderRHIRef CreateVertexShader(EShaderPlatform Platform, const FSHAHash& Hash);
static FPixelShaderRHIRef CreatePixelShader(EShaderPlatform Platform, const FSHAHash& Hash);
static FHullShaderRHIRef CreateHullShader(EShaderPlatform Platform, const FSHAHash& Hash);
static FDomainShaderRHIRef CreateDomainShader(EShaderPlatform Platform, const FSHAHash& Hash);
static FGeometryShaderRHIRef CreateGeometryShader(EShaderPlatform Platform, const FSHAHash& Hash);
static FComputeShaderRHIRef CreateComputeShader(EShaderPlatform Platform, const FSHAHash& Hash);
// Total number of shader entries in the library
static uint32 GetShaderCount(void);
// The shader platform that the library manages - at runtime this will only be one
static EShaderPlatform GetRuntimeShaderPlatform(void);
#if WITH_EDITOR
// Initialize the library cooker
static void InitForCooking(bool bNativeFormat);
// Clean the cook directories
static void CleanDirectories(TArray<FName> const& ShaderFormats);
struct FShaderFormatDescriptor
{
FName ShaderFormat;
bool bNeedsStableKeys;
bool bNeedsDeterministicOrder;
};
// Specify the shader formats to cook and which ones needs stable keys. Provide an array of FShaderFormatDescriptors
static void CookShaderFormats(TArray<FShaderFormatDescriptor> const& ShaderFormats);
// At cook time, add shader code to collection
static bool AddShaderCode(EShaderPlatform ShaderPlatform, const FShaderMapResourceCode* Code);
// We check this early in the callstack to avoid creating a bunch of FName and keys and things we will never save anyway.
// Pass the shader platform to check or EShaderPlatform::SP_NumPlatforms to check if any of the registered types require
// stable keys.
static bool NeedsShaderStableKeys(EShaderPlatform ShaderPlatform);
// At cook time, add the human readable key value information
static void AddShaderStableKeyValue(EShaderPlatform ShaderPlatform, FStableShaderKeyAndValue& StableKeyValue);
// Save collected shader code to a file for each specified shader platform, collating all child cooker results.
static bool SaveShaderCodeMaster(const FString& OutputDir, const FString& MetaOutputDir, const TArray<FName>& ShaderFormats, TArray<FString>& OutSCLCSVPath);
// Save collected shader code to a file for each specified shader platform, handles only this instances intermediate results.
static bool SaveShaderCodeChild(const FString& OutputDir, const FString& MetaOutputDir, const TArray<FName>& ShaderFormats);
// Package the separate shader bytecode files into a single native shader library. Must be called by the master process.
static bool PackageNativeShaderLibrary(const FString& ShaderCodeDir, const TArray<FName>& ShaderFormats);
// Dump collected stats for each shader platform
static void DumpShaderCodeStats();
// Create a smaller 'patch' library that only contains data from 'NewMetaDataDir' not contained in any of 'OldMetaDataDirs'
static bool CreatePatchLibrary(TArray<FString> const& OldMetaDataDirs, FString const& NewMetaDataDir, FString const& OutDir, bool bNativeFormat, bool bNeedsDeterministicOrder);
#endif
// Safely assign the hash to a shader object
static void SafeAssignHash(FRHIShader* InShader, const FSHAHash& Hash);
// Delegate called whenever shader code is requested.
static FDelegateHandle RegisterSharedShaderCodeRequestDelegate_Handle(const FSharedShaderCodeRequest::FDelegate& Delegate);
static void UnregisterSharedShaderCodeRequestDelegate_Handle(FDelegateHandle Handle);
};