2020-02-07 11:01:05 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2020-02-06 13:13:41 -05:00
/*=============================================================================
Shader . cpp : Shader implementation .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "Shader.h"
2023-01-27 14:54:10 -05:00
# include "Misc/App.h"
2020-02-06 13:13:41 -05:00
# include "Misc/CoreMisc.h"
2020-04-21 13:46:17 -04:00
# include "Misc/StringBuilder.h"
2020-02-06 13:13:41 -05:00
# include "VertexFactory.h"
# include "ShaderCodeLibrary.h"
# include "ShaderCore.h"
# include "Misc/ScopeLock.h"
# include "UObject/RenderingObjectVersion.h"
2022-12-02 13:38:49 -05:00
# include "DataDrivenShaderPlatformInfo.h"
2020-02-06 13:13:41 -05:00
2021-10-12 21:21:22 -04:00
static EShaderPermutationFlags GetCurrentShaderPermutationFlags ( )
{
EShaderPermutationFlags Result = EShaderPermutationFlags : : None ;
# if WITH_EDITORONLY_DATA
Result | = EShaderPermutationFlags : : HasEditorOnlyData ;
# endif
return Result ;
}
2020-10-27 16:35:01 -04:00
FShaderMapBase : : FShaderMapBase ( )
: PointerTable ( nullptr )
2020-02-06 13:13:41 -05:00
, NumFrozenShaders ( 0u )
2021-10-12 21:21:22 -04:00
{
PermutationFlags = GetCurrentShaderPermutationFlags ( ) ;
}
2020-02-06 13:13:41 -05:00
FShaderMapBase : : ~ FShaderMapBase ( )
{
DestroyContent ( ) ;
if ( PointerTable )
{
delete PointerTable ;
}
}
FShaderMapResourceCode * FShaderMapBase : : GetResourceCode ( )
{
if ( ! Code )
{
Code = new FShaderMapResourceCode ( ) ;
}
return Code ;
}
2020-10-27 16:35:01 -04:00
void FShaderMapBase : : AssignContent ( TMemoryImageObject < FShaderMapContent > InContent )
2020-10-22 19:19:16 -04:00
{
2020-10-27 16:35:01 -04:00
check ( ! Content . Object ) ;
2020-02-06 13:13:41 -05:00
check ( ! PointerTable ) ;
2020-10-27 16:35:01 -04:00
const FTypeLayoutDesc & ExpectedTypeDesc = GetContentTypeDesc ( ) ;
checkf ( * InContent . TypeDesc = = ExpectedTypeDesc , TEXT ( " FShaderMapBase expected content of type %s, got %s " ) , ExpectedTypeDesc . Name , InContent . TypeDesc - > Name ) ;
2020-02-06 13:13:41 -05:00
Content = InContent ;
PointerTable = CreatePointerTable ( ) ;
2021-08-19 23:56:04 -04:00
PostFinalizeContent ( ) ;
2020-02-06 13:13:41 -05:00
}
2020-10-27 16:35:01 -04:00
void FShaderMapBase : : AssignCopy ( const FShaderMapBase & Source )
{
check ( ! PointerTable ) ;
check ( ! Code ) ;
check ( Source . Content . Object ) ;
if ( Source . Content . FrozenSize = = 0u )
{
PointerTable = CreatePointerTable ( ) ;
Content = TMemoryImageObject < FShaderMapContent > ( FreezeMemoryImageObject ( Source . Content . Object , * Source . Content . TypeDesc , PointerTable ) ) ;
}
else
{
PointerTable = Source . PointerTable - > Clone ( ) ;
Content . TypeDesc = Source . Content . TypeDesc ;
Content . FrozenSize = Source . Content . FrozenSize ;
Content . Object = static_cast < FShaderMapContent * > ( FMemory : : Malloc ( Content . FrozenSize ) ) ;
FMemory : : Memcpy ( Content . Object , Source . Content . Object , Content . FrozenSize ) ;
}
NumFrozenShaders = Content . Object - > GetNumShaders ( ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , Content . FrozenSize ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
Code = new FShaderMapResourceCode ( * Source . Code ) ;
InitResource ( ) ;
}
2020-10-22 19:19:16 -04:00
void FShaderMapBase : : InitResource ( )
2020-02-06 13:13:41 -05:00
{
2020-10-22 19:19:16 -04:00
Resource . SafeRelease ( ) ;
if ( Code )
2020-02-06 13:13:41 -05:00
{
2020-10-22 19:19:16 -04:00
Code - > Finalize ( ) ;
Resource = new FShaderMapResource_InlineCode ( GetShaderPlatform ( ) , Code ) ;
BeginInitResource ( Resource ) ;
}
2021-08-19 23:56:04 -04:00
PostFinalizeContent ( ) ;
2020-10-22 19:19:16 -04:00
}
2020-10-27 16:35:01 -04:00
void FShaderMapBase : : FinalizeContent ( )
2020-10-22 19:19:16 -04:00
{
2020-10-27 16:35:01 -04:00
if ( Content . Freeze ( PointerTable ) )
2020-10-22 19:19:16 -04:00
{
2020-10-27 16:35:01 -04:00
NumFrozenShaders = Content . Object - > GetNumShaders ( ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , Content . FrozenSize ) ;
2020-02-06 13:13:41 -05:00
INC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
}
2020-10-27 16:35:01 -04:00
InitResource ( ) ;
2020-02-06 13:13:41 -05:00
}
void FShaderMapBase : : UnfreezeContent ( )
{
2020-10-27 16:35:01 -04:00
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , Content . FrozenSize ) ;
DEC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
Content . Unfreeze ( PointerTable ) ;
NumFrozenShaders = 0u ;
2020-02-06 13:13:41 -05:00
}
2020-03-12 20:19:35 -04:00
# define CHECK_SHADERMAP_DEPENDENCIES (WITH_EDITOR || !(UE_BUILD_SHIPPING || UE_BUILD_TEST))
2020-02-06 13:13:41 -05:00
2020-06-23 18:40:00 -04:00
bool FShaderMapBase : : Serialize ( FArchive & Ar , bool bInlineShaderResources , bool bLoadedByCookedMaterial , bool bInlineShaderCode )
2020-02-06 13:13:41 -05:00
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
if ( Ar . IsSaving ( ) )
{
2020-10-27 16:35:01 -04:00
check ( Content . Object ) ;
Content . Object - > Validate ( * this ) ;
2020-02-06 13:13:41 -05:00
{
2020-10-27 16:35:01 -04:00
TUniquePtr < FShaderMapPointerTable > SavePointerTable ( CreatePointerTable ( ) ) ;
FMemoryImage MemoryImage ;
MemoryImage . PrevPointerTable = PointerTable ;
MemoryImage . PointerTable = SavePointerTable . Get ( ) ;
MemoryImage . TargetLayoutParameters . InitializeForArchive ( Ar ) ;
FMemoryImageWriter Writer ( MemoryImage ) ;
Writer . WriteRootObject ( Content . Object , * Content . TypeDesc ) ;
FMemoryImageResult MemoryImageResult ;
MemoryImage . Flatten ( MemoryImageResult , true ) ;
MemoryImageResult . SaveToArchive ( Ar ) ;
2020-02-06 13:13:41 -05:00
}
bool bShareCode = false ;
# if WITH_EDITOR
2020-12-11 14:21:20 -04:00
bShareCode = ! bInlineShaderCode & & FShaderLibraryCooker : : IsShaderLibraryEnabled ( ) & & Ar . IsCooking ( ) ;
2020-02-06 13:13:41 -05:00
# endif // WITH_EDITOR
Ar < < bShareCode ;
# if WITH_EDITOR
2020-10-27 16:35:01 -04:00
// Serialize a copy of ShaderPlatform directly into the archive
// This will allow us to correctly deserialize the stream, even if we're not able to load the frozen content
2022-10-31 11:06:18 -04:00
const EShaderPlatform ShaderPlatform = GetShaderPlatform ( ) ;
2022-12-16 05:02:56 -05:00
FName ShaderPlatformName = FDataDrivenShaderPlatformInfo : : GetName ( ShaderPlatform ) ;
2022-10-31 11:06:18 -04:00
Ar < < ShaderPlatformName ;
2020-10-27 16:35:01 -04:00
2020-03-02 21:52:09 -05:00
if ( Ar . IsCooking ( ) )
{
2021-08-16 23:18:23 -04:00
const FName ShaderFormat = LegacyShaderPlatformToShaderFormat ( ShaderPlatform ) ;
if ( ShaderFormat ! = NAME_None )
{
Code - > NotifyShadersCompiled ( ShaderFormat ) ;
}
2020-03-02 21:52:09 -05:00
}
2020-02-06 13:13:41 -05:00
if ( bShareCode )
{
FSHAHash ResourceHash = Code - > ResourceHash ;
Ar < < ResourceHash ;
2022-12-16 05:02:56 -05:00
FShaderLibraryCooker : : AddShaderCode ( ShaderPlatform , Code , GetAssociatedAssets ( ) ) ;
2020-02-06 13:13:41 -05:00
}
else
# endif // WITH_EDITOR
{
2020-03-02 21:52:09 -05:00
Code - > Serialize ( Ar , bLoadedByCookedMaterial ) ;
2020-02-06 13:13:41 -05:00
}
}
else
{
check ( ! PointerTable ) ;
PointerTable = CreatePointerTable ( ) ;
2021-10-12 21:21:22 -04:00
FPlatformTypeLayoutParameters LayoutParameters ;
FMemoryImageObject LoadedContent = FMemoryImageResult : : LoadFromArchive ( Ar , GetContentTypeDesc ( ) , PointerTable , LayoutParameters ) ;
PermutationFlags = GetShaderPermutationFlags ( LayoutParameters ) ;
2020-03-03 19:38:43 -05:00
2020-02-06 13:13:41 -05:00
bool bShareCode = false ;
Ar < < bShareCode ;
2020-10-27 16:35:01 -04:00
2022-12-16 05:02:56 -05:00
FName ShaderPlatformName ;
2022-10-31 11:06:18 -04:00
Ar < < ShaderPlatformName ;
2022-12-16 05:02:56 -05:00
const EShaderPlatform ShaderPlatform = FDataDrivenShaderPlatformInfo : : GetShaderPlatformFromName ( ShaderPlatformName ) ;
2020-10-27 16:35:01 -04:00
2020-02-06 13:13:41 -05:00
if ( bShareCode )
{
FSHAHash ResourceHash ;
Ar < < ResourceHash ;
Resource = FShaderCodeLibrary : : LoadResource ( ResourceHash , & Ar ) ;
2020-03-12 20:19:35 -04:00
if ( ! Resource )
2020-02-25 13:39:14 -05:00
{
2020-04-02 16:00:42 -04:00
// do not warn when running -nullrhi (the resource cannot be created as the shader library will not be uninitialized),
// also do not warn for shader platforms other than current (if the game targets more than one RHI)
2020-10-27 16:35:01 -04:00
if ( FApp : : CanEverRender ( ) & & ShaderPlatform = = GMaxRHIShaderPlatform )
2020-04-01 20:32:33 -04:00
{
2021-06-07 20:09:45 -04:00
UE_LOG ( LogShaders , Error , TEXT ( " Missing shader resource for hash '%s' for shader platform '%s' in the shader library " ) , * ResourceHash . ToString ( ) , * LexToString ( ShaderPlatform ) ) ;
2020-04-01 20:32:33 -04:00
}
2020-02-25 13:39:14 -05:00
}
2020-02-06 13:13:41 -05:00
}
else
{
Code = new FShaderMapResourceCode ( ) ;
2020-03-02 21:52:09 -05:00
Code - > Serialize ( Ar , bLoadedByCookedMaterial ) ;
2020-10-27 16:35:01 -04:00
Resource = new FShaderMapResource_InlineCode ( ShaderPlatform , Code ) ;
2020-02-06 13:13:41 -05:00
}
2020-10-27 16:35:01 -04:00
if ( LoadedContent . Object & & Resource )
2020-02-25 13:39:14 -05:00
{
2020-10-27 16:35:01 -04:00
Content = TMemoryImageObject < FShaderMapContent > ( LoadedContent ) ;
// Possible we've loaded/converted unfrozen content, make sure it's frozen for the current platform before trying to render anything
if ( Content . FrozenSize = = 0u )
{
Content . Freeze ( PointerTable ) ;
}
2021-08-19 23:56:04 -04:00
PostFinalizeContent ( ) ;
2020-10-27 16:35:01 -04:00
NumFrozenShaders = Content . Object - > GetNumShaders ( ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , Content . FrozenSize ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
2020-03-12 20:19:35 -04:00
2020-02-25 13:39:14 -05:00
BeginInitResource ( Resource ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Resource - > GetSizeBytes ( ) ) ;
}
2020-03-12 20:19:35 -04:00
else
{
2020-10-27 16:35:01 -04:00
// Missing either content and/or resource
// In either case, shader map has failed to load
LoadedContent . Destroy ( PointerTable ) ;
2020-03-12 20:19:35 -04:00
Resource . SafeRelease ( ) ;
}
2020-02-06 13:13:41 -05:00
}
2020-03-12 20:19:35 -04:00
2020-10-27 16:35:01 -04:00
return ( bool ) Content . Object ;
2020-02-06 13:13:41 -05:00
}
2020-04-21 13:46:17 -04:00
FString FShaderMapBase : : ToString ( ) const
{
TStringBuilder < 32000 > String ;
{
FMemoryToStringContext Context ;
Context . PrevPointerTable = PointerTable ;
Context . String = & String ;
FPlatformTypeLayoutParameters LayoutParams ;
LayoutParams . InitializeForCurrent ( ) ;
2020-10-27 16:35:01 -04:00
Content . TypeDesc - > ToStringFunc ( Content . Object , * Content . TypeDesc , LayoutParams , Context ) ;
2020-04-21 13:46:17 -04:00
}
if ( Code )
{
Code - > ToString ( String ) ;
}
return String . ToString ( ) ;
}
2020-02-06 13:13:41 -05:00
void FShaderMapBase : : DestroyContent ( )
{
2020-10-27 16:35:01 -04:00
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , Content . FrozenSize ) ;
DEC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
Content . Destroy ( PointerTable ) ;
NumFrozenShaders = 0u ;
2020-02-06 13:13:41 -05:00
}
2020-04-06 21:12:18 -04:00
static uint16 MakeShaderHash ( const FHashedName & TypeName , int32 PermutationId )
{
return ( uint16 ) CityHash128to64 ( { TypeName . GetHash ( ) , ( uint64 ) PermutationId } ) ;
}
2022-12-02 13:38:49 -05:00
FShaderMapContent : : FShaderMapContent ( EShaderPlatform InPlatform )
2022-12-16 05:02:56 -05:00
: ShaderHash ( 128u ) , ShaderPlatformName ( FDataDrivenShaderPlatformInfo : : GetName ( InPlatform ) )
2022-12-02 13:38:49 -05:00
{ }
FShaderMapContent : : ~ FShaderMapContent ( )
{
Empty ( ) ;
}
EShaderPlatform FShaderMapContent : : GetShaderPlatform ( ) const
{
2022-12-16 05:02:56 -05:00
return FDataDrivenShaderPlatformInfo : : GetShaderPlatformFromName ( ShaderPlatformName ) ;
2022-12-02 13:38:49 -05:00
}
2020-02-06 13:13:41 -05:00
FShader * FShaderMapContent : : GetShader ( const FHashedName & TypeName , int32 PermutationId ) const
{
2021-03-13 07:09:37 -04:00
// TRACE_CPUPROFILER_EVENT_SCOPE(FShaderMapContent::GetShader); -- this function is called too frequently, so don't add the scope by default
2020-04-06 21:12:18 -04:00
const uint16 Hash = MakeShaderHash ( TypeName , PermutationId ) ;
const FHashedName * RESTRICT LocalShaderTypes = ShaderTypes . GetData ( ) ;
const int32 * RESTRICT LocalShaderPermutations = ShaderPermutations . GetData ( ) ;
const uint32 * RESTRICT LocalNextHashIndices = ShaderHash . GetNextIndices ( ) ;
const uint32 NumShaders = Shaders . Num ( ) ;
2020-02-06 13:13:41 -05:00
2020-04-06 21:12:18 -04:00
for ( uint32 Index = ShaderHash . First ( Hash ) ; ShaderHash . IsValid ( Index ) ; Index = LocalNextHashIndices [ Index ] )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
checkSlow ( Index < NumShaders ) ;
if ( LocalShaderTypes [ Index ] = = TypeName & & LocalShaderPermutations [ Index ] = = PermutationId )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
return Shaders [ Index ] . GetChecked ( ) ;
2020-02-06 13:13:41 -05:00
}
}
2020-04-06 21:12:18 -04:00
return nullptr ;
}
void FShaderMapContent : : AddShader ( const FHashedName & TypeName , int32 PermutationId , FShader * Shader )
{
check ( ! Shader - > IsFrozen ( ) ) ;
checkSlow ( ! HasShader ( TypeName , PermutationId ) ) ;
const uint16 Hash = MakeShaderHash ( TypeName , PermutationId ) ;
const int32 Index = Shaders . Add ( Shader ) ;
ShaderTypes . Add ( TypeName ) ;
ShaderPermutations . Add ( PermutationId ) ;
check ( ShaderTypes . Num ( ) = = Shaders . Num ( ) ) ;
check ( ShaderPermutations . Num ( ) = = Shaders . Num ( ) ) ;
ShaderHash . Add ( Hash , Index ) ;
}
FShader * FShaderMapContent : : FindOrAddShader ( const FHashedName & TypeName , int32 PermutationId , FShader * Shader )
{
check ( ! Shader - > IsFrozen ( ) ) ;
const uint16 Hash = MakeShaderHash ( TypeName , PermutationId ) ;
for ( uint32 Index = ShaderHash . First ( Hash ) ; ShaderHash . IsValid ( Index ) ; Index = ShaderHash . Next ( Index ) )
{
if ( ShaderTypes [ Index ] = = TypeName & & ShaderPermutations [ Index ] = = PermutationId )
{
DeleteObjectFromLayout ( Shader ) ;
return Shaders [ Index ] . GetChecked ( ) ;
}
}
const int32 Index = Shaders . Add ( Shader ) ;
ShaderHash . Add ( Hash , Index ) ;
ShaderTypes . Add ( TypeName ) ;
ShaderPermutations . Add ( PermutationId ) ;
check ( ShaderTypes . Num ( ) = = Shaders . Num ( ) ) ;
check ( ShaderPermutations . Num ( ) = = Shaders . Num ( ) ) ;
2020-02-06 13:13:41 -05:00
return Shader ;
}
void FShaderMapContent : : AddShaderPipeline ( FShaderPipeline * Pipeline )
{
checkSlow ( ! HasShaderPipeline ( Pipeline - > TypeName ) ) ;
const int32 Index = Algo : : LowerBoundBy ( ShaderPipelines , Pipeline - > TypeName , FProjectShaderPipelineToKey ( ) ) ;
ShaderPipelines . Insert ( Pipeline , Index ) ;
}
FShaderPipeline * FShaderMapContent : : FindOrAddShaderPipeline ( FShaderPipeline * Pipeline )
{
const int32 Index = Algo : : LowerBoundBy ( ShaderPipelines , Pipeline - > TypeName , FProjectShaderPipelineToKey ( ) ) ;
if ( Index < ShaderPipelines . Num ( ) )
{
FShaderPipeline * PrevShaderPipeline = ShaderPipelines [ Index ] ;
if ( PrevShaderPipeline - > TypeName = = Pipeline - > TypeName )
{
delete Pipeline ;
return PrevShaderPipeline ;
}
}
ShaderPipelines . Insert ( Pipeline , Index ) ;
return Pipeline ;
}
/**
* Removes the shader of the given type from the shader map
* @ param Type Shader type to remove the entry for
*/
2020-04-06 21:12:18 -04:00
void FShaderMapContent : : RemoveShaderTypePermutaion ( const FHashedName & TypeName , int32 PermutationId )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
const uint16 Hash = MakeShaderHash ( TypeName , PermutationId ) ;
for ( uint32 Index = ShaderHash . First ( Hash ) ; ShaderHash . IsValid ( Index ) ; Index = ShaderHash . Next ( Index ) )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
FShader * Shader = Shaders [ Index ] . GetChecked ( ) ;
if ( ShaderTypes [ Index ] = = TypeName & & ShaderPermutations [ Index ] = = PermutationId )
{
DeleteObjectFromLayout ( Shader ) ;
2020-04-13 14:29:28 -04:00
// Replace the shader we're removing with the last shader in the list
2020-04-06 21:12:18 -04:00
Shaders . RemoveAtSwap ( Index , 1 , false ) ;
ShaderTypes . RemoveAtSwap ( Index , 1 , false ) ;
ShaderPermutations . RemoveAtSwap ( Index , 1 , false ) ;
check ( ShaderTypes . Num ( ) = = Shaders . Num ( ) ) ;
check ( ShaderPermutations . Num ( ) = = Shaders . Num ( ) ) ;
ShaderHash . Remove ( Hash , Index ) ;
2020-04-13 14:29:28 -04:00
// SwapIndex is the old index of the shader at the end of the list, that's now been moved to replace the current shader
2020-04-06 21:12:18 -04:00
const int32 SwapIndex = Shaders . Num ( ) ;
2020-04-13 14:29:28 -04:00
if ( Index ! = SwapIndex )
2020-04-06 21:12:18 -04:00
{
2020-04-13 14:29:28 -04:00
// We need to update the hash table to reflect shader previously at SwapIndex being moved to Index
// Here we construct the hash from values at Index, since type/permutation have already been moved
2020-04-06 21:12:18 -04:00
const uint16 SwapHash = MakeShaderHash ( ShaderTypes [ Index ] , ShaderPermutations [ Index ] ) ;
ShaderHash . Remove ( SwapHash , SwapIndex ) ;
ShaderHash . Add ( SwapHash , Index ) ;
}
2020-04-27 22:11:56 -04:00
2020-04-06 21:12:18 -04:00
break ;
}
2020-02-06 13:13:41 -05:00
}
}
void FShaderMapContent : : RemoveShaderPipelineType ( const FShaderPipelineType * ShaderPipelineType )
{
const int32 Index = Algo : : BinarySearchBy ( ShaderPipelines , ShaderPipelineType - > GetHashedName ( ) , FProjectShaderPipelineToKey ( ) ) ;
if ( Index ! = INDEX_NONE )
{
FShaderPipeline * Pipeline = ShaderPipelines [ Index ] ;
delete Pipeline ;
ShaderPipelines . RemoveAt ( Index , 1 , false ) ;
}
}
void FShaderMapContent : : GetShaderList ( const FShaderMapBase & InShaderMap , const FSHAHash & InMaterialShaderMapHash , TMap < FShaderId , TShaderRef < FShader > > & OutShaders ) const
{
2020-04-06 21:12:18 -04:00
for ( int32 ShaderIndex = 0 ; ShaderIndex < Shaders . Num ( ) ; + + ShaderIndex )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
FShader * Shader = Shaders [ ShaderIndex ] . GetChecked ( ) ;
2020-02-06 13:13:41 -05:00
const FShaderId ShaderId (
Shader - > GetType ( InShaderMap . GetPointerTable ( ) ) ,
InMaterialShaderMapHash ,
FHashedName ( ) ,
Shader - > GetVertexFactoryType ( InShaderMap . GetPointerTable ( ) ) ,
2020-04-06 21:12:18 -04:00
ShaderPermutations [ ShaderIndex ] ,
2020-02-06 13:13:41 -05:00
GetShaderPlatform ( ) ) ;
OutShaders . Add ( ShaderId , TShaderRef < FShader > ( Shader , InShaderMap ) ) ;
}
for ( const FShaderPipeline * ShaderPipeline : ShaderPipelines )
{
2020-04-06 21:12:18 -04:00
for ( uint32 Frequency = 0u ; Frequency < SF_NumGraphicsFrequencies ; + + Frequency )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
FShader * Shader = ShaderPipeline - > Shaders [ Frequency ] . Get ( ) ;
if ( Shader )
{
const FShaderId ShaderId (
Shader - > GetType ( InShaderMap . GetPointerTable ( ) ) ,
InMaterialShaderMapHash ,
ShaderPipeline - > TypeName ,
Shader - > GetVertexFactoryType ( InShaderMap . GetPointerTable ( ) ) ,
ShaderPipeline - > PermutationIds [ Frequency ] ,
GetShaderPlatform ( ) ) ;
OutShaders . Add ( ShaderId , TShaderRef < FShader > ( Shader , InShaderMap ) ) ;
}
2020-02-06 13:13:41 -05:00
}
}
}
void FShaderMapContent : : GetShaderList ( const FShaderMapBase & InShaderMap , TMap < FHashedName , TShaderRef < FShader > > & OutShaders ) const
{
2020-04-06 21:12:18 -04:00
for ( int32 ShaderIndex = 0 ; ShaderIndex < Shaders . Num ( ) ; + + ShaderIndex )
2020-02-06 13:13:41 -05:00
{
2023-04-04 15:06:09 -04:00
FShader * Shader = Shaders [ ShaderIndex ] . Get ( ) ;
if ( ensure ( Shader ) )
{
OutShaders . Add ( ShaderTypes [ ShaderIndex ] , TShaderRef < FShader > ( Shader , InShaderMap ) ) ;
}
2020-02-06 13:13:41 -05:00
}
for ( const FShaderPipeline * ShaderPipeline : ShaderPipelines )
{
for ( const TShaderRef < FShader > & Shader : ShaderPipeline - > GetShaders ( InShaderMap ) )
{
2020-04-06 21:12:18 -04:00
OutShaders . Add ( Shader . GetType ( ) - > GetHashedName ( ) , Shader ) ;
2020-02-06 13:13:41 -05:00
}
}
}
void FShaderMapContent : : GetShaderPipelineList ( const FShaderMapBase & InShaderMap , TArray < FShaderPipelineRef > & OutShaderPipelines , FShaderPipeline : : EFilter Filter ) const
{
2022-10-31 11:06:18 -04:00
const EShaderPlatform ShaderPlatform = GetShaderPlatform ( ) ;
2020-02-06 13:13:41 -05:00
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
const FShaderPipelineType * PipelineType = FShaderPipelineType : : GetShaderPipelineTypeByName ( Pipeline - > TypeName ) ;
2022-10-31 11:06:18 -04:00
if ( PipelineType - > ShouldOptimizeUnusedOutputs ( ShaderPlatform ) & & Filter = = FShaderPipeline : : EOnlyShared )
2020-02-06 13:13:41 -05:00
{
continue ;
}
2022-10-31 11:06:18 -04:00
else if ( ! PipelineType - > ShouldOptimizeUnusedOutputs ( ShaderPlatform ) & & Filter = = FShaderPipeline : : EOnlyUnique )
2020-02-06 13:13:41 -05:00
{
continue ;
}
OutShaderPipelines . Add ( FShaderPipelineRef ( Pipeline , InShaderMap ) ) ;
}
}
2020-10-22 19:19:16 -04:00
void FShaderMapContent : : Validate ( const FShaderMapBase & InShaderMap ) const
2020-02-06 13:13:41 -05:00
{
2020-10-22 19:19:16 -04:00
for ( const FShader * Shader : Shaders )
2020-02-06 13:13:41 -05:00
{
checkf ( Shader - > GetResourceIndex ( ) ! = INDEX_NONE , TEXT ( " Missing resource for %s " ) , Shader - > GetType ( InShaderMap . GetPointerTable ( ) ) - > GetName ( ) ) ;
}
/*for(FShaderPipeline* Pipeline : ShaderPipelines)
{
for ( const TShaderRef < FShader > & Shader : Pipeline - > GetShaders ( InPtrTable ) )
{
checkf ( Shader . GetResource ( ) , TEXT ( " Missing resource for %s " ) , Shader . GetType ( ) - > GetName ( ) ) ;
}
} */
}
# if WITH_EDITOR
static bool CheckOutdatedShaderType ( EShaderPlatform Platform , const TShaderRef < FShader > & Shader , TArray < const FShaderType * > & OutdatedShaderTypes , TArray < const FVertexFactoryType * > & OutdatedFactoryTypes )
{
const FShaderType * Type = Shader . GetType ( ) ;
const bool bOutdatedShader = Type - > GetSourceHash ( Platform ) ! = Shader - > GetHash ( ) ;
const FVertexFactoryType * VFType = Shader . GetVertexFactoryType ( ) ;
const bool bOutdatedVertexFactory = VFType & & VFType - > GetSourceHash ( Platform ) ! = Shader - > GetVertexFactoryHash ( ) ;
if ( bOutdatedShader )
{
OutdatedShaderTypes . AddUnique ( Type ) ;
}
if ( bOutdatedVertexFactory )
{
OutdatedFactoryTypes . AddUnique ( VFType ) ;
}
return bOutdatedShader | | bOutdatedVertexFactory ;
}
void FShaderMapContent : : GetOutdatedTypes ( const FShaderMapBase & InShaderMap , TArray < const FShaderType * > & OutdatedShaderTypes , TArray < const FShaderPipelineType * > & OutdatedShaderPipelineTypes , TArray < const FVertexFactoryType * > & OutdatedFactoryTypes ) const
{
for ( FShader * Shader : Shaders )
{
CheckOutdatedShaderType ( GetShaderPlatform ( ) , TShaderRef < FShader > ( Shader , InShaderMap ) , OutdatedShaderTypes , OutdatedFactoryTypes ) ;
}
for ( const FShaderPipeline * Pipeline : ShaderPipelines )
{
for ( const TShaderRef < FShader > & Shader : Pipeline - > GetShaders ( InShaderMap ) )
{
if ( CheckOutdatedShaderType ( GetShaderPlatform ( ) , Shader , OutdatedShaderTypes , OutdatedFactoryTypes ) )
{
const FShaderPipelineType * PipelineType = FShaderPipelineType : : GetShaderPipelineTypeByName ( Pipeline - > TypeName ) ;
check ( PipelineType ) ;
OutdatedShaderPipelineTypes . AddUnique ( PipelineType ) ;
}
}
}
}
void FShaderMapContent : : SaveShaderStableKeys ( const FShaderMapBase & InShaderMap , EShaderPlatform TargetShaderPlatform , const struct FStableShaderKeyAndValue & SaveKeyVal )
{
2020-04-06 21:12:18 -04:00
for ( int32 ShaderIndex = 0 ; ShaderIndex < Shaders . Num ( ) ; + + ShaderIndex )
2020-02-06 13:13:41 -05:00
{
2020-04-06 21:12:18 -04:00
const int32 PermutationId = ShaderPermutations [ ShaderIndex ] ;
Shaders [ ShaderIndex ] - > SaveShaderStableKeys ( InShaderMap . GetPointerTable ( ) , TargetShaderPlatform , PermutationId , SaveKeyVal ) ;
2020-02-06 13:13:41 -05:00
}
for ( const FShaderPipeline * Pipeline : ShaderPipelines )
{
Pipeline - > SaveShaderStableKeys ( InShaderMap . GetPointerTable ( ) , TargetShaderPlatform , SaveKeyVal ) ;
}
}
uint32 FShaderMapContent : : GetMaxTextureSamplersShaderMap ( const FShaderMapBase & InShaderMap ) const
{
uint32 MaxTextureSamplers = 0 ;
for ( FShader * Shader : Shaders )
{
2023-04-04 15:06:09 -04:00
if ( ensure ( Shader ) )
{
MaxTextureSamplers = FMath : : Max ( MaxTextureSamplers , Shader - > GetNumTextureSamplers ( ) ) ;
}
2020-02-06 13:13:41 -05:00
}
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
for ( const TShaderRef < FShader > & Shader : Pipeline - > GetShaders ( InShaderMap ) )
{
MaxTextureSamplers = FMath : : Max ( MaxTextureSamplers , Shader - > GetNumTextureSamplers ( ) ) ;
}
}
return MaxTextureSamplers ;
}
# endif // WITH_EDITOR
uint32 FShaderMapContent : : GetNumShaders ( ) const
{
uint32 NumShaders = Shaders . Num ( ) ;
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
NumShaders + = Pipeline - > GetNumShaders ( ) ;
}
return NumShaders ;
}
uint32 FShaderMapContent : : GetMaxNumInstructionsForShader ( const FShaderMapBase & InShaderMap , FShaderType * ShaderType ) const
{
uint32 MaxNumInstructions = 0 ;
FShader * Shader = GetShader ( ShaderType ) ;
if ( Shader )
{
MaxNumInstructions = FMath : : Max ( MaxNumInstructions , Shader - > GetNumInstructions ( ) ) ;
}
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
FShader * PipelineShader = Pipeline - > GetShader ( ShaderType - > GetFrequency ( ) ) ;
if ( PipelineShader )
{
2022-02-23 08:41:47 -05:00
const FShaderType * PipelineShaderType = PipelineShader - > GetType ( InShaderMap . GetPointerTable ( ) ) ;
if ( PipelineShaderType & &
( PipelineShaderType = = ShaderType ) )
{
MaxNumInstructions = FMath : : Max ( MaxNumInstructions , PipelineShader - > GetNumInstructions ( ) ) ;
}
2020-02-06 13:13:41 -05:00
}
}
return MaxNumInstructions ;
}
2020-04-06 21:12:18 -04:00
struct FSortedShaderEntry
{
FHashedName TypeName ;
int32 PermutationId ;
int32 Index ;
friend bool operator < ( const FSortedShaderEntry & Lhs , const FSortedShaderEntry & Rhs )
{
if ( Lhs . TypeName ! = Rhs . TypeName )
{
return Lhs . TypeName < Rhs . TypeName ;
}
return Lhs . PermutationId < Rhs . PermutationId ;
}
} ;
2020-04-21 15:57:02 -04:00
void FShaderMapContent : : Finalize ( const FShaderMapResourceCode * Code )
2020-04-06 21:12:18 -04:00
{
2020-04-21 15:57:02 -04:00
check ( Code ) ;
for ( FShader * Shader : Shaders )
{
Shader - > Finalize ( Code ) ;
}
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
Pipeline - > Finalize ( Code ) ;
}
2020-04-06 21:12:18 -04:00
// Sort the shaders by type/permutation, so they are consistently ordered
TArray < FSortedShaderEntry > SortedEntries ;
SortedEntries . Empty ( Shaders . Num ( ) ) ;
for ( int32 ShaderIndex = 0 ; ShaderIndex < Shaders . Num ( ) ; + + ShaderIndex )
{
FSortedShaderEntry & Entry = SortedEntries . AddDefaulted_GetRef ( ) ;
Entry . TypeName = ShaderTypes [ ShaderIndex ] ;
Entry . PermutationId = ShaderPermutations [ ShaderIndex ] ;
Entry . Index = ShaderIndex ;
}
SortedEntries . Sort ( ) ;
// Choose a good hash size based on the number of shaders we have
const uint32 HashSize = FMath : : RoundUpToPowerOfTwo ( FMath : : Max ( ( Shaders . Num ( ) * 3 ) / 2 , 1 ) ) ;
FMemoryImageHashTable NewShaderHash ( HashSize , Shaders . Num ( ) ) ;
TMemoryImageArray < TMemoryImagePtr < FShader > > NewShaders ;
NewShaders . Empty ( Shaders . Num ( ) ) ;
ShaderTypes . Empty ( Shaders . Num ( ) ) ;
ShaderPermutations . Empty ( Shaders . Num ( ) ) ;
for ( int32 SortedIndex = 0 ; SortedIndex < SortedEntries . Num ( ) ; + + SortedIndex )
{
const FSortedShaderEntry & SortedEntry = SortedEntries [ SortedIndex ] ;
2020-04-21 13:46:17 -04:00
2020-04-06 21:12:18 -04:00
const uint16 Key = MakeShaderHash ( SortedEntry . TypeName , SortedEntry . PermutationId ) ;
NewShaders . Add ( Shaders [ SortedEntry . Index ] ) ;
ShaderTypes . Add ( SortedEntry . TypeName ) ;
ShaderPermutations . Add ( SortedEntry . PermutationId ) ;
NewShaderHash . Add ( Key , SortedIndex ) ;
}
Shaders = MoveTemp ( NewShaders ) ;
ShaderHash = MoveTemp ( NewShaderHash ) ;
}
void FShaderMapContent : : UpdateHash ( FSHA1 & Hasher ) const
{
for ( int32 ShaderIndex = 0 ; ShaderIndex < Shaders . Num ( ) ; + + ShaderIndex )
{
2020-09-24 00:43:27 -04:00
const uint64 TypeNameHash = ShaderTypes [ ShaderIndex ] . GetHash ( ) ;
2020-04-06 21:12:18 -04:00
const int32 PermutationId = ShaderPermutations [ ShaderIndex ] ;
2020-09-24 00:43:27 -04:00
Hasher . Update ( ( uint8 * ) & TypeNameHash , sizeof ( TypeNameHash ) ) ;
2020-04-06 21:12:18 -04:00
Hasher . Update ( ( uint8 * ) & PermutationId , sizeof ( PermutationId ) ) ;
}
for ( const FShaderPipeline * Pipeline : GetShaderPipelines ( ) )
{
2020-09-24 00:43:27 -04:00
const uint64 TypeNameHash = Pipeline - > TypeName . GetHash ( ) ;
Hasher . Update ( ( uint8 * ) & TypeNameHash , sizeof ( TypeNameHash ) ) ;
2020-04-06 21:12:18 -04:00
}
}
2021-05-11 16:29:41 -04:00
void FShaderMapContent : : Empty ( )
2020-02-06 13:13:41 -05:00
{
2021-05-11 16:29:41 -04:00
EmptyShaderPipelines ( ) ;
2020-02-06 13:13:41 -05:00
for ( int32 i = 0 ; i < Shaders . Num ( ) ; + + i )
{
2020-10-22 19:19:16 -04:00
TMemoryImagePtr < FShader > & Shader = Shaders [ i ] ;
2021-05-11 16:29:41 -04:00
Shader . SafeDelete ( ) ;
2020-02-06 13:13:41 -05:00
}
Shaders . Empty ( ) ;
2020-04-06 21:12:18 -04:00
ShaderTypes . Empty ( ) ;
ShaderPermutations . Empty ( ) ;
ShaderHash . Clear ( ) ;
2020-02-06 13:13:41 -05:00
}
2021-05-11 16:29:41 -04:00
void FShaderMapContent : : EmptyShaderPipelines ( )
2020-02-06 13:13:41 -05:00
{
for ( TMemoryImagePtr < FShaderPipeline > & Pipeline : ShaderPipelines )
{
2021-05-11 16:29:41 -04:00
Pipeline . SafeDelete ( ) ;
2020-02-06 13:13:41 -05:00
}
ShaderPipelines . Empty ( ) ;
2023-01-27 14:54:10 -05:00
}