2020-02-07 11:01:05 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2020-02-06 13:13:41 -05:00
# include "ShaderCodeArchive.h"
# include "ShaderCodeLibrary.h"
# include "Stats/Stats.h"
# include "ProfilingDebugging/LoadTimeTracker.h"
2020-06-23 18:40:00 -04:00
# include "Misc/ScopeRWLock.h"
2020-02-06 13:13:41 -05:00
# include "Misc/MemStack.h"
2020-10-22 19:19:16 -04:00
# include "Policies/PrettyJsonPrintPolicy.h"
# include "Serialization/JsonSerializer.h"
# include "Misc/FileHelper.h"
2021-06-10 09:36:47 -04:00
# include "Serialization/MemoryReader.h"
2020-12-11 14:21:20 -04:00
# if WITH_EDITOR
# include "Misc/StringBuilder.h"
# include "Templates/Greater.h"
# endif
2020-02-06 13:13:41 -05:00
int32 GShaderCodeLibraryAsyncLoadingPriority = int32 ( AIOP_Normal ) ;
static FAutoConsoleVariableRef CVarShaderCodeLibraryAsyncLoadingPriority (
TEXT ( " r.ShaderCodeLibrary.DefaultAsyncIOPriority " ) ,
GShaderCodeLibraryAsyncLoadingPriority ,
TEXT ( " " ) ,
ECVF_Default
) ;
2020-06-23 18:40:00 -04:00
int32 GShaderCodeLibraryAsyncLoadingAllowDontCache = 0 ;
static FAutoConsoleVariableRef CVarShaderCodeLibraryAsyncLoadingAllowDontCache (
TEXT ( " r.ShaderCodeLibrary.AsyncIOAllowDontCache " ) ,
GShaderCodeLibraryAsyncLoadingAllowDontCache ,
TEXT ( " " ) ,
ECVF_Default
) ;
2020-02-06 13:13:41 -05:00
int32 FSerializedShaderArchive : : FindShaderMapWithKey ( const FSHAHash & Hash , uint32 Key ) const
{
for ( uint32 Index = ShaderMapHashTable . First ( Key ) ; ShaderMapHashTable . IsValid ( Index ) ; Index = ShaderMapHashTable . Next ( Index ) )
{
if ( ShaderMapHashes [ Index ] = = Hash )
{
return Index ;
}
}
return INDEX_NONE ;
}
int32 FSerializedShaderArchive : : FindShaderMap ( const FSHAHash & Hash ) const
{
const uint32 Key = GetTypeHash ( Hash ) ;
return FindShaderMapWithKey ( Hash , Key ) ;
}
2020-10-22 19:19:16 -04:00
bool FSerializedShaderArchive : : FindOrAddShaderMap ( const FSHAHash & Hash , int32 & OutIndex , const FShaderMapAssetPaths * AssociatedAssets )
2020-02-06 13:13:41 -05:00
{
const uint32 Key = GetTypeHash ( Hash ) ;
int32 Index = FindShaderMapWithKey ( Hash , Key ) ;
bool bAdded = false ;
if ( Index = = INDEX_NONE )
{
Index = ShaderMapHashes . Add ( Hash ) ;
ShaderMapEntries . AddDefaulted ( ) ;
check ( ShaderMapEntries . Num ( ) = = ShaderMapHashes . Num ( ) ) ;
ShaderMapHashTable . Add ( Key , Index ) ;
2020-10-22 19:19:16 -04:00
# if WITH_EDITOR
if ( AssociatedAssets & & AssociatedAssets - > Num ( ) > 0 )
{
ShaderCodeToAssets . Add ( Hash , * AssociatedAssets ) ;
}
# endif
2020-02-06 13:13:41 -05:00
bAdded = true ;
}
2020-10-22 19:19:16 -04:00
else
{
# if WITH_EDITOR
// check if we need to replace or merge assets
if ( AssociatedAssets & & AssociatedAssets - > Num ( ) )
{
FShaderMapAssetPaths * PrevAssets = ShaderCodeToAssets . Find ( Hash ) ;
if ( PrevAssets )
{
int PrevAssetsNum = PrevAssets - > Num ( ) ;
PrevAssets - > Append ( * AssociatedAssets ) ;
}
else
{
ShaderCodeToAssets . Add ( Hash , * AssociatedAssets ) ;
}
}
# endif
}
2020-02-06 13:13:41 -05:00
OutIndex = Index ;
return bAdded ;
}
int32 FSerializedShaderArchive : : FindShaderWithKey ( const FSHAHash & Hash , uint32 Key ) const
{
for ( uint32 Index = ShaderHashTable . First ( Key ) ; ShaderHashTable . IsValid ( Index ) ; Index = ShaderHashTable . Next ( Index ) )
{
if ( ShaderHashes [ Index ] = = Hash )
{
return Index ;
}
}
return INDEX_NONE ;
}
int32 FSerializedShaderArchive : : FindShader ( const FSHAHash & Hash ) const
{
const uint32 Key = GetTypeHash ( Hash ) ;
return FindShaderWithKey ( Hash , Key ) ;
}
bool FSerializedShaderArchive : : FindOrAddShader ( const FSHAHash & Hash , int32 & OutIndex )
{
const uint32 Key = GetTypeHash ( Hash ) ;
int32 Index = FindShaderWithKey ( Hash , Key ) ;
bool bAdded = false ;
if ( Index = = INDEX_NONE )
{
Index = ShaderHashes . Add ( Hash ) ;
ShaderEntries . AddDefaulted ( ) ;
check ( ShaderEntries . Num ( ) = = ShaderHashes . Num ( ) ) ;
ShaderHashTable . Add ( Key , Index ) ;
bAdded = true ;
}
OutIndex = Index ;
return bAdded ;
}
void FSerializedShaderArchive : : DecompressShader ( int32 Index , const TArray < TArray < uint8 > > & ShaderCode , TArray < uint8 > & OutDecompressedShader ) const
{
const FShaderCodeEntry & Entry = ShaderEntries [ Index ] ;
OutDecompressedShader . SetNum ( Entry . UncompressedSize , false ) ;
if ( Entry . Size = = Entry . UncompressedSize )
{
FMemory : : Memcpy ( OutDecompressedShader . GetData ( ) , ShaderCode [ Index ] . GetData ( ) , Entry . UncompressedSize ) ;
}
else
{
2021-03-11 21:19:35 -04:00
bool bSucceed = FCompression : : UncompressMemory ( GetShaderCompressionFormat ( ) , OutDecompressedShader . GetData ( ) , Entry . UncompressedSize , ShaderCode [ Index ] . GetData ( ) , Entry . Size ) ;
2020-02-06 13:13:41 -05:00
check ( bSucceed ) ;
}
}
void FSerializedShaderArchive : : Finalize ( )
{
// Set the correct offsets
{
uint64 Offset = 0u ;
for ( FShaderCodeEntry & Entry : ShaderEntries )
{
Entry . Offset = Offset ;
Offset + = Entry . Size ;
}
}
PreloadEntries . Empty ( ) ;
for ( FShaderMapEntry & ShaderMapEntry : ShaderMapEntries )
{
check ( ShaderMapEntry . NumShaders > 0u ) ;
TArray < FFileCachePreloadEntry > SortedPreloadEntries ;
2020-03-05 16:37:51 -05:00
SortedPreloadEntries . Empty ( ShaderMapEntry . NumShaders + 1 ) ;
2020-02-06 13:13:41 -05:00
for ( uint32 i = 0 ; i < ShaderMapEntry . NumShaders ; + + i )
{
const int32 ShaderIndex = ShaderIndices [ ShaderMapEntry . ShaderIndicesOffset + i ] ;
const FShaderCodeEntry & ShaderEntry = ShaderEntries [ ShaderIndex ] ;
SortedPreloadEntries . Add ( FFileCachePreloadEntry ( ShaderEntry . Offset , ShaderEntry . Size ) ) ;
}
SortedPreloadEntries . Sort ( [ ] ( const FFileCachePreloadEntry & Lhs , const FFileCachePreloadEntry & Rhs ) { return Lhs . Offset < Rhs . Offset ; } ) ;
SortedPreloadEntries . Add ( FFileCachePreloadEntry ( INT64_MAX , 0 ) ) ;
ShaderMapEntry . FirstPreloadIndex = PreloadEntries . Num ( ) ;
FFileCachePreloadEntry CurrentPreloadEntry = SortedPreloadEntries [ 0 ] ;
for ( uint32 PreloadIndex = 1 ; PreloadIndex < = ShaderMapEntry . NumShaders ; + + PreloadIndex )
{
const FFileCachePreloadEntry & PreloadEntry = SortedPreloadEntries [ PreloadIndex ] ;
const int64 Gap = PreloadEntry . Offset - CurrentPreloadEntry . Offset - CurrentPreloadEntry . Size ;
2020-03-05 16:37:51 -05:00
checkf ( Gap > = 0 , TEXT ( " Overlapping preload entries, [%lld-%lld), [%lld-%lld) " ) ,
CurrentPreloadEntry . Offset , CurrentPreloadEntry . Offset + CurrentPreloadEntry . Size , PreloadEntry . Offset , PreloadEntry . Offset + PreloadEntry . Size ) ;
2020-02-06 13:13:41 -05:00
if ( Gap > 1024 )
{
+ + ShaderMapEntry . NumPreloadEntries ;
PreloadEntries . Add ( CurrentPreloadEntry ) ;
CurrentPreloadEntry = PreloadEntry ;
}
else
{
CurrentPreloadEntry . Size = PreloadEntry . Offset + PreloadEntry . Size - CurrentPreloadEntry . Offset ;
}
}
check ( ShaderMapEntry . NumPreloadEntries > 0u ) ;
check ( CurrentPreloadEntry . Size = = 0 ) ;
}
}
void FSerializedShaderArchive : : Serialize ( FArchive & Ar )
{
Ar < < ShaderMapHashes ;
Ar < < ShaderHashes ;
Ar < < ShaderMapEntries ;
Ar < < ShaderEntries ;
Ar < < PreloadEntries ;
Ar < < ShaderIndices ;
check ( ShaderHashes . Num ( ) = = ShaderEntries . Num ( ) ) ;
check ( ShaderMapHashes . Num ( ) = = ShaderMapEntries . Num ( ) ) ;
if ( Ar . IsLoading ( ) )
{
{
const uint32 HashSize = FMath : : Min < uint32 > ( 0x10000 , 1u < < FMath : : CeilLogTwo ( ShaderMapHashes . Num ( ) ) ) ;
2020-07-06 18:58:26 -04:00
ShaderMapHashTable . Clear ( HashSize , ShaderMapHashes . Num ( ) ) ;
2020-02-06 13:13:41 -05:00
for ( int32 Index = 0 ; Index < ShaderMapHashes . Num ( ) ; + + Index )
{
const uint32 Key = GetTypeHash ( ShaderMapHashes [ Index ] ) ;
ShaderMapHashTable . Add ( Key , Index ) ;
}
}
{
const uint32 HashSize = FMath : : Min < uint32 > ( 0x10000 , 1u < < FMath : : CeilLogTwo ( ShaderHashes . Num ( ) ) ) ;
2020-07-06 18:58:26 -04:00
ShaderHashTable . Clear ( HashSize , ShaderHashes . Num ( ) ) ;
2020-02-06 13:13:41 -05:00
for ( int32 Index = 0 ; Index < ShaderHashes . Num ( ) ; + + Index )
{
const uint32 Key = GetTypeHash ( ShaderHashes [ Index ] ) ;
ShaderHashTable . Add ( Key , Index ) ;
}
}
}
}
2020-10-22 19:19:16 -04:00
# if WITH_EDITOR
void FSerializedShaderArchive : : SaveAssetInfo ( FArchive & Ar )
{
if ( Ar . IsSaving ( ) )
{
FString JsonTcharText ;
{
TSharedRef < TJsonWriter < TCHAR , TPrettyJsonPrintPolicy < TCHAR > > > Writer = TJsonWriterFactory < TCHAR , TPrettyJsonPrintPolicy < TCHAR > > : : Create ( & JsonTcharText ) ;
Writer - > WriteObjectStart ( ) ;
Writer - > WriteValue ( TEXT ( " AssetInfoVersion " ) , static_cast < int32 > ( EAssetInfoVersion : : CurrentVersion ) ) ;
Writer - > WriteArrayStart ( TEXT ( " ShaderCodeToAssets " ) ) ;
for ( TMap < FSHAHash , FShaderMapAssetPaths > : : TConstIterator Iter ( ShaderCodeToAssets ) ; Iter ; + + Iter )
{
Writer - > WriteObjectStart ( ) ;
const FSHAHash & Hash = Iter . Key ( ) ;
Writer - > WriteValue ( TEXT ( " ShaderMapHash " ) , Hash . ToString ( ) ) ;
const FShaderMapAssetPaths & Assets = Iter . Value ( ) ;
Writer - > WriteArrayStart ( TEXT ( " Assets " ) ) ;
for ( FShaderMapAssetPaths : : TConstIterator AssetIter ( Assets ) ; AssetIter ; + + AssetIter )
{
2020-12-11 14:21:20 -04:00
Writer - > WriteValue ( ( * AssetIter ) . ToString ( ) ) ;
2020-10-22 19:19:16 -04:00
}
Writer - > WriteArrayEnd ( ) ;
Writer - > WriteObjectEnd ( ) ;
}
Writer - > WriteArrayEnd ( ) ;
Writer - > WriteObjectEnd ( ) ;
Writer - > Close ( ) ;
}
FTCHARToUTF8 JsonUtf8 ( * JsonTcharText ) ;
Ar . Serialize ( const_cast < void * > ( reinterpret_cast < const void * > ( JsonUtf8 . Get ( ) ) ) , JsonUtf8 . Length ( ) * sizeof ( UTF8CHAR ) ) ;
}
}
bool FSerializedShaderArchive : : LoadAssetInfo ( const FString & Filename )
{
TArray < uint8 > FileData ;
if ( ! FFileHelper : : LoadFileToArray ( FileData , * Filename ) )
{
return false ;
}
FString JsonText ;
FFileHelper : : BufferToString ( JsonText , FileData . GetData ( ) , FileData . Num ( ) ) ;
TSharedPtr < FJsonObject > JsonObject ;
TSharedRef < TJsonReader < TCHAR > > Reader = TJsonReaderFactory < TCHAR > : : Create ( JsonText ) ;
// Attempt to deserialize JSON
if ( ! FJsonSerializer : : Deserialize ( Reader , JsonObject ) | | ! JsonObject . IsValid ( ) )
{
return false ;
}
TSharedPtr < FJsonValue > AssetInfoVersion = JsonObject - > Values . FindRef ( TEXT ( " AssetInfoVersion " ) ) ;
if ( ! AssetInfoVersion . IsValid ( ) )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: missing AssetInfoVersion (damaged file?) " ) ,
* Filename ) ;
return false ;
}
const EAssetInfoVersion FileVersion = static_cast < EAssetInfoVersion > ( static_cast < int64 > ( AssetInfoVersion - > AsNumber ( ) ) ) ;
if ( FileVersion ! = EAssetInfoVersion : : CurrentVersion )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: expected version %d, got unsupported version %d. " ) ,
* Filename , static_cast < int32 > ( EAssetInfoVersion : : CurrentVersion ) , static_cast < int32 > ( FileVersion ) ) ;
return false ;
}
TSharedPtr < FJsonValue > AssetInfoArrayValue = JsonObject - > Values . FindRef ( TEXT ( " ShaderCodeToAssets " ) ) ;
if ( ! AssetInfoArrayValue . IsValid ( ) )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: missing ShaderCodeToAssets array (damaged file?) " ) ,
* Filename ) ;
return false ;
}
TArray < TSharedPtr < FJsonValue > > AssetInfoArray = AssetInfoArrayValue - > AsArray ( ) ;
UE_LOG ( LogShaderLibrary , Display , TEXT ( " Reading asset info file %s: found %d existing mappings " ) ,
* Filename , AssetInfoArray . Num ( ) ) ;
for ( int32 IdxPair = 0 , NumPairs = AssetInfoArray . Num ( ) ; IdxPair < NumPairs ; + + IdxPair )
{
TSharedPtr < FJsonObject > Pair = AssetInfoArray [ IdxPair ] - > AsObject ( ) ;
if ( UNLIKELY ( ! Pair . IsValid ( ) ) )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: ShaderCodeToAssets array contains unreadable mapping #%d (damaged file?) " ) ,
* Filename ,
IdxPair
) ;
return false ;
}
TSharedPtr < FJsonValue > ShaderMapHashJson = Pair - > Values . FindRef ( TEXT ( " ShaderMapHash " ) ) ;
if ( UNLIKELY ( ! ShaderMapHashJson . IsValid ( ) ) )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: ShaderCodeToAssets array contains unreadable ShaderMapHash for mapping %d (damaged file?) " ) ,
* Filename ,
IdxPair
) ;
return false ;
}
FSHAHash ShaderMapHash ;
ShaderMapHash . FromString ( ShaderMapHashJson - > AsString ( ) ) ;
TSharedPtr < FJsonValue > AssetPathsArrayValue = Pair - > Values . FindRef ( TEXT ( " Assets " ) ) ;
if ( UNLIKELY ( ! AssetPathsArrayValue . IsValid ( ) ) )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Rejecting asset info file %s: ShaderCodeToAssets array contains unreadable Assets array for mapping %d (damaged file?) " ) ,
* Filename ,
IdxPair
) ;
return false ;
}
FShaderMapAssetPaths Paths ;
TArray < TSharedPtr < FJsonValue > > AssetPathsArray = AssetPathsArrayValue - > AsArray ( ) ;
for ( int32 IdxAsset = 0 , NumAssets = AssetPathsArray . Num ( ) ; IdxAsset < NumAssets ; + + IdxAsset )
{
2020-12-11 14:21:20 -04:00
Paths . Add ( FName ( * AssetPathsArray [ IdxAsset ] - > AsString ( ) ) ) ;
2020-10-22 19:19:16 -04:00
}
ShaderCodeToAssets . Add ( ShaderMapHash , Paths ) ;
}
return true ;
}
2020-12-11 14:21:20 -04:00
void FSerializedShaderArchive : : CreateAsChunkFrom ( const FSerializedShaderArchive & Parent , const TSet < FName > & PackagesInChunk , TArray < int32 > & OutShaderCodeEntriesNeeded )
{
// we should begin with a clean slate
checkf ( ShaderMapHashes . Num ( ) = = 0 & & ShaderHashes . Num ( ) = = 0 & & ShaderMapEntries . Num ( ) = = 0 & & ShaderEntries . Num ( ) = = 0 & & PreloadEntries . Num ( ) = = 0 & & ShaderIndices . Num ( ) = = 0 ,
TEXT ( " Expecting a new, uninitialized FSerializedShaderArchive instance for creating a chunk. " ) ) ;
2021-01-08 19:56:07 -04:00
// go through parent's shadermap hashes in the order of their addition
for ( int32 IdxSM = 0 , NumSMs = Parent . ShaderMapHashes . Num ( ) ; IdxSM < NumSMs ; + + IdxSM )
2020-12-11 14:21:20 -04:00
{
2021-01-08 19:56:07 -04:00
const FSHAHash & ShaderMapHash = Parent . ShaderMapHashes [ IdxSM ] ;
const FShaderMapAssetPaths * Assets = Parent . ShaderCodeToAssets . Find ( ShaderMapHash ) ;
bool bIncludeSM = false ;
if ( UNLIKELY ( Assets = = nullptr ) )
2020-12-11 14:21:20 -04:00
{
2021-01-08 19:56:07 -04:00
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Shadermap %s is not associated with any asset. Including it in every chunk " ) , * ShaderMapHash . ToString ( ) ) ;
bIncludeSM = true ;
}
else
{
// if any asset is in the chunk, include
for ( const FName & Asset : * Assets )
{
if ( PackagesInChunk . Contains ( Asset ) )
{
bIncludeSM = true ;
break ;
}
}
}
2020-12-11 14:21:20 -04:00
2021-01-08 19:56:07 -04:00
if ( bIncludeSM )
{
2020-12-11 14:21:20 -04:00
// add this shader map
int32 ShaderMapIndex = INDEX_NONE ;
2021-01-08 19:56:07 -04:00
if ( FindOrAddShaderMap ( ShaderMapHash , ShaderMapIndex , Assets ) )
2020-12-11 14:21:20 -04:00
{
// if we're in this scope, it means it's a new shadermap for the chunk and we need more information about it from the parent
2021-01-08 19:56:07 -04:00
int32 ParentShaderMapIndex = IdxSM ;
2020-12-11 14:21:20 -04:00
const FShaderMapEntry & ParentShaderMapDescriptor = Parent . ShaderMapEntries [ ParentShaderMapIndex ] ;
const int32 NumShaders = ParentShaderMapDescriptor . NumShaders ;
FShaderMapEntry & ShaderMapDescriptor = ShaderMapEntries [ ShaderMapIndex ] ;
ShaderMapDescriptor . NumShaders = NumShaders ;
ShaderMapDescriptor . ShaderIndicesOffset = ShaderIndices . AddZeroed ( NumShaders ) ;
// add shader by shader
for ( int32 ShaderIdx = 0 ; ShaderIdx < NumShaders ; + + ShaderIdx )
{
int32 ParentShaderIndex = Parent . ShaderIndices [ ParentShaderMapDescriptor . ShaderIndicesOffset + ShaderIdx ] ;
int32 ShaderIndex = INDEX_NONE ;
if ( FindOrAddShader ( Parent . ShaderHashes [ ParentShaderIndex ] , ShaderIndex ) )
{
// new shader! add it to the mapping of parent shadercode entries to ours. and check the integrity of the mapping
checkf ( OutShaderCodeEntriesNeeded . Num ( ) = = ShaderIndex , TEXT ( " Mapping between the shader indices in a chunk and the whole archive is inconsistent " ) ) ;
OutShaderCodeEntriesNeeded . Add ( ParentShaderIndex ) ;
// copy the entry as is
ShaderEntries [ ShaderIndex ] = Parent . ShaderEntries [ ParentShaderIndex ] ;
}
ShaderIndices [ ShaderMapDescriptor . ShaderIndicesOffset + ShaderIdx ] = ShaderIndex ;
}
}
}
}
}
void FSerializedShaderArchive : : CollectStatsAndDebugInfo ( FDebugStats & OutDebugStats , FExtendedDebugStats * OutExtendedDebugStats )
{
// collect the light-weight stats first
FMemory : : Memzero ( OutDebugStats ) ;
OutDebugStats . NumUniqueShaders = ShaderHashes . Num ( ) ;
OutDebugStats . NumShaderMaps = ShaderMapHashes . Num ( ) ;
int32 TotalShaders = 0 ;
int64 TotalShaderSize = 0 ;
uint32 MinSMSizeInShaders = UINT_MAX ;
uint32 MaxSMSizeInShaders = 0 ;
for ( const FShaderMapEntry & SMEntry : ShaderMapEntries )
{
MinSMSizeInShaders = FMath : : Min ( MinSMSizeInShaders , SMEntry . NumShaders ) ;
MaxSMSizeInShaders = FMath : : Max ( MaxSMSizeInShaders , SMEntry . NumShaders ) ;
TotalShaders + = SMEntry . NumShaders ;
const int32 ThisSMShaders = SMEntry . NumShaders ;
for ( int32 ShaderIdx = 0 ; ShaderIdx < ThisSMShaders ; + + ShaderIdx )
{
TotalShaderSize + = ShaderEntries [ ShaderIndices [ SMEntry . ShaderIndicesOffset + ShaderIdx ] ] . Size ;
}
}
OutDebugStats . NumShaders = TotalShaders ;
OutDebugStats . ShadersSize = TotalShaderSize ;
2021-01-08 19:56:07 -04:00
// this is moderately expensive, consider moving to ExtendedStats?
{
TSet < FName > AllAssets ;
for ( TMap < FSHAHash , FShaderMapAssetPaths > : : TConstIterator Iter ( ShaderCodeToAssets ) ; Iter ; + + Iter )
{
for ( const FName & AssetName : Iter . Value ( ) )
{
AllAssets . Add ( AssetName ) ;
}
}
OutDebugStats . NumAssets = AllAssets . Num ( ) ;
}
2020-12-11 14:21:20 -04:00
int64 ActuallySavedShaderSize = 0 ;
for ( const FShaderCodeEntry & ShaderEntry : ShaderEntries )
{
ActuallySavedShaderSize + = ShaderEntry . Size ;
}
OutDebugStats . ShadersUniqueSize = ActuallySavedShaderSize ;
// If OutExtendedDebugStats pointer is passed, we're asked to fill out a heavy-weight stats.
if ( OutExtendedDebugStats )
{
// textual rep
DumpContentsInPlaintext ( OutExtendedDebugStats - > TextualRepresentation ) ;
OutExtendedDebugStats - > MinNumberOfShadersPerSM = MinSMSizeInShaders ;
OutExtendedDebugStats - > MaxNumberofShadersPerSM = MaxSMSizeInShaders ;
// median SM size in shaders
TArray < int32 > ShadersInSM ;
// shader usage
TMap < int32 , int32 > ShaderToUsageMap ;
for ( const FShaderMapEntry & SMEntry : ShaderMapEntries )
{
const int32 ThisSMShaders = SMEntry . NumShaders ;
ShadersInSM . Add ( ThisSMShaders ) ;
for ( int32 ShaderIdx = 0 ; ShaderIdx < ThisSMShaders ; + + ShaderIdx )
{
int ShaderIndex = ShaderIndices [ SMEntry . ShaderIndicesOffset + ShaderIdx ] ;
int32 & Usage = ShaderToUsageMap . FindOrAdd ( ShaderIndex , 0 ) ;
+ + Usage ;
}
}
ShadersInSM . Sort ( ) ;
2021-01-21 16:22:06 -04:00
OutExtendedDebugStats - > MedianNumberOfShadersPerSM = ShadersInSM . Num ( ) ? ShadersInSM [ ShadersInSM . Num ( ) / 2 ] : 0 ;
2020-12-11 14:21:20 -04:00
ShaderToUsageMap . ValueSort ( TGreater < int32 > ( ) ) ;
// add top 10 shaders
for ( const TTuple < int32 , int32 > & UsagePair : ShaderToUsageMap )
{
OutExtendedDebugStats - > TopShaderUsages . Add ( UsagePair . Value ) ;
if ( OutExtendedDebugStats - > TopShaderUsages . Num ( ) > = 10 )
{
break ;
}
}
}
#if 0 // graph visualization - maybe one day we'll return to this
// enumerate all shaders first (so they can be identified by people looking them up in other debug output)
int32 IdxShaderNum = 0 ;
for ( const FSHAHash & ShaderHash : ShaderHashes )
{
FString Numeral = FString : : Printf ( TEXT ( " Shd_%d " ) , IdxShaderNum ) ;
OutRelationshipGraph - > Add ( TTuple < FString , FString > ( Numeral , FString ( " Hash_ " ) + ShaderHash . ToString ( ) ) ) ;
+ + IdxShaderNum ;
}
// add all assets if any
for ( TMap < FName , FSHAHash > : : TConstIterator Iter ( AssetToShaderCode ) ; Iter ; + + Iter )
{
int32 SMIndex = FindShaderMap ( Iter . Value ( ) ) ;
OutRelationshipGraph - > Add ( TTuple < FString , FString > ( Iter . Key ( ) . ToString ( ) , FString : : Printf ( TEXT ( " SM_%d " ) , SMIndex ) ) ) ;
}
// shadermaps to shaders
int NumSMs = ShaderMapHashes . Num ( ) ;
for ( int32 IdxSM = 0 ; IdxSM < NumSMs ; + + IdxSM )
{
FString SMId = FString : : Printf ( TEXT ( " SM_%d " ) , IdxSM ) ;
const FShaderMapEntry & SMEntry = ShaderMapEntries [ IdxSM ] ;
const int32 ThisSMShaders = SMEntry . NumShaders ;
for ( int32 ShaderIdx = 0 ; ShaderIdx < ThisSMShaders ; + + ShaderIdx )
{
FString ReferencedShader = FString : : Printf ( TEXT ( " Shd_%d " ) , ShaderIndices [ SMEntry . ShaderIndicesOffset + ShaderIdx ] ) ;
OutRelationshipGraph - > Add ( TTuple < FString , FString > ( SMId , ReferencedShader ) ) ;
}
}
# endif // 0
}
void FSerializedShaderArchive : : DumpContentsInPlaintext ( FString & OutText ) const
{
TStringBuilder < 256 > Out ;
Out < < TEXT ( " FSerializedShaderArchive \n { \n " ) ;
{
Out < < TEXT ( " \t ShaderMapHashes \n \t { \n " ) ;
for ( int32 IdxMapHash = 0 , NumMapHashes = ShaderMapHashes . Num ( ) ; IdxMapHash < NumMapHashes ; + + IdxMapHash )
{
Out < < TEXT ( " \t \t " ) ;
Out < < ShaderMapHashes [ IdxMapHash ] . ToString ( ) ;
Out < < TEXT ( " \n " ) ;
}
Out < < TEXT ( " \t } \n " ) ;
}
{
Out < < TEXT ( " \t ShaderHashes \n \t { \n " ) ;
2021-04-01 12:16:46 -04:00
for ( int32 IdxHash = 0 , NumHashes = ShaderHashes . Num ( ) ; IdxHash < NumHashes ; + + IdxHash )
2020-12-11 14:21:20 -04:00
{
Out < < TEXT ( " \t \t " ) ;
Out < < ShaderHashes [ IdxHash ] . ToString ( ) ;
Out < < TEXT ( " \n " ) ;
}
Out < < TEXT ( " \t } \n " ) ;
}
{
Out < < TEXT ( " \t ShaderMapEntries \n \t { \n " ) ;
for ( int32 IdxEntry = 0 , NumEntries = ShaderMapEntries . Num ( ) ; IdxEntry < NumEntries ; + + IdxEntry )
{
Out < < TEXT ( " \t \t FShaderMapEntry \n \t \t { \n " ) ;
Out < < TEXT ( " \t \t \t ShaderIndicesOffset : " ) ;
Out < < ShaderMapEntries [ IdxEntry ] . ShaderIndicesOffset ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t NumShaders : " ) ;
Out < < ShaderMapEntries [ IdxEntry ] . NumShaders ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t FirstPreloadIndex : " ) ;
Out < < ShaderMapEntries [ IdxEntry ] . FirstPreloadIndex ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t NumPreloadEntries : " ) ;
Out < < ShaderMapEntries [ IdxEntry ] . NumPreloadEntries ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t } \n " ) ;
}
Out < < TEXT ( " \t } \n " ) ;
}
{
Out < < TEXT ( " \t ShaderEntries \n \t { \n " ) ;
for ( int32 IdxEntry = 0 , NumEntries = ShaderEntries . Num ( ) ; IdxEntry < NumEntries ; + + IdxEntry )
{
Out < < TEXT ( " \t \t FShaderCodeEntry \n \t \t { \n " ) ;
Out < < TEXT ( " \t \t \t Offset : " ) ;
Out < < ShaderEntries [ IdxEntry ] . Offset ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t Size : " ) ;
Out < < ShaderEntries [ IdxEntry ] . Size ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t UncompressedSize : " ) ;
Out < < ShaderEntries [ IdxEntry ] . UncompressedSize ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t Frequency : " ) ;
Out < < ShaderEntries [ IdxEntry ] . Frequency ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t } \n " ) ;
}
Out < < TEXT ( " \t } \n " ) ;
}
{
Out < < TEXT ( " \t PreloadEntries \n \t { \n " ) ;
for ( int32 IdxEntry = 0 , NumEntries = PreloadEntries . Num ( ) ; IdxEntry < NumEntries ; + + IdxEntry )
{
Out < < TEXT ( " \t \t FFileCachePreloadEntry \n \t \t { \n " ) ;
Out < < TEXT ( " \t \t \t Offset : " ) ;
Out < < PreloadEntries [ IdxEntry ] . Offset ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t \t Size : " ) ;
Out < < PreloadEntries [ IdxEntry ] . Size ;
Out < < TEXT ( " \n " ) ;
Out < < TEXT ( " \t \t } \n " ) ;
}
Out < < TEXT ( " \t } \n " ) ;
}
{
Out < < TEXT ( " \t ShaderIndices \n \t { \n " ) ;
// split it by shadermaps
int32 IdxSMEntry = 0 ;
2021-01-21 16:22:06 -04:00
int32 NumShadersLeftInSM = ShaderMapEntries . Num ( ) ? ShaderMapEntries [ 0 ] . NumShaders : 0 ;
2020-12-11 14:21:20 -04:00
bool bNewSM = true ;
for ( int32 IdxEntry = 0 , NumEntries = ShaderIndices . Num ( ) ; IdxEntry < NumEntries ; + + IdxEntry )
{
if ( UNLIKELY ( bNewSM ) )
{
Out < < TEXT ( " \t \t " ) ;
bNewSM = false ;
}
else
{
Out < < TEXT ( " , " ) ;
}
Out < < ShaderIndices [ IdxEntry ] ;
- - NumShadersLeftInSM ;
while ( NumShadersLeftInSM = = 0 )
{
bNewSM = true ;
+ + IdxSMEntry ;
if ( IdxSMEntry > = ShaderMapEntries . Num ( ) )
{
break ;
}
NumShadersLeftInSM = ShaderMapEntries [ IdxSMEntry ] . NumShaders ;
}
if ( bNewSM )
{
Out < < TEXT ( " \n " ) ;
}
}
Out < < TEXT ( " \t } \n " ) ;
}
Out < < TEXT ( " } \n " ) ;
OutText = FStringView ( Out ) ;
}
2020-10-22 19:19:16 -04:00
# endif // WITH_EDITOR
2020-02-06 13:13:41 -05:00
FShaderCodeArchive * FShaderCodeArchive : : Create ( EShaderPlatform InPlatform , FArchive & Ar , const FString & InDestFilePath , const FString & InLibraryDir , const FString & InLibraryName )
{
FShaderCodeArchive * Library = new FShaderCodeArchive ( InPlatform , InLibraryDir , InLibraryName ) ;
Ar < < Library - > SerializedShaders ;
2020-06-23 18:40:00 -04:00
Library - > ShaderPreloads . SetNum ( Library - > SerializedShaders . GetNumShaders ( ) ) ;
2020-02-06 13:13:41 -05:00
Library - > LibraryCodeOffset = Ar . Tell ( ) ;
// Open library for async reads
Library - > FileCacheHandle = IFileCacheHandle : : CreateFileCacheHandle ( * InDestFilePath ) ;
UE_LOG ( LogShaderLibrary , Display , TEXT ( " Using %s for material shader code. Total %d unique shaders. " ) , * InDestFilePath , Library - > SerializedShaders . ShaderEntries . Num ( ) ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Library - > GetSizeBytes ( ) ) ;
return Library ;
}
FShaderCodeArchive : : FShaderCodeArchive ( EShaderPlatform InPlatform , const FString & InLibraryDir , const FString & InLibraryName )
: FRHIShaderLibrary ( InPlatform , InLibraryName )
, LibraryDir ( InLibraryDir )
, LibraryCodeOffset ( 0 )
, FileCacheHandle ( nullptr )
{
}
FShaderCodeArchive : : ~ FShaderCodeArchive ( )
{
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , GetSizeBytes ( ) ) ;
2020-02-25 16:56:18 -05:00
Teardown ( ) ;
}
void FShaderCodeArchive : : Teardown ( )
{
2020-02-06 13:13:41 -05:00
if ( FileCacheHandle )
{
delete FileCacheHandle ;
2020-02-25 16:56:18 -05:00
FileCacheHandle = nullptr ;
2020-02-06 13:13:41 -05:00
}
2020-06-23 18:40:00 -04:00
for ( int32 ShaderIndex = 0 ; ShaderIndex < SerializedShaders . GetNumShaders ( ) ; + + ShaderIndex )
2020-02-06 13:13:41 -05:00
{
2020-06-23 18:40:00 -04:00
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
if ( ShaderPreloadEntry . Code )
2020-03-30 17:41:29 -04:00
{
2020-06-23 18:40:00 -04:00
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ ShaderIndex ] ;
FMemory : : Free ( ShaderPreloadEntry . Code ) ;
ShaderPreloadEntry . Code = nullptr ;
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , ShaderEntry . Size ) ;
2020-03-30 17:41:29 -04:00
}
2020-02-06 13:13:41 -05:00
}
}
2020-06-23 18:40:00 -04:00
void FShaderCodeArchive : : OnShaderPreloadFinished ( int32 ShaderIndex , const IMemoryReadStreamRef & PreloadData )
2020-02-06 13:13:41 -05:00
{
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ ShaderIndex ] ;
2021-07-22 11:57:21 -04:00
PreloadData - > EnsureReadNonBlocking ( ) ; // Ensure data is ready before taking the lock
{
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
PreloadData - > CopyTo ( ShaderPreloadEntry . Code , 0 , ShaderEntry . Size ) ;
ShaderPreloadEntry . PreloadEvent . SafeRelease ( ) ;
}
2020-02-06 13:13:41 -05:00
}
2020-06-23 18:40:00 -04:00
struct FPreloadShaderTask
2020-02-06 13:13:41 -05:00
{
2020-06-23 18:40:00 -04:00
explicit FPreloadShaderTask ( FShaderCodeArchive * InArchive , int32 InShaderIndex , const IMemoryReadStreamRef & InData )
: Archive ( InArchive ) , Data ( InData ) , ShaderIndex ( InShaderIndex )
{ }
FShaderCodeArchive * Archive ;
IMemoryReadStreamRef Data ;
int32 ShaderIndex ;
void DoTask ( ENamedThreads : : Type CurrentThread , const FGraphEventRef & MyCompletionGraphEvent )
{
Archive - > OnShaderPreloadFinished ( ShaderIndex , Data ) ;
Data . SafeRelease ( ) ;
}
FORCEINLINE static ESubsequentsMode : : Type GetSubsequentsMode ( ) { return ESubsequentsMode : : TrackSubsequents ; }
FORCEINLINE ENamedThreads : : Type GetDesiredThread ( ) { return ENamedThreads : : AnyNormalThreadNormalTask ; }
FORCEINLINE TStatId GetStatId ( ) const { return TStatId ( ) ; }
} ;
bool FShaderCodeArchive : : PreloadShader ( int32 ShaderIndex , FGraphEventArray & OutCompletionEvents )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-18 14:37:34 -05:00
checkf ( ! ShaderPreloadEntry . bNeverToBePreloaded , TEXT ( " We are preloading a shader that shouldn't be preloaded in this run (e.g. raytracing shader on D3D11). " ) ) ;
2020-06-23 18:40:00 -04:00
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ ShaderIndex ] ;
ShaderPreloadEntry . Code = FMemory : : Malloc ( ShaderEntry . Size ) ;
ShaderPreloadEntry . FramePreloadStarted = GFrameNumber ;
const EAsyncIOPriorityAndFlags IOPriority = ( EAsyncIOPriorityAndFlags ) GShaderCodeLibraryAsyncLoadingPriority ;
FGraphEventArray ReadCompletionEvents ;
EAsyncIOPriorityAndFlags DontCache = GShaderCodeLibraryAsyncLoadingAllowDontCache ? AIOP_FLAG_DONTCACHE : AIOP_MIN ;
IMemoryReadStreamRef PreloadData = FileCacheHandle - > ReadData ( ReadCompletionEvents , LibraryCodeOffset + ShaderEntry . Offset , ShaderEntry . Size , IOPriority | DontCache ) ;
auto Task = TGraphTask < FPreloadShaderTask > : : CreateTask ( & ReadCompletionEvents ) . ConstructAndHold ( this , ShaderIndex , MoveTemp ( PreloadData ) ) ;
ShaderPreloadEntry . PreloadEvent = Task - > GetCompletionEvent ( ) ;
Task - > Unlock ( ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , ShaderEntry . Size ) ;
}
if ( ShaderPreloadEntry . PreloadEvent )
{
OutCompletionEvents . Add ( ShaderPreloadEntry . PreloadEvent ) ;
}
return true ;
}
bool FShaderCodeArchive : : PreloadShaderMap ( int32 ShaderMapIndex , FGraphEventArray & OutCompletionEvents )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
2020-02-06 13:13:41 -05:00
const FShaderMapEntry & ShaderMapEntry = SerializedShaders . ShaderMapEntries [ ShaderMapIndex ] ;
2020-06-23 18:40:00 -04:00
const EAsyncIOPriorityAndFlags IOPriority = ( EAsyncIOPriorityAndFlags ) GShaderCodeLibraryAsyncLoadingPriority ;
2020-03-30 17:41:29 -04:00
const uint32 FrameNumber = GFrameNumber ;
2020-06-23 18:40:00 -04:00
uint32 PreloadMemory = 0u ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
2020-03-30 17:41:29 -04:00
for ( uint32 i = 0u ; i < ShaderMapEntry . NumShaders ; + + i )
{
2020-06-23 18:40:00 -04:00
const int32 ShaderIndex = SerializedShaders . ShaderIndices [ ShaderMapEntry . ShaderIndicesOffset + i ] ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-07 23:43:01 -05:00
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ ShaderIndex ] ;
# if RHI_RAYTRACING
if ( ! IsRayTracingEnabled ( ) & & IsRayTracingShaderFrequency ( static_cast < EShaderFrequency > ( ShaderEntry . Frequency ) ) )
{
ShaderPreloadEntry . bNeverToBePreloaded = 1 ;
continue ;
}
# endif
2020-06-23 18:40:00 -04:00
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
ShaderPreloadEntry . Code = FMemory : : Malloc ( ShaderEntry . Size ) ;
ShaderPreloadEntry . FramePreloadStarted = FrameNumber ;
PreloadMemory + = ShaderEntry . Size ;
FGraphEventArray ReadCompletionEvents ;
EAsyncIOPriorityAndFlags DontCache = GShaderCodeLibraryAsyncLoadingAllowDontCache ? AIOP_FLAG_DONTCACHE : AIOP_MIN ;
IMemoryReadStreamRef PreloadData = FileCacheHandle - > ReadData ( ReadCompletionEvents , LibraryCodeOffset + ShaderEntry . Offset , ShaderEntry . Size , IOPriority | DontCache ) ;
auto Task = TGraphTask < FPreloadShaderTask > : : CreateTask ( & ReadCompletionEvents ) . ConstructAndHold ( this , ShaderIndex , MoveTemp ( PreloadData ) ) ;
ShaderPreloadEntry . PreloadEvent = Task - > GetCompletionEvent ( ) ;
Task - > Unlock ( ) ;
OutCompletionEvents . Add ( ShaderPreloadEntry . PreloadEvent ) ;
}
else if ( ShaderPreloadEntry . PreloadEvent )
{
OutCompletionEvents . Add ( ShaderPreloadEntry . PreloadEvent ) ;
}
2020-03-30 17:41:29 -04:00
}
2020-06-23 18:40:00 -04:00
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , PreloadMemory ) ;
return true ;
2020-03-30 17:41:29 -04:00
}
2020-06-23 18:40:00 -04:00
bool FShaderCodeArchive : : WaitForPreload ( FShaderPreloadEntry & ShaderPreloadEntry )
2020-03-30 17:41:29 -04:00
{
2020-06-23 18:40:00 -04:00
FGraphEventRef Event ;
2020-03-30 17:41:29 -04:00
{
2020-06-23 18:40:00 -04:00
FReadScopeLock Lock ( ShaderPreloadLock ) ;
if ( ShaderPreloadEntry . NumRefs > 0u )
{
Event = ShaderPreloadEntry . PreloadEvent ;
}
else
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
}
}
const bool bNeedToWait = Event & & ! Event - > IsComplete ( ) ;
if ( bNeedToWait )
{
FTaskGraphInterface : : Get ( ) . WaitUntilTaskCompletes ( Event ) ;
}
return bNeedToWait ;
}
void FShaderCodeArchive : : ReleasePreloadedShader ( int32 ShaderIndex )
{
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-07 23:43:01 -05:00
if ( ! ShaderPreloadEntry . bNeverToBePreloaded )
2020-06-23 18:40:00 -04:00
{
2021-11-07 23:43:01 -05:00
WaitForPreload ( ShaderPreloadEntry ) ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
ShaderPreloadEntry . PreloadEvent . SafeRelease ( ) ;
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs - - ;
check ( ShaderPreloadEntry . Code ) ;
check ( ShaderNumRefs > 0u ) ;
if ( ShaderNumRefs = = 1u )
{
FMemory : : Free ( ShaderPreloadEntry . Code ) ;
ShaderPreloadEntry . Code = nullptr ;
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ ShaderIndex ] ;
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , ShaderEntry . Size ) ;
}
2020-03-30 17:41:29 -04:00
}
2020-02-06 13:13:41 -05:00
}
TRefCountPtr < FRHIShader > FShaderCodeArchive : : CreateShader ( int32 Index )
{
2020-06-23 18:40:00 -04:00
LLM_SCOPE ( ELLMTag : : Shaders ) ;
2021-09-27 19:54:25 -04:00
# if STATS
double TimeFunctionEntered = FPlatformTime : : Seconds ( ) ;
ON_SCOPE_EXIT
{
if ( IsInRenderingThread ( ) )
{
double ShaderCreationTime = FPlatformTime : : Seconds ( ) - TimeFunctionEntered ;
INC_FLOAT_STAT_BY ( STAT_Shaders_TotalRTShaderInitForRenderingTime , ShaderCreationTime ) ;
}
} ;
# endif
2020-02-06 13:13:41 -05:00
TRefCountPtr < FRHIShader > Shader ;
2020-06-23 18:40:00 -04:00
FMemStackBase & MemStack = FMemStack : : Get ( ) ;
FMemMark Mark ( MemStack ) ;
const FShaderCodeEntry & ShaderEntry = SerializedShaders . ShaderEntries [ Index ] ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ Index ] ;
2021-11-18 14:37:34 -05:00
checkf ( ! ShaderPreloadEntry . bNeverToBePreloaded , TEXT ( " We are creating a shader that shouldn't be preloaded in this run (e.g. raytracing shader on D3D11). " ) ) ;
2020-06-23 18:40:00 -04:00
void * PreloadedShaderCode = nullptr ;
2020-02-06 13:13:41 -05:00
{
2020-06-23 18:40:00 -04:00
const bool bNeededToWait = WaitForPreload ( ShaderPreloadEntry ) ;
if ( bNeededToWait )
2020-02-06 13:13:41 -05:00
{
2020-06-23 18:40:00 -04:00
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Blocking wait for shader preload, NumRefs: %d, FramePreloadStarted: %d " ) , ShaderPreloadEntry . NumRefs , ShaderPreloadEntry . FramePreloadStarted ) ;
2020-02-06 13:13:41 -05:00
}
2020-06-23 18:40:00 -04:00
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
if ( ShaderPreloadEntry . NumRefs > 0u )
2020-02-06 13:13:41 -05:00
{
2020-06-23 18:40:00 -04:00
check ( ! ShaderPreloadEntry . PreloadEvent | | ShaderPreloadEntry . PreloadEvent - > IsComplete ( ) ) ;
ShaderPreloadEntry . PreloadEvent . SafeRelease ( ) ;
2020-02-06 13:13:41 -05:00
2020-06-23 18:40:00 -04:00
ShaderPreloadEntry . NumRefs + + ; // Hold a reference to code while we're using it to create shader
PreloadedShaderCode = ShaderPreloadEntry . Code ;
check ( PreloadedShaderCode ) ;
2020-02-06 13:13:41 -05:00
}
}
2020-06-23 18:40:00 -04:00
const uint8 * ShaderCode = ( uint8 * ) PreloadedShaderCode ;
if ( ! ShaderCode )
{
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Blocking shader load, NumRefs: %d, FramePreloadStarted: %d " ) , ShaderPreloadEntry . NumRefs , ShaderPreloadEntry . FramePreloadStarted ) ;
FGraphEventArray ReadCompleteEvents ;
EAsyncIOPriorityAndFlags DontCache = GShaderCodeLibraryAsyncLoadingAllowDontCache ? AIOP_FLAG_DONTCACHE : AIOP_MIN ;
IMemoryReadStreamRef LoadedCode = FileCacheHandle - > ReadData ( ReadCompleteEvents , LibraryCodeOffset + ShaderEntry . Offset , ShaderEntry . Size , AIOP_CriticalPath | DontCache ) ;
if ( ReadCompleteEvents . Num ( ) > 0 )
{
FTaskGraphInterface : : Get ( ) . WaitUntilTasksComplete ( ReadCompleteEvents ) ;
}
void * LoadedShaderCode = MemStack . Alloc ( ShaderEntry . Size , 16 ) ;
LoadedCode - > CopyTo ( LoadedShaderCode , 0 , ShaderEntry . Size ) ;
ShaderCode = ( uint8 * ) LoadedShaderCode ;
}
if ( ShaderEntry . UncompressedSize ! = ShaderEntry . Size )
{
void * UncompressedCode = MemStack . Alloc ( ShaderEntry . UncompressedSize , 16 ) ;
2021-03-11 21:19:35 -04:00
const bool bDecompressResult = FCompression : : UncompressMemory ( GetShaderCompressionFormat ( ) , UncompressedCode , ShaderEntry . UncompressedSize , ShaderCode , ShaderEntry . Size ) ;
2020-06-23 18:40:00 -04:00
check ( bDecompressResult ) ;
ShaderCode = ( uint8 * ) UncompressedCode ;
}
2021-09-21 15:10:29 -04:00
// detect the breach of contract early
ensureAlwaysMsgf ( IsInRenderingThread ( ) | | GRHISupportsMultithreadedShaderCreation , TEXT ( " More than one thread is creating shaders, but GRHISupportsMultithreadedShaderCreation is false. " ) ) ;
2020-06-23 18:40:00 -04:00
const auto ShaderCodeView = MakeArrayView ( ShaderCode , ShaderEntry . UncompressedSize ) ;
const FSHAHash & ShaderHash = SerializedShaders . ShaderHashes [ Index ] ;
switch ( ShaderEntry . Frequency )
{
case SF_Vertex : Shader = RHICreateVertexShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
2021-03-18 18:42:49 -04:00
case SF_Mesh : Shader = RHICreateMeshShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
case SF_Amplification : Shader = RHICreateAmplificationShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
2020-06-23 18:40:00 -04:00
case SF_Pixel : Shader = RHICreatePixelShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
case SF_Geometry : Shader = RHICreateGeometryShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
case SF_Compute : Shader = RHICreateComputeShader ( ShaderCodeView , ShaderHash ) ; CheckShaderCreation ( Shader , Index ) ; break ;
case SF_RayGen : case SF_RayMiss : case SF_RayHitGroup : case SF_RayCallable :
# if RHI_RAYTRACING
2021-11-23 10:25:31 -05:00
if ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders )
2020-06-23 18:40:00 -04:00
{
Shader = RHICreateRayTracingShader ( ShaderCodeView , ShaderHash , ShaderEntry . GetFrequency ( ) ) ;
CheckShaderCreation ( Shader , Index ) ;
}
# endif // RHI_RAYTRACING
break ;
default : checkNoEntry ( ) ; break ;
}
// Release the refernece we were holding
if ( PreloadedShaderCode )
{
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
check ( ShaderPreloadEntry . NumRefs > 1u ) ; // we shouldn't be holding the last ref here
- - ShaderPreloadEntry . NumRefs ;
PreloadedShaderCode = nullptr ;
}
if ( Shader )
{
2021-09-27 19:54:25 -04:00
INC_DWORD_STAT ( STAT_Shaders_NumShadersUsedForRendering ) ;
2020-06-23 18:40:00 -04:00
Shader - > SetHash ( ShaderHash ) ;
}
2020-02-06 13:13:41 -05:00
return Shader ;
}
2021-06-10 09:36:47 -04:00
2021-09-15 10:39:23 -04:00
FIoChunkId FIoStoreShaderCodeArchive : : GetShaderCodeArchiveChunkId ( const FString & LibraryName , FName FormatName )
{
FString Name = FString : : Printf ( TEXT ( " %s-%s " ) , * LibraryName , * FormatName . ToString ( ) ) ;
Name . ToLowerInline ( ) ;
uint64 Hash = CityHash64 ( reinterpret_cast < const char * > ( * Name ) , Name . Len ( ) * sizeof ( TCHAR ) ) ;
return CreateIoChunkId ( Hash , 0 , EIoChunkType : : ShaderCodeLibrary ) ;
}
FIoChunkId FIoStoreShaderCodeArchive : : GetShaderCodeChunkId ( const FSHAHash & ShaderHash )
{
uint8 Data [ 12 ] ;
FMemory : : Memcpy ( Data , ShaderHash . Hash , 11 ) ;
* reinterpret_cast < uint8 * > ( & Data [ 11 ] ) = static_cast < uint8 > ( EIoChunkType : : ShaderCode ) ;
FIoChunkId ChunkId ;
ChunkId . Set ( Data , 12 ) ;
return ChunkId ;
}
void FIoStoreShaderCodeArchive : : SaveIoStoreShaderCodeArchive ( const FSerializedShaderArchive & SerializedShaders , FArchive & OutLibraryAr )
{
uint32 Version = CurrentVersion ;
OutLibraryAr < < Version ;
OutLibraryAr < < const_cast < FSerializedShaderArchive & > ( SerializedShaders ) . ShaderMapHashes ;
OutLibraryAr < < const_cast < FSerializedShaderArchive & > ( SerializedShaders ) . ShaderHashes ;
TArray < FIoStoreShaderMapEntry > ShaderMapEntries ;
ShaderMapEntries . Reserve ( SerializedShaders . ShaderMapEntries . Num ( ) ) ;
for ( const FShaderMapEntry & ShaderMapEntry : SerializedShaders . ShaderMapEntries )
{
FIoStoreShaderMapEntry & IoStoreShaderMapEntry = ShaderMapEntries . AddDefaulted_GetRef ( ) ;
IoStoreShaderMapEntry . ShaderIndicesOffset = ShaderMapEntry . ShaderIndicesOffset ;
IoStoreShaderMapEntry . NumShaders = ShaderMapEntry . NumShaders ;
}
OutLibraryAr < < ShaderMapEntries ;
TArray < FIoStoreShaderCodeEntry > ShaderEntries ;
ShaderEntries . Reserve ( SerializedShaders . ShaderEntries . Num ( ) ) ;
for ( const FShaderCodeEntry & ShaderEntry : SerializedShaders . ShaderEntries )
{
FIoStoreShaderCodeEntry & IoStoreShaderEntry = ShaderEntries . AddDefaulted_GetRef ( ) ;
IoStoreShaderEntry . UncompressedSize = ShaderEntry . UncompressedSize ;
IoStoreShaderEntry . CompressedSize = ShaderEntry . Size ;
IoStoreShaderEntry . Frequency = ShaderEntry . Frequency ;
}
OutLibraryAr < < ShaderEntries ;
OutLibraryAr < < const_cast < FSerializedShaderArchive & > ( SerializedShaders ) . ShaderIndices ;
}
2021-06-10 09:36:47 -04:00
FIoStoreShaderCodeArchive * FIoStoreShaderCodeArchive : : Create ( EShaderPlatform InPlatform , const FString & InLibraryName , FIoDispatcher & InIoDispatcher )
{
const FName PlatformName = LegacyShaderPlatformToShaderFormat ( InPlatform ) ;
FIoChunkId ChunkId = GetShaderCodeArchiveChunkId ( InLibraryName , PlatformName ) ;
if ( InIoDispatcher . DoesChunkExist ( ChunkId ) )
{
FIoBatch IoBatch = InIoDispatcher . NewBatch ( ) ;
FIoRequest IoRequest = IoBatch . Read ( ChunkId , FIoReadOptions ( ) , IoDispatcherPriority_Max ) ;
FEvent * Event = FPlatformProcess : : GetSynchEventFromPool ( ) ;
IoBatch . IssueAndTriggerEvent ( Event ) ;
Event - > Wait ( ) ;
FPlatformProcess : : ReturnSynchEventToPool ( Event ) ;
2021-10-12 21:21:22 -04:00
const FIoBuffer & IoBuffer = IoRequest . GetResultOrDie ( ) ;
2021-06-10 09:36:47 -04:00
FMemoryReaderView Ar ( MakeArrayView ( IoBuffer . Data ( ) , IoBuffer . DataSize ( ) ) ) ;
uint32 Version = 0 ;
Ar < < Version ;
2021-09-15 10:39:23 -04:00
if ( Version = = CurrentVersion )
2021-06-10 09:36:47 -04:00
{
FIoStoreShaderCodeArchive * Library = new FIoStoreShaderCodeArchive ( InPlatform , InLibraryName , InIoDispatcher ) ;
Ar < < Library - > ShaderMapHashes ;
Ar < < Library - > ShaderHashes ;
Ar < < Library - > ShaderMapEntries ;
Ar < < Library - > ShaderEntries ;
Ar < < Library - > ShaderIndices ;
Library - > ShaderPreloads . SetNum ( Library - > GetNumShaders ( ) ) ;
{
const uint32 HashSize = FMath : : Min < uint32 > ( 0x10000 , 1u < < FMath : : CeilLogTwo ( Library - > ShaderMapHashes . Num ( ) ) ) ;
Library - > ShaderMapHashTable . Clear ( HashSize , Library - > ShaderMapHashes . Num ( ) ) ;
for ( int32 Index = 0 ; Index < Library - > ShaderMapHashes . Num ( ) ; + + Index )
{
const uint32 Key = GetTypeHash ( Library - > ShaderMapHashes [ Index ] ) ;
Library - > ShaderMapHashTable . Add ( Key , Index ) ;
}
}
{
const uint32 HashSize = FMath : : Min < uint32 > ( 0x10000 , 1u < < FMath : : CeilLogTwo ( Library - > ShaderHashes . Num ( ) ) ) ;
Library - > ShaderHashTable . Clear ( HashSize , Library - > ShaderHashes . Num ( ) ) ;
for ( int32 Index = 0 ; Index < Library - > ShaderHashes . Num ( ) ; + + Index )
{
const uint32 Key = GetTypeHash ( Library - > ShaderHashes [ Index ] ) ;
Library - > ShaderHashTable . Add ( Key , Index ) ;
}
}
UE_LOG ( LogShaderLibrary , Display , TEXT ( " Using IoDispatcher for shader code library %s. Total %d unique shaders. " ) , * InLibraryName , Library - > ShaderEntries . Num ( ) ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Library - > GetSizeBytes ( ) ) ;
return Library ;
}
}
return nullptr ;
}
FIoStoreShaderCodeArchive : : FIoStoreShaderCodeArchive ( EShaderPlatform InPlatform , const FString & InLibraryName , FIoDispatcher & InIoDispatcher )
: FRHIShaderLibrary ( InPlatform , InLibraryName )
, IoDispatcher ( InIoDispatcher )
{
}
FIoStoreShaderCodeArchive : : ~ FIoStoreShaderCodeArchive ( )
{
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , GetSizeBytes ( ) ) ;
Teardown ( ) ;
}
void FIoStoreShaderCodeArchive : : Teardown ( )
{
for ( int32 ShaderIndex = 0 ; ShaderIndex < ShaderPreloads . Num ( ) ; + + ShaderIndex )
{
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
check ( ! ShaderPreloadEntry . NumRefs ) ;
}
}
bool FIoStoreShaderCodeArchive : : PreloadShader ( int32 ShaderIndex , FGraphEventArray & OutCompletionEvents )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
const FIoStoreShaderCodeEntry & ShaderEntry = ShaderEntries [ ShaderIndex ] ;
ShaderPreloadEntry . FramePreloadStarted = GFrameNumber ;
ShaderPreloadEntry . PreloadEvent = FGraphEvent : : CreateGraphEvent ( ) ;
FIoBatch IoBatch = IoDispatcher . NewBatch ( ) ;
2021-11-07 23:43:01 -05:00
ShaderPreloadEntry . IoRequest = IoBatch . Read ( GetShaderCodeChunkId ( ShaderHashes [ ShaderIndex ] ) , FIoReadOptions ( ) , IoDispatcherPriority_Medium ) ;
2021-06-10 09:36:47 -04:00
IoBatch . IssueAndDispatchSubsequents ( ShaderPreloadEntry . PreloadEvent ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , ShaderEntry . CompressedSize ) ;
}
if ( ShaderPreloadEntry . PreloadEvent & & ! ShaderPreloadEntry . PreloadEvent - > IsComplete ( ) )
{
OutCompletionEvents . Add ( ShaderPreloadEntry . PreloadEvent ) ;
}
return true ;
}
bool FIoStoreShaderCodeArchive : : PreloadShaderMap ( int32 ShaderMapIndex , FGraphEventArray & OutCompletionEvents )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
const FIoStoreShaderMapEntry & ShaderMapEntry = ShaderMapEntries [ ShaderMapIndex ] ;
const uint32 FrameNumber = GFrameNumber ;
uint32 PreloadMemory = 0u ;
uint32 PreloadCount = 0u ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
for ( uint32 i = 0u ; i < ShaderMapEntry . NumShaders ; + + i )
{
const int32 ShaderIndex = ShaderIndices [ ShaderMapEntry . ShaderIndicesOffset + i ] ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-07 23:43:01 -05:00
const FIoStoreShaderCodeEntry & ShaderEntry = ShaderEntries [ ShaderIndex ] ;
# if RHI_RAYTRACING
if ( ! IsRayTracingEnabled ( ) & & IsRayTracingShaderFrequency ( static_cast < EShaderFrequency > ( ShaderEntry . Frequency ) ) )
{
ShaderPreloadEntry . bNeverToBePreloaded = 1 ;
continue ;
}
# endif
2021-06-10 09:36:47 -04:00
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
ShaderPreloadEntry . FramePreloadStarted = FrameNumber ;
PreloadMemory + = ShaderEntry . CompressedSize ;
+ + PreloadCount ;
ShaderPreloadEntry . PreloadEvent = FGraphEvent : : CreateGraphEvent ( ) ;
FIoBatch IoBatch = IoDispatcher . NewBatch ( ) ;
ShaderPreloadEntry . IoRequest = IoBatch . Read ( GetShaderCodeChunkId ( ShaderHashes [ ShaderIndex ] ) , FIoReadOptions ( ) , IoDispatcherPriority_Medium ) ;
IoBatch . IssueAndDispatchSubsequents ( ShaderPreloadEntry . PreloadEvent ) ;
}
if ( ShaderPreloadEntry . PreloadEvent & & ! ShaderPreloadEntry . PreloadEvent - > IsComplete ( ) )
{
OutCompletionEvents . Add ( ShaderPreloadEntry . PreloadEvent ) ;
}
}
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , PreloadMemory ) ;
return true ;
}
bool FIoStoreShaderCodeArchive : : PreloadShaderMap ( int32 ShaderMapIndex , FCoreDelegates : : FAttachShaderReadRequestFunc AttachShaderReadRequestFunc )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
const FIoStoreShaderMapEntry & ShaderMapEntry = ShaderMapEntries [ ShaderMapIndex ] ;
const uint32 FrameNumber = GFrameNumber ;
uint32 PreloadMemory = 0u ;
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
for ( uint32 i = 0u ; i < ShaderMapEntry . NumShaders ; + + i )
{
const int32 ShaderIndex = ShaderIndices [ ShaderMapEntry . ShaderIndicesOffset + i ] ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-07 23:43:01 -05:00
const FIoStoreShaderCodeEntry & ShaderEntry = ShaderEntries [ ShaderIndex ] ;
# if RHI_RAYTRACING
if ( ! IsRayTracingEnabled ( ) & & IsRayTracingShaderFrequency ( static_cast < EShaderFrequency > ( ShaderEntry . Frequency ) ) )
{
ShaderPreloadEntry . bNeverToBePreloaded = 1 ;
continue ;
}
# endif
2021-06-10 09:36:47 -04:00
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
ShaderPreloadEntry . FramePreloadStarted = FrameNumber ;
PreloadMemory + = ShaderEntry . CompressedSize ;
ShaderPreloadEntry . PreloadEvent = FGraphEvent : : CreateGraphEvent ( ) ;
ShaderPreloadEntry . IoRequest = AttachShaderReadRequestFunc ( GetShaderCodeChunkId ( ShaderHashes [ ShaderIndex ] ) , ShaderPreloadEntry . PreloadEvent ) ;
}
}
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , PreloadMemory ) ;
return true ;
}
bool FIoStoreShaderCodeArchive : : ReleaseRef ( int32 ShaderIndex )
{
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ ShaderIndex ] ;
2021-11-07 23:43:01 -05:00
if ( ! ShaderPreloadEntry . bNeverToBePreloaded )
2021-06-10 09:36:47 -04:00
{
2021-11-07 23:43:01 -05:00
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs - - ;
check ( ShaderNumRefs > 0u ) ;
if ( ShaderNumRefs = = 1u )
{
ShaderPreloadEntry . IoRequest = FIoRequest ( ) ;
ShaderPreloadEntry . PreloadEvent . SafeRelease ( ) ;
const FIoStoreShaderCodeEntry & ShaderEntry = ShaderEntries [ ShaderIndex ] ;
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderPreloadMemory , ShaderEntry . CompressedSize ) ;
return true ;
}
return false ;
2021-06-10 09:36:47 -04:00
}
2021-11-07 23:43:01 -05:00
return true ;
2021-06-10 09:36:47 -04:00
}
void FIoStoreShaderCodeArchive : : ReleasePreloadedShader ( int32 ShaderIndex )
{
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
ReleaseRef ( ShaderIndex ) ;
}
int32 FIoStoreShaderCodeArchive : : FindShaderMapIndex ( const FSHAHash & Hash )
{
const uint32 Key = GetTypeHash ( Hash ) ;
for ( uint32 Index = ShaderMapHashTable . First ( Key ) ; ShaderMapHashTable . IsValid ( Index ) ; Index = ShaderMapHashTable . Next ( Index ) )
{
if ( ShaderMapHashes [ Index ] = = Hash )
{
return Index ;
}
}
return INDEX_NONE ;
}
int32 FIoStoreShaderCodeArchive : : FindShaderIndex ( const FSHAHash & Hash )
{
const uint32 Key = GetTypeHash ( Hash ) ;
for ( uint32 Index = ShaderHashTable . First ( Key ) ; ShaderHashTable . IsValid ( Index ) ; Index = ShaderHashTable . Next ( Index ) )
{
if ( ShaderHashes [ Index ] = = Hash )
{
return Index ;
}
}
return INDEX_NONE ;
}
TRefCountPtr < FRHIShader > FIoStoreShaderCodeArchive : : CreateShader ( int32 Index )
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
TRefCountPtr < FRHIShader > Shader ;
const FIoStoreShaderCodeEntry & ShaderEntry = ShaderEntries [ Index ] ;
FShaderPreloadEntry & ShaderPreloadEntry = ShaderPreloads [ Index ] ;
FGraphEventRef Event ;
{
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs + + ;
if ( ShaderNumRefs = = 0u )
{
check ( ! ShaderPreloadEntry . PreloadEvent ) ;
ShaderPreloadEntry . PreloadEvent = FGraphEvent : : CreateGraphEvent ( ) ;
FIoBatch IoBatch = IoDispatcher . NewBatch ( ) ;
ShaderPreloadEntry . IoRequest = IoBatch . Read ( GetShaderCodeChunkId ( ShaderHashes [ Index ] ) , FIoReadOptions ( ) , IoDispatcherPriority_Max ) ;
IoBatch . IssueAndDispatchSubsequents ( ShaderPreloadEntry . PreloadEvent ) ;
}
else if ( ! ShaderPreloadEntry . IoRequest . Status ( ) . IsCompleted ( ) )
{
ShaderPreloadEntry . IoRequest . UpdatePriority ( IoDispatcherPriority_Max ) ;
}
Event = ShaderPreloadEntry . PreloadEvent ;
}
const bool bNeededToWait = ! Event - > IsComplete ( ) ;
if ( bNeededToWait )
{
TRACE_CPUPROFILER_EVENT_SCOPE ( BlockingShaderLoad ) ;
UE_LOG ( LogShaderLibrary , Warning , TEXT ( " Blocking wait for shader preload, NumRefs: %d, FramePreloadStarted: %d " ) , ShaderPreloadEntry . NumRefs , ShaderPreloadEntry . FramePreloadStarted ) ;
FTaskGraphInterface : : Get ( ) . WaitUntilTaskCompletes ( Event ) ;
}
2021-10-12 21:21:22 -04:00
const uint8 * ShaderCode = ShaderPreloadEntry . IoRequest . GetResultOrDie ( ) . Data ( ) ;
2021-06-10 09:36:47 -04:00
FMemStackBase & MemStack = FMemStack : : Get ( ) ;
FMemMark Mark ( MemStack ) ;
if ( ShaderEntry . UncompressedSize ! = ShaderEntry . CompressedSize )
{
void * UncompressedCode = MemStack . Alloc ( ShaderEntry . UncompressedSize , 16 ) ;
const bool bDecompressResult = FCompression : : UncompressMemory ( GetShaderCompressionFormat ( ) , UncompressedCode , ShaderEntry . UncompressedSize , ShaderCode , ShaderEntry . CompressedSize ) ;
check ( bDecompressResult ) ;
ShaderCode = ( uint8 * ) UncompressedCode ;
}
const auto ShaderCodeView = MakeArrayView ( ShaderCode , ShaderEntry . UncompressedSize ) ;
const FSHAHash & ShaderHash = ShaderHashes [ Index ] ;
switch ( ShaderEntry . Frequency )
{
case SF_Vertex : Shader = RHICreateVertexShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Mesh : Shader = RHICreateMeshShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Amplification : Shader = RHICreateAmplificationShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Pixel : Shader = RHICreatePixelShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Geometry : Shader = RHICreateGeometryShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Compute : Shader = RHICreateComputeShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_RayGen : case SF_RayMiss : case SF_RayHitGroup : case SF_RayCallable :
# if RHI_RAYTRACING
2021-11-23 10:25:31 -05:00
if ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders )
2021-06-10 09:36:47 -04:00
{
Shader = RHICreateRayTracingShader ( ShaderCodeView , ShaderHash , ShaderEntry . GetFrequency ( ) ) ;
}
# endif // RHI_RAYTRACING
break ;
default : checkNoEntry ( ) ; break ;
}
{
FWriteScopeLock Lock ( ShaderPreloadLock ) ;
const uint32 ShaderNumRefs = ShaderPreloadEntry . NumRefs - - ;
check ( ShaderNumRefs > 0u ) ;
if ( ShaderNumRefs = = 1u )
{
ShaderPreloadEntry . PreloadEvent . SafeRelease ( ) ;
ShaderPreloadEntry . IoRequest = FIoRequest ( ) ;
}
}
if ( Shader )
{
Shader - > SetHash ( ShaderHash ) ;
}
return Shader ;
}