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"
# 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 "Stats/StatsMisc.h"
# include "Serialization/MemoryWriter.h"
# include "VertexFactory.h"
# include "ProfilingDebugging/DiagnosticTable.h"
# include "Interfaces/ITargetPlatform.h"
# include "Interfaces/ITargetPlatformManagerModule.h"
# include "Interfaces/IShaderFormat.h"
# include "ShaderCodeLibrary.h"
# include "ShaderCore.h"
# include "RenderUtils.h"
# include "Misc/ConfigCacheIni.h"
# include "Misc/ScopeLock.h"
# include "UObject/RenderingObjectVersion.h"
# include "UObject/FortniteMainBranchObjectVersion.h"
# include "Misc/ScopeRWLock.h"
# include "ProfilingDebugging/LoadTimeTracker.h"
# if WITH_EDITORONLY_DATA
# include "Interfaces/IShaderFormat.h"
# endif
FShaderMapBase : : FShaderMapBase ( const FTypeLayoutDesc & InContentTypeLayout )
: ContentTypeLayout ( InContentTypeLayout )
, PointerTable ( nullptr )
, Content ( nullptr )
, FrozenContentSize ( 0u )
, NumFrozenShaders ( 0u )
{ }
FShaderMapBase : : ~ FShaderMapBase ( )
{
DestroyContent ( ) ;
if ( PointerTable )
{
delete PointerTable ;
}
}
FShaderMapResourceCode * FShaderMapBase : : GetResourceCode ( )
{
if ( ! Code )
{
Code = new FShaderMapResourceCode ( ) ;
}
return Code ;
}
void FShaderMapBase : : AssignContent ( FShaderMapContent * InContent )
{
check ( ! Content ) ;
check ( ! PointerTable ) ;
Content = InContent ;
PointerTable = CreatePointerTable ( ) ;
}
void FShaderMapBase : : FinalizeContent ( )
{
if ( Content & & FrozenContentSize = = 0u )
{
Content - > Validate ( * this ) ;
FMemoryImage MemoryImage ;
MemoryImage . TargetLayoutParameters . InitializeForCurrent ( ) ;
MemoryImage . PointerTable = PointerTable ;
FMemoryImageWriter Writer ( MemoryImage ) ;
Writer . WriteObject ( Content , ContentTypeLayout ) ;
FMemoryImageResult MemoryImageResult ;
MemoryImage . Flatten ( MemoryImageResult , true ) ;
DestroyContent ( ) ;
{
FrozenContentSize = MemoryImageResult . Bytes . Num ( ) ;
check ( FrozenContentSize > 0u ) ;
void * ContentMemory = FMemory : : Malloc ( FrozenContentSize ) ;
FMemory : : Memcpy ( ContentMemory , MemoryImageResult . Bytes . GetData ( ) , FrozenContentSize ) ;
Content = static_cast < FShaderMapContent * > ( ContentMemory ) ;
MemoryImageResult . ApplyPatches ( Content ) ;
NumFrozenShaders = Content - > GetNumShaders ( ) ;
}
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , FrozenContentSize ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
}
Code - > Finalize ( ) ;
Resource = new FShaderMapResource_InlineCode ( GetShaderPlatform ( ) , Code ) ;
BeginInitResource ( Resource ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Resource - > GetSizeBytes ( ) ) ;
}
void FShaderMapBase : : UnfreezeContent ( )
{
if ( Content & & FrozenContentSize > 0u )
{
void * UnfrozenMemory = FMemory : : Malloc ( ContentTypeLayout . Size , ContentTypeLayout . Alignment ) ;
FMemoryUnfreezeContent Context ;
Context . PrevPointerTable = PointerTable ;
Context . UnfreezeObject ( Content , ContentTypeLayout , UnfrozenMemory ) ;
DestroyContent ( ) ;
Content = static_cast < FShaderMapContent * > ( UnfrozenMemory ) ;
}
}
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-03-12 20:19:35 -04:00
bool FShaderMapBase : : Serialize ( FArchive & Ar , bool bInlineShaderResources , bool bLoadedByCookedMaterial )
2020-02-06 13:13:41 -05:00
{
LLM_SCOPE ( ELLMTag : : Shaders ) ;
2020-03-12 20:19:35 -04:00
bool bContentValid = true ;
2020-02-06 13:13:41 -05:00
if ( Ar . IsSaving ( ) )
{
check ( Content ) ;
Content - > Validate ( * this ) ;
FShaderMapPointerTable * SavePointerTable = CreatePointerTable ( ) ;
FMemoryImage MemoryImage ;
MemoryImage . PrevPointerTable = PointerTable ;
MemoryImage . PointerTable = SavePointerTable ;
MemoryImage . TargetLayoutParameters . InitializeForArchive ( Ar ) ;
FMemoryImageWriter Writer ( MemoryImage ) ;
Writer . WriteObject ( Content , ContentTypeLayout ) ;
FMemoryImageResult MemoryImageResult ;
MemoryImage . Flatten ( MemoryImageResult , true ) ;
void * SaveFrozenContent = MemoryImageResult . Bytes . GetData ( ) ;
uint32 SaveFrozenContentSize = MemoryImageResult . Bytes . Num ( ) ;
2020-03-03 19:38:43 -05:00
check ( SaveFrozenContentSize > 0u ) ;
2020-02-06 13:13:41 -05:00
Ar < < SaveFrozenContentSize ;
Ar . Serialize ( SaveFrozenContent , SaveFrozenContentSize ) ;
MemoryImageResult . SaveToArchive ( Ar ) ;
SavePointerTable - > SaveToArchive ( Ar , SaveFrozenContent , bInlineShaderResources ) ;
delete SavePointerTable ;
int32 NumDependencies = MemoryImage . TypeDependencies . Num ( ) ;
Ar < < NumDependencies ;
for ( const FTypeLayoutDesc * DependencyTypeDesc : MemoryImage . TypeDependencies )
{
uint64 NameHash = DependencyTypeDesc - > NameHash ;
FSHAHash LayoutHash ;
uint32 LayoutSize = Freeze : : HashLayout ( * DependencyTypeDesc , MemoryImage . TargetLayoutParameters , LayoutHash ) ;
Ar < < NameHash ;
Ar < < LayoutSize ;
Ar < < LayoutHash ;
}
bool bShareCode = false ;
# if WITH_EDITOR
bShareCode = FShaderCodeLibrary : : IsEnabled ( ) & & Ar . IsCooking ( ) ;
# endif // WITH_EDITOR
Ar < < bShareCode ;
# if WITH_EDITOR
2020-03-02 21:52:09 -05:00
if ( Ar . IsCooking ( ) )
{
Code - > NotifyShadersCooked ( Ar . CookingTarget ( ) ) ;
}
2020-02-06 13:13:41 -05:00
if ( bShareCode )
{
FSHAHash ResourceHash = Code - > ResourceHash ;
Ar < < ResourceHash ;
FShaderCodeLibrary : : AddShaderCode ( GetShaderPlatform ( ) , Code ) ;
}
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 ( ) ;
Ar < < FrozenContentSize ;
2020-03-03 19:38:43 -05:00
// ensure frozen content is at least as big as our FShaderMapContent-derived class
checkf ( FrozenContentSize > = ContentTypeLayout . Size , TEXT ( " Invalid FrozenContentSize for %s, got %d, expected at least %d " ) , ContentTypeLayout . Name , FrozenContentSize , ContentTypeLayout . Size ) ;
2020-02-06 13:13:41 -05:00
void * ContentMemory = FMemory : : Malloc ( FrozenContentSize ) ;
Ar . Serialize ( ContentMemory , FrozenContentSize ) ;
Content = static_cast < FShaderMapContent * > ( ContentMemory ) ;
FMemoryImageResult : : ApplyPatchesFromArchive ( Content , Ar ) ;
PointerTable - > LoadFromArchive ( Ar , Content , bInlineShaderResources , bLoadedByCookedMaterial ) ;
int32 NumDependencies = 0 ;
Ar < < NumDependencies ;
if ( NumDependencies > 0 )
{
# if CHECK_SHADERMAP_DEPENDENCIES
FPlatformTypeLayoutParameters LayoutParams ;
LayoutParams . InitializeForCurrent ( ) ;
# endif // CHECK_SHADERMAP_DEPENDENCIES
// Waste a bit of time even in shipping builds skipping over this stuff
// Could add a cook-time option to exclude dependencies completely
for ( int32 i = 0u ; i < NumDependencies ; + + i )
{
uint64 NameHash = 0u ;
uint32 SavedLayoutSize = 0u ;
FSHAHash SavedLayoutHash ;
Ar < < NameHash ;
Ar < < SavedLayoutSize ;
Ar < < SavedLayoutHash ;
# if CHECK_SHADERMAP_DEPENDENCIES
const FTypeLayoutDesc * DependencyType = FTypeLayoutDesc : : Find ( NameHash ) ;
if ( DependencyType )
{
FSHAHash CheckLayoutHash ;
const uint32 CheckLayoutSize = Freeze : : HashLayout ( * DependencyType , LayoutParams , CheckLayoutHash ) ;
2020-03-12 20:19:35 -04:00
if ( CheckLayoutSize ! = SavedLayoutSize )
{
UE_LOG ( LogShaders , Error , TEXT ( " Mismatch size for type %s, compiled size is %d, loaded size is %d " ) , DependencyType - > Name , CheckLayoutSize , SavedLayoutSize ) ;
bContentValid = false ;
}
else if ( CheckLayoutHash ! = SavedLayoutHash )
{
UE_LOG ( LogShaders , Error , TEXT ( " Mismatch hash for type %s " ) , DependencyType - > Name ) ;
bContentValid = false ;
}
2020-02-06 13:13:41 -05:00
}
# endif // CHECK_SHADERMAP_DEPENDENCIES
}
}
2020-02-11 16:05:35 -05:00
2020-02-06 13:13:41 -05:00
bool bShareCode = false ;
Ar < < bShareCode ;
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)
if ( FApp : : CanEverRender ( ) & & GetShaderPlatform ( ) = = GMaxRHIShaderPlatform )
2020-04-01 20:32:33 -04:00
{
2020-04-02 16:00:42 -04:00
UE_LOG ( LogShaders , Error , TEXT ( " Missing shader resource for hash '%s' for shader platform %d in the shader library " ) , * ResourceHash . ToString ( ) , GetShaderPlatform ( ) ) ;
2020-04-01 20:32:33 -04:00
}
2020-03-12 20:19:35 -04:00
bContentValid = false ;
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-02-06 13:13:41 -05:00
Resource = new FShaderMapResource_InlineCode ( GetShaderPlatform ( ) , Code ) ;
}
2020-03-12 20:19:35 -04:00
if ( bContentValid )
2020-02-25 13:39:14 -05:00
{
2020-03-12 20:19:35 -04:00
check ( Resource ) ;
NumFrozenShaders = Content - > GetNumShaders ( ) ;
2020-02-25 13:39:14 -05:00
BeginInitResource ( Resource ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Resource - > GetSizeBytes ( ) ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , FrozenContentSize ) ;
INC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
}
2020-03-12 20:19:35 -04:00
else
{
Resource . SafeRelease ( ) ;
// Don't call destructors here, this is basically unknown/invalid memory at this point
FMemory : : Free ( Content ) ;
Content = nullptr ;
}
2020-02-06 13:13:41 -05:00
}
2020-03-12 20:19:35 -04:00
return bContentValid ;
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 ( ) ;
ContentTypeLayout . ToStringFunc ( Content , ContentTypeLayout , LayoutParams , Context ) ;
}
if ( Code )
{
Code - > ToString ( String ) ;
}
return String . ToString ( ) ;
}
2020-02-06 13:13:41 -05:00
void FShaderMapBase : : DestroyContent ( )
{
if ( Content )
{
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderMemory , FrozenContentSize ) ;
DEC_DWORD_STAT_BY ( STAT_Shaders_NumShadersLoaded , NumFrozenShaders ) ;
InternalDeleteObjectFromLayout ( Content , ContentTypeLayout , FrozenContentSize > 0u ) ;
2020-03-02 21:52:11 -05:00
if ( FrozenContentSize > 0u )
{
FMemory : : Free ( Content ) ;
}
2020-02-06 13:13:41 -05:00
FrozenContentSize = 0u ;
NumFrozenShaders = 0u ;
Content = nullptr ;
}
}
2020-04-06 21:12:18 -04:00
static uint16 MakeShaderHash ( const FHashedName & TypeName , int32 PermutationId )
{
return ( uint16 ) CityHash128to64 ( { TypeName . GetHash ( ) , ( uint64 ) PermutationId } ) ;
}
2020-02-06 13:13:41 -05:00
FShader * FShaderMapContent : : GetShader ( const FHashedName & TypeName , int32 PermutationId ) const
{
TRACE_CPUPROFILER_EVENT_SCOPE ( FShaderMapContent : : GetShader ) ;
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 ) ;
}
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
{
2020-04-06 21:12:18 -04:00
FShader * Shader = Shaders [ ShaderIndex ] . GetChecked ( ) ;
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
{
for ( FShaderPipeline * Pipeline : ShaderPipelines )
{
const FShaderPipelineType * PipelineType = FShaderPipelineType : : GetShaderPipelineTypeByName ( Pipeline - > TypeName ) ;
if ( PipelineType - > ShouldOptimizeUnusedOutputs ( Platform ) & & Filter = = FShaderPipeline : : EOnlyShared )
{
continue ;
}
else if ( ! PipelineType - > ShouldOptimizeUnusedOutputs ( Platform ) & & Filter = = FShaderPipeline : : EOnlyUnique )
{
continue ;
}
OutShaderPipelines . Add ( FShaderPipelineRef ( Pipeline , InShaderMap ) ) ;
}
}
void FShaderMapContent : : Validate ( const FShaderMapBase & InShaderMap )
{
for ( FShader * Shader : Shaders )
{
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 )
{
MaxTextureSamplers = FMath : : Max ( MaxTextureSamplers , Shader - > GetNumTextureSamplers ( ) ) ;
}
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 )
{
MaxNumInstructions = FMath : : Max ( MaxNumInstructions , PipelineShader - > GetNumInstructions ( ) ) ;
}
}
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 )
{
const FHashedName & TypeName = ShaderTypes [ ShaderIndex ] ;
const int32 PermutationId = ShaderPermutations [ ShaderIndex ] ;
Hasher . Update ( ( uint8 * ) & TypeName , sizeof ( TypeName ) ) ;
Hasher . Update ( ( uint8 * ) & PermutationId , sizeof ( PermutationId ) ) ;
}
for ( const FShaderPipeline * Pipeline : GetShaderPipelines ( ) )
{
const FHashedName & TypeName = Pipeline - > TypeName ;
Hasher . Update ( ( uint8 * ) & TypeName , sizeof ( TypeName ) ) ;
}
}
2020-02-06 13:13:41 -05:00
void FShaderMapContent : : Empty ( )
{
EmptyShaderPipelines ( ) ;
for ( int32 i = 0 ; i < Shaders . Num ( ) ; + + i )
{
Shaders [ i ] . SafeDelete ( ) ;
}
Shaders . Empty ( ) ;
2020-04-06 21:12:18 -04:00
ShaderTypes . Empty ( ) ;
ShaderPermutations . Empty ( ) ;
ShaderHash . Clear ( ) ;
2020-02-06 13:13:41 -05:00
}
void FShaderMapContent : : EmptyShaderPipelines ( )
{
for ( TMemoryImagePtr < FShaderPipeline > & Pipeline : ShaderPipelines )
{
Pipeline . SafeDelete ( ) ;
}
ShaderPipelines . Empty ( ) ;
}