2020-02-07 11:01:05 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2020-02-06 13:13:41 -05:00
/*=============================================================================
ShaderResource . cpp : ShaderResource implementation .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "Shader.h"
2024-09-10 13:06:22 -04:00
# include "Compression/OodleDataCompression.h"
# include "DataDrivenShaderPlatformInfo.h"
2023-01-27 14:54:10 -05:00
# include "Misc/Compression.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 "Interfaces/ITargetPlatform.h"
# include "Interfaces/ITargetPlatformManagerModule.h"
# include "Interfaces/IShaderFormat.h"
2024-09-10 13:06:22 -04:00
# include "Misc/MemStack.h"
2020-02-06 13:13:41 -05:00
# include "Misc/ScopeLock.h"
2023-01-27 14:54:10 -05:00
# include "RenderingThread.h"
2024-09-10 13:06:22 -04:00
# include "RHI.h"
2022-11-07 10:15:34 -05:00
# include "RHIResources.h" // Access to FRHIRayTracingShader::RayTracingPayloadType requires this
2024-09-10 13:06:22 -04:00
# include "ShaderCompilerCore.h"
# include "ShaderCore.h"
# include "UObject/RenderingObjectVersion.h"
2020-02-06 13:13:41 -05:00
# if WITH_EDITORONLY_DATA
# include "Interfaces/IShaderFormat.h"
# endif
2022-06-14 17:03:34 -04:00
DECLARE_LOG_CATEGORY_CLASS ( LogShaderWarnings , Log , Log ) ;
2024-06-14 18:16:47 -04:00
# if (CSV_PROFILER_STATS && !UE_BUILD_SHIPPING)
2024-05-16 10:48:02 -04:00
TCsvPersistentCustomStat < int > * CsvStatNumShaderMapsUsedForRendering = nullptr ;
# endif
2021-03-11 21:19:35 -04:00
2022-06-14 17:03:34 -04:00
static int32 GShaderCompilerEmitWarningsOnLoad = 0 ;
static FAutoConsoleVariableRef CVarShaderCompilerEmitWarningsOnLoad (
TEXT ( " r.ShaderCompiler.EmitWarningsOnLoad " ) ,
GShaderCompilerEmitWarningsOnLoad ,
TEXT ( " When 1, shader compiler warnings are emitted to the log for all shaders as they are loaded. " ) ,
ECVF_Default
) ;
2023-02-09 00:35:55 -05:00
FName GetShaderCompressionFormat ( )
2021-03-11 21:19:35 -04:00
{
2023-02-09 00:35:55 -05:00
// We always use oodle now. This was instituted because UnrealPak recompresses the shaders and doens't have
// access to the INIs that drive the CVars and would always use default, resulting in mismatches for non
// default encoder selection.
return NAME_Oodle ;
2022-01-04 00:58:30 -05:00
}
void GetShaderCompressionOodleSettings ( FOodleDataCompression : : ECompressor & OutCompressor , FOodleDataCompression : : ECompressionLevel & OutLevel , const FName & ShaderFormat )
{
// support an older developer-only CVar for compatibility and make it preempt
# if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
2023-02-09 00:35:55 -05:00
// Since we always use Oodle, we make SkipCompression tell Oodle to not compress.
2022-01-04 00:58:30 -05:00
static const IConsoleVariable * CVarSkipCompression = IConsoleManager : : Get ( ) . FindConsoleVariable ( TEXT ( " r.Shaders.SkipCompression " ) ) ;
static bool bSkipCompression = ( CVarSkipCompression & & CVarSkipCompression - > GetInt ( ) ! = 0 ) ;
if ( UNLIKELY ( bSkipCompression ) )
{
OutCompressor = FOodleDataCompression : : ECompressor : : Selkie ;
OutLevel = FOodleDataCompression : : ECompressionLevel : : None ;
return ;
}
# endif
2023-02-09 00:35:55 -05:00
// We just use mermaid/normal here since these settings get overwritten in unrealpak, so this is just for non pak'd builds.
OutCompressor = FOodleDataCompression : : ECompressor : : Mermaid ;
OutLevel = FOodleDataCompression : : ECompressionLevel : : Normal ;
2021-03-11 21:19:35 -04:00
}
2020-02-06 13:13:41 -05:00
bool FShaderMapResource : : ArePlatformsCompatible ( EShaderPlatform CurrentPlatform , EShaderPlatform TargetPlatform )
{
bool bFeatureLevelCompatible = CurrentPlatform = = TargetPlatform ;
if ( ! bFeatureLevelCompatible & & IsPCPlatform ( CurrentPlatform ) & & IsPCPlatform ( TargetPlatform ) )
{
bFeatureLevelCompatible = GetMaxSupportedFeatureLevel ( CurrentPlatform ) > = GetMaxSupportedFeatureLevel ( TargetPlatform ) ;
2021-03-11 19:26:01 -04:00
bool const bIsTargetD3D = IsD3DPlatform ( TargetPlatform ) ;
2020-02-06 13:13:41 -05:00
2021-03-11 19:26:01 -04:00
bool const bIsCurrentPlatformD3D = IsD3DPlatform ( CurrentPlatform ) ;
2020-02-06 13:13:41 -05:00
// For Metal in Editor we can switch feature-levels, but not in cooked projects when using Metal shader librariss.
bool const bIsCurrentMetal = IsMetalPlatform ( CurrentPlatform ) ;
bool const bIsTargetMetal = IsMetalPlatform ( TargetPlatform ) ;
bool const bIsMetalCompatible = ( bIsCurrentMetal = = bIsTargetMetal )
# if !WITH_EDITOR // Static analysis doesn't like (|| WITH_EDITOR)
& & ( ! IsMetalPlatform ( CurrentPlatform ) | | ( CurrentPlatform = = TargetPlatform ) )
# endif
;
bool const bIsCurrentOpenGL = IsOpenGLPlatform ( CurrentPlatform ) ;
bool const bIsTargetOpenGL = IsOpenGLPlatform ( TargetPlatform ) ;
bFeatureLevelCompatible = bFeatureLevelCompatible & & ( bIsCurrentPlatformD3D = = bIsTargetD3D & & bIsMetalCompatible & & bIsCurrentOpenGL = = bIsTargetOpenGL ) ;
}
return bFeatureLevelCompatible ;
}
# if RHI_RAYTRACING
2022-05-19 07:03:30 -04:00
class FRayTracingShaderLibrary
2020-02-06 13:13:41 -05:00
{
2022-05-19 07:03:30 -04:00
public :
uint32 AddShader ( FRHIRayTracingShader * Shader )
2020-02-06 13:13:41 -05:00
{
2022-10-24 20:11:02 -04:00
const int32 PayloadIndex = FMath : : CountTrailingZeros ( Shader - > RayTracingPayloadType ) ;
2022-05-19 07:03:30 -04:00
FScopeLock Lock ( & CS ) ;
2022-10-24 20:11:02 -04:00
if ( UnusedIndicies [ PayloadIndex ] . Num ( ) ! = 0 )
2022-05-19 07:03:30 -04:00
{
2024-01-19 16:41:35 -05:00
uint32 Index = UnusedIndicies [ PayloadIndex ] . Pop ( EAllowShrinking : : No ) ;
2022-10-24 20:11:02 -04:00
checkSlow ( Shaders [ PayloadIndex ] [ Index ] = = nullptr ) ;
Shaders [ PayloadIndex ] [ Index ] = Shader ;
2022-05-19 07:03:30 -04:00
return Index ;
}
else
{
2022-10-24 20:11:02 -04:00
return Shaders [ PayloadIndex ] . Add ( Shader ) ;
2022-05-19 07:03:30 -04:00
}
2020-02-06 13:13:41 -05:00
}
2022-05-19 07:03:30 -04:00
2022-10-24 20:11:02 -04:00
void RemoveShader ( uint32 Index , FRHIRayTracingShader * Shader )
2022-05-19 07:03:30 -04:00
{
if ( Index ! = ~ 0u )
{
2022-10-24 20:11:02 -04:00
const int32 PayloadIndex = FMath : : CountTrailingZeros ( Shader - > RayTracingPayloadType ) ;
2022-05-19 07:03:30 -04:00
FScopeLock Lock ( & CS ) ;
2022-10-24 20:11:02 -04:00
checkSlow ( Shaders [ PayloadIndex ] [ Index ] = = Shader ) ;
UnusedIndicies [ PayloadIndex ] . Push ( Index ) ;
Shaders [ PayloadIndex ] [ Index ] = nullptr ;
2022-05-19 07:03:30 -04:00
}
}
void GetShaders ( TArray < FRHIRayTracingShader * > & OutShaders , FRHIRayTracingShader * DefaultShader )
{
2022-10-24 20:11:02 -04:00
const int32 PayloadIndex = FMath : : CountTrailingZeros ( DefaultShader - > RayTracingPayloadType ) ;
2023-01-03 15:55:23 -05:00
const int32 BaseOutIndex = OutShaders . Num ( ) ;
2022-05-19 07:03:30 -04:00
FScopeLock Lock ( & CS ) ;
2023-01-03 15:55:23 -05:00
OutShaders . Append ( Shaders [ PayloadIndex ] ) ;
2022-05-19 07:03:30 -04:00
2022-10-24 20:11:02 -04:00
for ( uint32 Index : UnusedIndicies [ PayloadIndex ] )
2022-05-19 07:03:30 -04:00
{
2023-01-03 15:55:23 -05:00
OutShaders [ BaseOutIndex + Index ] = DefaultShader ;
2022-05-19 07:03:30 -04:00
}
}
private :
2022-10-24 20:11:02 -04:00
TArray < uint32 > UnusedIndicies [ 32 ] ;
TArray < FRHIRayTracingShader * > Shaders [ 32 ] ;
2022-05-19 07:03:30 -04:00
FCriticalSection CS ;
} ;
static FRayTracingShaderLibrary GlobalRayTracingHitGroupLibrary ;
static FRayTracingShaderLibrary GlobalRayTracingCallableShaderLibrary ;
static FRayTracingShaderLibrary GlobalRayTracingMissShaderLibrary ;
void FShaderMapResource : : GetRayTracingHitGroupLibrary ( TArray < FRHIRayTracingShader * > & RayTracingShaders , FRHIRayTracingShader * DefaultShader )
{
GlobalRayTracingHitGroupLibrary . GetShaders ( RayTracingShaders , DefaultShader ) ;
2020-02-06 13:13:41 -05:00
}
2022-05-19 07:03:30 -04:00
void FShaderMapResource : : GetRayTracingCallableShaderLibrary ( TArray < FRHIRayTracingShader * > & RayTracingCallableShaders , FRHIRayTracingShader * DefaultShader )
2020-02-06 13:13:41 -05:00
{
2022-05-19 07:03:30 -04:00
GlobalRayTracingCallableShaderLibrary . GetShaders ( RayTracingCallableShaders , DefaultShader ) ;
2020-02-06 13:13:41 -05:00
}
2022-05-19 07:03:30 -04:00
void FShaderMapResource : : GetRayTracingMissShaderLibrary ( TArray < FRHIRayTracingShader * > & RayTracingMissShaders , FRHIRayTracingShader * DefaultShader )
2020-02-06 13:13:41 -05:00
{
2022-05-19 07:03:30 -04:00
GlobalRayTracingMissShaderLibrary . GetShaders ( RayTracingMissShaders , DefaultShader ) ;
2020-02-06 13:13:41 -05:00
}
# endif // RHI_RAYTRACING
static void ApplyResourceStats ( FShaderMapResourceCode & Resource )
{
# if STATS
INC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Resource . GetSizeBytes ( ) ) ;
2024-09-10 13:06:22 -04:00
for ( const FShaderCodeResource & Shader : Resource . ShaderCodeResources )
2020-02-06 13:13:41 -05:00
{
2024-10-01 19:02:22 -04:00
INC_DWORD_STAT_BY_FName ( GetMemoryStatType ( Shader . GetFrequency ( ) ) . GetName ( ) , Shader . GetCodeBuffer ( ) . GetSize ( ) ) ;
2020-02-06 13:13:41 -05:00
}
# endif // STATS
}
static void RemoveResourceStats ( FShaderMapResourceCode & Resource )
{
# if STATS
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , Resource . GetSizeBytes ( ) ) ;
2024-09-10 13:06:22 -04:00
for ( const FShaderCodeResource & Shader : Resource . ShaderCodeResources )
2020-02-06 13:13:41 -05:00
{
2024-10-01 19:02:22 -04:00
DEC_DWORD_STAT_BY_FName ( GetMemoryStatType ( Shader . GetFrequency ( ) ) . GetName ( ) , Shader . GetCodeBuffer ( ) . GetSize ( ) ) ;
2020-02-06 13:13:41 -05:00
}
# endif // STATS
}
Fix memory leak of shader code during shader compilation (during cooks, deployments, or editor). Depending on settings and project this can save a considerable amount. For example, this saved ~39GB on the test project I was cooking.
- FShaderMapResourceCode derives from FThreadSafeRefCountedObject which has a member that keeps track of the number of references to the object. We were doing deep copies using the Copy Constructor of FShaderMapResourceCode which resulted in a member wise copy of the num refs. This is not the behavior you'd expect.
- The offending line of code that caused the memory leak was in FShaderMapBase::AssignCopy:
- Code = new FShaderMapResourceCode(*Source.Code);
- Like FRefCountBase I've deleted the copy constructor and assignment operator for FRefCountedObject and FThreadSafeRefCountedObject to catch issues at compile time where we are copying across NumRefs incorrectly.
- To fix the issue I've manually created copy constructors for FGPUProfilerEventNodeStats and FShaderMapResourceCode.
#rb Devin.Doucette, Dave.Jones, Arciel.Rekman, Ben.Ingram
#review-16115628 @Devin.Doucette, @Dave.Jones, @Arciel.Rekman, @Ben.Ingram
#jira UE-108598, UE-113736
[CL 16116577 by Jason Nadro in ue5-main branch]
2021-04-26 14:03:07 -04:00
FShaderMapResourceCode : : FShaderMapResourceCode ( const FShaderMapResourceCode & Other )
{
ResourceHash = Other . ResourceHash ;
ShaderHashes = Other . ShaderHashes ;
2024-09-10 13:06:22 -04:00
ShaderCodeResources = Other . ShaderCodeResources ;
Fix memory leak of shader code during shader compilation (during cooks, deployments, or editor). Depending on settings and project this can save a considerable amount. For example, this saved ~39GB on the test project I was cooking.
- FShaderMapResourceCode derives from FThreadSafeRefCountedObject which has a member that keeps track of the number of references to the object. We were doing deep copies using the Copy Constructor of FShaderMapResourceCode which resulted in a member wise copy of the num refs. This is not the behavior you'd expect.
- The offending line of code that caused the memory leak was in FShaderMapBase::AssignCopy:
- Code = new FShaderMapResourceCode(*Source.Code);
- Like FRefCountBase I've deleted the copy constructor and assignment operator for FRefCountedObject and FThreadSafeRefCountedObject to catch issues at compile time where we are copying across NumRefs incorrectly.
- To fix the issue I've manually created copy constructors for FGPUProfilerEventNodeStats and FShaderMapResourceCode.
#rb Devin.Doucette, Dave.Jones, Arciel.Rekman, Ben.Ingram
#review-16115628 @Devin.Doucette, @Dave.Jones, @Arciel.Rekman, @Ben.Ingram
#jira UE-108598, UE-113736
[CL 16116577 by Jason Nadro in ue5-main branch]
2021-04-26 14:03:07 -04:00
# if WITH_EDITORONLY_DATA
2022-10-03 09:42:06 -04:00
ShaderEditorOnlyDataEntries = Other . ShaderEditorOnlyDataEntries ;
Fix memory leak of shader code during shader compilation (during cooks, deployments, or editor). Depending on settings and project this can save a considerable amount. For example, this saved ~39GB on the test project I was cooking.
- FShaderMapResourceCode derives from FThreadSafeRefCountedObject which has a member that keeps track of the number of references to the object. We were doing deep copies using the Copy Constructor of FShaderMapResourceCode which resulted in a member wise copy of the num refs. This is not the behavior you'd expect.
- The offending line of code that caused the memory leak was in FShaderMapBase::AssignCopy:
- Code = new FShaderMapResourceCode(*Source.Code);
- Like FRefCountBase I've deleted the copy constructor and assignment operator for FRefCountedObject and FThreadSafeRefCountedObject to catch issues at compile time where we are copying across NumRefs incorrectly.
- To fix the issue I've manually created copy constructors for FGPUProfilerEventNodeStats and FShaderMapResourceCode.
#rb Devin.Doucette, Dave.Jones, Arciel.Rekman, Ben.Ingram
#review-16115628 @Devin.Doucette, @Dave.Jones, @Arciel.Rekman, @Ben.Ingram
#jira UE-108598, UE-113736
[CL 16116577 by Jason Nadro in ue5-main branch]
2021-04-26 14:03:07 -04:00
# endif // WITH_EDITORONLY_DATA
}
2024-09-10 13:06:22 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS
2020-02-06 13:13:41 -05:00
FShaderMapResourceCode : : ~ FShaderMapResourceCode ( )
{
RemoveResourceStats ( * this ) ;
}
2024-09-10 13:06:22 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2020-02-06 13:13:41 -05:00
void FShaderMapResourceCode : : Finalize ( )
{
FSHA1 Hasher ;
Hasher . Update ( ( uint8 * ) ShaderHashes . GetData ( ) , ShaderHashes . Num ( ) * sizeof ( FSHAHash ) ) ;
Hasher . Final ( ) ;
Hasher . GetHash ( ResourceHash . Hash ) ;
ApplyResourceStats ( * this ) ;
2022-06-14 17:03:34 -04:00
# if WITH_EDITORONLY_DATA
LogShaderCompilerWarnings ( ) ;
# endif
2020-02-06 13:13:41 -05:00
}
2020-04-21 13:46:17 -04:00
uint32 FShaderMapResourceCode : : GetSizeBytes ( ) const
{
2024-09-10 13:06:22 -04:00
uint64 Size = sizeof ( * this ) + ShaderHashes . GetAllocatedSize ( ) + ShaderCodeResources . GetAllocatedSize ( ) ;
for ( const FShaderCodeResource & Entry : ShaderCodeResources )
2020-04-21 13:46:17 -04:00
{
2024-10-01 19:02:22 -04:00
Size + = Entry . GetCacheBuffer ( ) . GetSize ( ) ;
2020-04-21 13:46:17 -04:00
}
2022-01-07 10:39:08 -05:00
check ( Size < = TNumericLimits < uint32 > : : Max ( ) ) ;
return static_cast < uint32 > ( Size ) ;
2020-04-21 13:46:17 -04:00
}
int32 FShaderMapResourceCode : : FindShaderIndex ( const FSHAHash & InHash ) const
{
return Algo : : BinarySearch ( ShaderHashes , InHash ) ;
}
2024-07-18 13:35:59 -04:00
void FShaderMapResourceCode : : AddShaderCompilerOutput ( const FShaderCompilerOutput & Output , const FString & DebugName , FString DebugInfo )
2020-04-21 13:46:17 -04:00
{
2021-01-25 12:06:02 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FShaderMapResourceCode : : AddShaderCode ) ;
2022-10-03 09:42:06 -04:00
const FSHAHash & InHash = Output . OutputHash ;
2020-04-21 13:46:17 -04:00
const int32 Index = Algo : : LowerBound ( ShaderHashes , InHash ) ;
if ( Index > = ShaderHashes . Num ( ) | | ShaderHashes [ Index ] ! = InHash )
{
ShaderHashes . Insert ( InHash , Index ) ;
2022-10-03 09:42:06 -04:00
# if WITH_EDITORONLY_DATA
// Output.Errors contains warnings in the case any exist (no errors since if there were the job would have failed)
2024-07-18 13:35:59 -04:00
AddEditorOnlyData ( Index , DebugName , Output . PlatformDebugData , Output . Errors , Output . ShaderStatistics , DebugInfo ) ;
2022-10-03 09:42:06 -04:00
# endif
2024-10-01 19:02:22 -04:00
ShaderCodeResources . Insert ( Output . GetFinalizedCodeResource ( ) , Index ) ;
2020-04-21 13:46:17 -04:00
}
2022-10-03 09:42:06 -04:00
# if WITH_EDITORONLY_DATA
else
{
// Output.Errors contains warnings in the case any exist (no errors since if there were the job would have failed)
2024-07-18 13:35:59 -04:00
// We append the warnings and deduplicate other data like DebugInfo for any additional jobs which resulted in the
// same bytecode for the sake of determinism in the results saved to DDC.
UpdateEditorOnlyData ( Index , DebugName , Output . Errors , DebugInfo ) ;
2024-06-12 14:41:45 -04:00
ValidateShaderStatisticsEditorOnlyData ( Index , Output . ShaderStatistics ) ;
2022-10-03 09:42:06 -04:00
}
# endif
2020-04-21 13:46:17 -04:00
}
# if WITH_EDITORONLY_DATA
2024-07-18 13:35:59 -04:00
void FShaderMapResourceCode : : AddEditorOnlyData ( int32 Index , const FString & DebugName , TConstArrayView < uint8 > InPlatformDebugData , TConstArrayView < FShaderCompilerError > InCompilerWarnings , const TArray < FGenericShaderStat > & ShaderStatistics , const FString & DebugInfo )
2020-04-21 13:46:17 -04:00
{
2022-10-03 09:42:06 -04:00
FShaderEditorOnlyDataEntry & Entry = ShaderEditorOnlyDataEntries . InsertDefaulted_GetRef ( Index ) ;
Entry . PlatformDebugData = InPlatformDebugData ;
2020-04-21 13:46:17 -04:00
2024-06-12 14:41:45 -04:00
// This should be a newly created shader entry.
check ( Entry . ShaderStatistics . Num ( ) = = 0 ) ;
Entry . ShaderStatistics = ShaderStatistics ;
2024-07-18 13:35:59 -04:00
UpdateEditorOnlyData ( Index , DebugName , InCompilerWarnings , DebugInfo ) ;
2022-10-03 09:42:06 -04:00
}
2020-04-21 13:46:17 -04:00
2024-07-18 13:35:59 -04:00
void FShaderMapResourceCode : : UpdateEditorOnlyData ( int32 Index , const FString & DebugName , TConstArrayView < FShaderCompilerError > InCompilerWarnings , const FString & DebugInfo )
2022-10-03 09:42:06 -04:00
{
FShaderEditorOnlyDataEntry & Entry = ShaderEditorOnlyDataEntries [ Index ] ;
2024-07-18 13:35:59 -04:00
// Keep a single DebugInfo as it doesn't matter which one we use, but make sure it is the same one for determinism
if ( ! DebugInfo . IsEmpty ( ) & & ( Entry . DebugInfo . IsEmpty ( ) | | ( DebugInfo < Entry . DebugInfo ) ) )
{
Entry . DebugInfo = DebugInfo ;
}
2022-10-03 09:42:06 -04:00
for ( const FShaderCompilerError & Warning : InCompilerWarnings )
2020-04-21 13:46:17 -04:00
{
2022-10-03 09:42:06 -04:00
FString ModifiedWarning = ! DebugName . IsEmpty ( ) ? FString : : Printf ( TEXT ( " %s [%s] " ) , * Warning . GetErrorString ( ) , * DebugName ) : Warning . GetErrorString ( ) ;
// Maintain sorted order in Entry.CompilerWarnings & deduplicate
const int32 WarningIndex = Algo : : LowerBound ( Entry . CompilerWarnings , ModifiedWarning ) ;
if ( WarningIndex > = Entry . CompilerWarnings . Num ( ) | | Entry . CompilerWarnings [ WarningIndex ] ! = ModifiedWarning )
{
Entry . CompilerWarnings . Insert ( ModifiedWarning , WarningIndex ) ;
}
2020-04-21 13:46:17 -04:00
}
}
2022-06-14 17:03:34 -04:00
2024-06-12 14:41:45 -04:00
void FShaderMapResourceCode : : ValidateShaderStatisticsEditorOnlyData ( int32 Index , const TArray < FGenericShaderStat > & ShaderStatistics )
{
check ( ShaderEditorOnlyDataEntries . IsValidIndex ( Index ) ) ;
FShaderEditorOnlyDataEntry & Entry = ShaderEditorOnlyDataEntries [ Index ] ;
if ( Entry . ShaderStatistics . Num ( ) ! = ShaderStatistics . Num ( ) )
{
UE_LOG ( LogShaders , Warning , TEXT ( " Non-determinism detected in shader statistics. Multiple duplicate shaders have the same shader statistics. " ) ) ;
return ;
}
for ( int i = 0 ; i < ShaderStatistics . Num ( ) ; + + i )
{
const FGenericShaderStat & StatA = Entry . ShaderStatistics [ i ] ;
const FGenericShaderStat & StatB = ShaderStatistics [ i ] ;
if ( ! ( StatA = = StatB ) )
{
UE_LOG ( LogShaders , Warning , TEXT ( " Non-determinism detected in shader statistics. Multiple duplicate shaders have the same shader statistics. " ) ) ;
return ;
}
}
}
2022-06-14 17:03:34 -04:00
void FShaderMapResourceCode : : LogShaderCompilerWarnings ( )
{
2022-10-03 09:42:06 -04:00
if ( ShaderEditorOnlyDataEntries . Num ( ) > 0 & & GShaderCompilerEmitWarningsOnLoad ! = 0 )
2022-06-14 17:03:34 -04:00
{
// Emit all the compiler warnings seen whilst serializing/loading this shader to the log.
// Since successfully compiled shaders are stored in the DDC, we'll get the compiler warnings
// even if we didn't compile the shader this run.
2022-10-03 09:42:06 -04:00
for ( const FShaderEditorOnlyDataEntry & Entry : ShaderEditorOnlyDataEntries )
2022-06-14 17:03:34 -04:00
{
2022-10-03 09:42:06 -04:00
for ( const FString & CompilerWarning : Entry . CompilerWarnings )
{
UE_LOG ( LogShaderWarnings , Warning , TEXT ( " %s " ) , * CompilerWarning ) ;
}
2022-06-14 17:03:34 -04:00
}
}
}
2020-04-21 13:46:17 -04:00
# endif // WITH_EDITORONLY_DATA
void FShaderMapResourceCode : : ToString ( FStringBuilderBase & OutString ) const
{
OutString . Appendf ( TEXT ( " Shaders: Num=%d \n " ) , ShaderHashes . Num ( ) ) ;
for ( int32 i = 0 ; i < ShaderHashes . Num ( ) ; + + i )
{
2024-09-10 13:06:22 -04:00
const FShaderCodeResource & Res = ShaderCodeResources [ i ] ;
2024-10-01 19:02:22 -04:00
OutString . Appendf ( TEXT ( " [%d]: { Hash: %s, Freq: %s, Size: %llu, UncompressedSize: %d } \n " ) ,
i , * ShaderHashes [ i ] . ToString ( ) , GetShaderFrequencyString ( Res . GetFrequency ( ) ) , Res . GetCodeBuffer ( ) . GetSize ( ) , Res . GetUncompressedSize ( ) ) ;
2020-04-21 13:46:17 -04:00
}
}
2024-09-10 13:06:22 -04:00
void FShaderMapResourceCode : : Serialize ( FShaderSerializeContext & Ctx )
2020-02-06 13:13:41 -05:00
{
2024-09-10 13:06:22 -04:00
FArchive & Ar = Ctx . GetMainArchive ( ) ;
2020-02-06 13:13:41 -05:00
Ar < < ResourceHash ;
Ar < < ShaderHashes ;
2024-09-10 13:06:22 -04:00
if ( ! Ctx . SerializeCodeFunc )
{
Ar < < ShaderCodeResources ;
}
else
{
if ( Ar . IsLoading ( ) )
{
ShaderCodeResources . SetNum ( ShaderHashes . Num ( ) ) ;
}
if ( Ctx . ReserveCodeFunc )
{
Ctx . ReserveCodeFunc ( ShaderCodeResources . Num ( ) ) ;
}
for ( int32 CodeIndex = 0 ; CodeIndex < ShaderCodeResources . Num ( ) ; + + CodeIndex )
{
Ctx . SerializeCodeFunc ( ShaderCodeResources [ CodeIndex ] , CodeIndex ) ;
}
}
check ( ShaderCodeResources . Num ( ) = = ShaderHashes . Num ( ) ) ;
2020-03-02 21:52:09 -05:00
# if WITH_EDITORONLY_DATA
2024-09-10 13:06:22 -04:00
const bool bSerializeEditorOnlyData = ! Ctx . bLoadingCooked & & ( ! Ar . IsCooking ( ) | | Ar . CookingTarget ( ) - > HasEditorOnlyData ( ) ) ;
2022-06-14 17:03:34 -04:00
if ( bSerializeEditorOnlyData )
2020-03-02 21:52:09 -05:00
{
2022-10-03 09:42:06 -04:00
Ar < < ShaderEditorOnlyDataEntries ;
2020-03-02 21:52:09 -05:00
}
# endif // WITH_EDITORONLY_DATA
2020-02-06 13:13:41 -05:00
ApplyResourceStats ( * this ) ;
2022-06-14 17:03:34 -04:00
# if WITH_EDITORONLY_DATA
if ( Ar . IsLoading ( ) )
{
LogShaderCompilerWarnings ( ) ;
}
# endif
2020-02-06 13:13:41 -05:00
}
2020-03-02 21:52:09 -05:00
# if WITH_EDITORONLY_DATA
2021-08-16 23:18:23 -04:00
void FShaderMapResourceCode : : NotifyShadersCompiled ( FName FormatName )
2020-03-02 21:52:09 -05:00
{
# if WITH_ENGINE
// Notify the platform shader format that this particular shader is being used in the cook.
// We discard this data in cooked builds unless Ar.CookingTarget()->HasEditorOnlyData() is true.
2022-10-03 09:42:06 -04:00
if ( ShaderEditorOnlyDataEntries . Num ( ) )
2020-03-02 21:52:09 -05:00
{
2021-08-16 23:18:23 -04:00
if ( const IShaderFormat * ShaderFormat = GetTargetPlatformManagerRef ( ) . FindShaderFormat ( FormatName ) )
2020-03-02 21:52:09 -05:00
{
2022-10-03 09:42:06 -04:00
for ( const FShaderEditorOnlyDataEntry & Entry : ShaderEditorOnlyDataEntries )
2020-03-02 21:52:09 -05:00
{
2024-07-18 13:35:59 -04:00
ShaderFormat - > NotifyShaderCompiled ( Entry . PlatformDebugData , FormatName , Entry . DebugInfo ) ;
2020-03-02 21:52:09 -05:00
}
}
}
# endif // WITH_ENGINE
}
# endif // WITH_EDITORONLY_DATA
2020-02-06 13:13:41 -05:00
FShaderMapResource : : FShaderMapResource ( EShaderPlatform InPlatform , int32 NumShaders )
2024-05-10 11:19:30 -04:00
: NumRHIShaders ( static_cast < uint32 > ( NumShaders ) )
, bAtLeastOneRHIShaderCreated ( 0 )
2020-06-23 18:40:00 -04:00
, Platform ( InPlatform )
2020-02-06 13:13:41 -05:00
, NumRefs ( 0 )
{
2020-06-23 18:40:00 -04:00
RHIShaders = MakeUnique < std : : atomic < FRHIShader * > [ ] > ( NumRHIShaders ) ; // this MakeUnique() zero-initializes the array
2020-02-06 13:13:41 -05:00
# if RHI_RAYTRACING
2021-11-23 10:25:31 -05:00
if ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders )
2020-06-23 18:40:00 -04:00
{
2022-05-19 07:03:30 -04:00
RayTracingLibraryIndices . AddUninitialized ( NumShaders ) ;
FMemory : : Memset ( RayTracingLibraryIndices . GetData ( ) , 0xff , NumShaders * RayTracingLibraryIndices . GetTypeSize ( ) ) ;
2020-06-23 18:40:00 -04:00
}
2020-02-06 13:13:41 -05:00
# endif // RHI_RAYTRACING
}
FShaderMapResource : : ~ FShaderMapResource ( )
{
2020-06-23 18:40:00 -04:00
ReleaseShaders ( ) ;
2022-03-30 20:57:33 -04:00
check ( NumRefs . load ( std : : memory_order_relaxed ) = = 0 ) ;
2020-02-06 13:13:41 -05:00
}
void FShaderMapResource : : AddRef ( )
{
2022-03-30 20:57:33 -04:00
NumRefs . fetch_add ( 1 , std : : memory_order_relaxed ) ;
2020-02-06 13:13:41 -05:00
}
void FShaderMapResource : : Release ( )
{
2022-03-30 20:57:33 -04:00
check ( NumRefs . load ( std : : memory_order_relaxed ) > 0 ) ;
if ( NumRefs . fetch_sub ( 1 , std : : memory_order_release ) - 1 = = 0 & & TryRelease ( ) )
2020-02-06 13:13:41 -05:00
{
2022-03-30 20:57:33 -04:00
//check https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html for explanation
std : : atomic_thread_fence ( std : : memory_order_acquire ) ;
2020-02-06 13:13:41 -05:00
// Send a release message to the rendering thread when the shader loses its last reference.
BeginReleaseResource ( this ) ;
BeginCleanup ( this ) ;
DEC_DWORD_STAT_BY ( STAT_Shaders_ShaderResourceMemory , GetSizeBytes ( ) ) ;
}
}
2020-06-23 18:40:00 -04:00
void FShaderMapResource : : ReleaseShaders ( )
{
if ( RHIShaders )
{
2024-05-10 11:19:30 -04:00
FScopeLock ScopeLock ( & RHIShadersCreationGuard ) ;
2024-05-16 10:48:02 -04:00
int NumReleaseShaders = 0 ;
2024-05-10 11:19:30 -04:00
for ( uint32 Idx = 0 ; Idx < NumRHIShaders ; + + Idx )
2020-06-23 18:40:00 -04:00
{
if ( FRHIShader * Shader = RHIShaders [ Idx ] . load ( std : : memory_order_acquire ) )
{
Shader - > Release ( ) ;
2024-05-16 10:48:02 -04:00
NumReleaseShaders + + ;
2024-05-10 11:19:30 -04:00
DEC_DWORD_STAT ( STAT_Shaders_NumShadersCreated ) ;
2020-06-23 18:40:00 -04:00
}
}
2024-05-16 10:48:02 -04:00
2024-06-14 18:16:47 -04:00
# if (CSV_PROFILER_STATS && !UE_BUILD_SHIPPING)
2024-05-16 10:48:02 -04:00
TCsvPersistentCustomStat < int > * CsvStatNumShadersCreated = FCsvProfiler : : Get ( ) - > GetOrCreatePersistentCustomStatInt ( TEXT ( " NumShadersCreated " ) , CSV_CATEGORY_INDEX ( Shaders ) ) ;
CsvStatNumShadersCreated - > Sub ( NumReleaseShaders ) ;
# endif
2020-06-23 18:40:00 -04:00
RHIShaders = nullptr ;
NumRHIShaders = 0 ;
2024-05-10 11:19:30 -04:00
if ( bAtLeastOneRHIShaderCreated )
{
DEC_DWORD_STAT ( STAT_Shaders_NumShaderMapsUsedForRendering ) ;
2024-05-16 10:48:02 -04:00
2024-06-14 18:16:47 -04:00
# if (CSV_PROFILER_STATS && !UE_BUILD_SHIPPING)
2024-05-16 10:48:02 -04:00
if ( CsvStatNumShaderMapsUsedForRendering = = nullptr )
{
CsvStatNumShaderMapsUsedForRendering = FCsvProfiler : : Get ( ) - > GetOrCreatePersistentCustomStatInt ( TEXT ( " NumShaderMapsUsedForRendering " ) , CSV_CATEGORY_INDEX ( Shaders ) ) ;
}
CsvStatNumShaderMapsUsedForRendering - > Sub ( 1 ) ;
# endif
2024-05-10 11:19:30 -04:00
}
bAtLeastOneRHIShaderCreated = false ;
2020-06-23 18:40:00 -04:00
}
}
2020-02-06 13:13:41 -05:00
void FShaderMapResource : : ReleaseRHI ( )
{
# if RHI_RAYTRACING
2022-05-19 07:03:30 -04:00
if ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders )
2020-02-06 13:13:41 -05:00
{
2024-05-10 11:19:30 -04:00
check ( NumRHIShaders = = static_cast < uint32 > ( RayTracingLibraryIndices . Num ( ) ) ) ;
2022-05-19 07:03:30 -04:00
2024-05-10 11:19:30 -04:00
for ( uint32 Idx = 0 ; Idx < NumRHIShaders ; + + Idx )
2022-05-19 07:03:30 -04:00
{
if ( FRHIShader * Shader = RHIShaders [ Idx ] . load ( std : : memory_order_acquire ) )
{
int32 IndexInLibrary = RayTracingLibraryIndices [ Idx ] ;
switch ( Shader - > GetFrequency ( ) )
{
case SF_RayHitGroup :
2022-10-24 20:11:02 -04:00
GlobalRayTracingHitGroupLibrary . RemoveShader ( IndexInLibrary , static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
2022-05-19 07:03:30 -04:00
break ;
case SF_RayCallable :
2022-10-24 20:11:02 -04:00
GlobalRayTracingCallableShaderLibrary . RemoveShader ( IndexInLibrary , static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
2022-05-19 07:03:30 -04:00
break ;
case SF_RayMiss :
2022-10-24 20:11:02 -04:00
GlobalRayTracingMissShaderLibrary . RemoveShader ( IndexInLibrary , static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
2022-05-19 07:03:30 -04:00
break ;
default :
break ;
}
}
}
2020-02-06 13:13:41 -05:00
}
2022-05-19 07:03:30 -04:00
RayTracingLibraryIndices . Empty ( ) ;
2020-02-06 13:13:41 -05:00
# endif // RHI_RAYTRACING
2020-06-23 18:40:00 -04:00
ReleaseShaders ( ) ;
2020-02-06 13:13:41 -05:00
}
void FShaderMapResource : : BeginCreateAllShaders ( )
{
FShaderMapResource * Resource = this ;
ENQUEUE_RENDER_COMMAND ( InitCommand ) (
[ Resource ] ( FRHICommandListImmediate & RHICmdList )
{
for ( int32 ShaderIndex = 0 ; ShaderIndex < Resource - > GetNumShaders ( ) ; + + ShaderIndex )
{
2024-04-25 04:16:22 -04:00
Resource - > GetShader ( ShaderIndex , true /*bRequired*/ ) ;
2020-02-06 13:13:41 -05:00
}
} ) ;
}
2024-04-25 04:16:22 -04:00
FRHIShader * FShaderMapResource : : CreateShaderOrCrash ( int32 ShaderIndex , bool bRequired )
2022-11-07 10:15:34 -05:00
{
FRHIShader * Shader = nullptr ;
// create before taking the lock. This may cause multiple creations, but it's better
// than a potential oversubscription deadlock, since CreateShader can spawn async tasks
2024-04-25 04:16:22 -04:00
FRHIShader * CreatedShader = CreateRHIShaderOrCrash ( ShaderIndex , bRequired ) ; // guaranteed to return non-null if required is set
if ( CreatedShader = = nullptr )
{
check ( ! bRequired ) ;
return nullptr ;
}
2020-02-06 13:13:41 -05:00
{
2022-11-07 10:15:34 -05:00
// Most shadermaps have <100 shaders, and less than a half of them can be created.
2024-05-10 11:19:30 -04:00
// However, if this path is often contended, you can slice this lock (but remember to take care of STAT_Shaders_NumShaderMapsUsedForRendering!)
2022-11-07 10:15:34 -05:00
FScopeLock ScopeLock ( & RHIShadersCreationGuard ) ;
Shader = RHIShaders [ ShaderIndex ] . load ( std : : memory_order_relaxed ) ;
if ( UNLIKELY ( Shader = = nullptr ) )
2022-05-19 07:03:30 -04:00
{
2022-11-07 10:15:34 -05:00
Shader = CreatedShader ;
CreatedShader = nullptr ;
RHIShaders [ ShaderIndex ] . store ( Shader , std : : memory_order_release ) ;
2024-05-10 11:19:30 -04:00
if ( ! bAtLeastOneRHIShaderCreated )
{
INC_DWORD_STAT ( STAT_Shaders_NumShaderMapsUsedForRendering ) ;
2024-05-16 10:48:02 -04:00
2024-06-14 18:16:47 -04:00
# if (CSV_PROFILER_STATS && !UE_BUILD_SHIPPING)
2024-05-16 10:48:02 -04:00
if ( CsvStatNumShaderMapsUsedForRendering = = nullptr )
{
CsvStatNumShaderMapsUsedForRendering = FCsvProfiler : : Get ( ) - > GetOrCreatePersistentCustomStatInt ( TEXT ( " NumShaderMapsUsedForRendering " ) , CSV_CATEGORY_INDEX ( Shaders ) ) ;
}
CsvStatNumShaderMapsUsedForRendering - > Add ( 1 ) ;
# endif
2024-05-10 11:19:30 -04:00
bAtLeastOneRHIShaderCreated = 1 ;
}
2022-11-07 10:15:34 -05:00
# if RHI_RAYTRACING
// Registers RT shaders in global "libraries" that track all shaders potentially usable in a scene for adding to RTPSO
EShaderFrequency Frequency = Shader - > GetFrequency ( ) ;
if ( LIKELY ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders ) )
{
switch ( Frequency )
{
case SF_RayHitGroup :
RayTracingLibraryIndices [ ShaderIndex ] = GlobalRayTracingHitGroupLibrary . AddShader ( static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
break ;
case SF_RayCallable :
RayTracingLibraryIndices [ ShaderIndex ] = GlobalRayTracingCallableShaderLibrary . AddShader ( static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
break ;
case SF_RayMiss :
RayTracingLibraryIndices [ ShaderIndex ] = GlobalRayTracingMissShaderLibrary . AddShader ( static_cast < FRHIRayTracingShader * > ( Shader ) ) ;
break ;
case SF_RayGen :
// NOTE: we do not maintain a library for raygen shaders since the list of rayshaders we care about is usually small and consistent
break ;
default :
break ;
}
}
2020-02-06 13:13:41 -05:00
# endif // RHI_RAYTRACING
2020-06-23 18:40:00 -04:00
2022-11-07 10:15:34 -05:00
// When using shader library, shader code is usually preloaded during the material load. Release it
// since we won't need it anymore for this shader.
ReleasePreloadedShaderCode ( ShaderIndex ) ;
}
2020-06-23 18:40:00 -04:00
}
2022-11-07 10:15:34 -05:00
if ( LIKELY ( CreatedShader ) )
{
// free redundantly created shader
checkSlow ( Shader ! = nullptr ) ;
CreatedShader - > Release ( ) ;
}
return Shader ;
2020-02-06 13:13:41 -05:00
}
2022-11-28 19:16:55 -05:00
FSHAHash FShaderMapResource_InlineCode : : GetShaderHash ( int32 ShaderIndex )
{
return Code - > ShaderHashes [ ShaderIndex ] ;
}
2024-04-25 04:16:22 -04:00
FRHIShader * FShaderMapResource_InlineCode : : CreateRHIShaderOrCrash ( int32 ShaderIndex , bool bRequired )
2020-02-06 13:13:41 -05:00
{
2022-11-07 10:15:34 -05:00
TRACE_CPUPROFILER_EVENT_SCOPE ( FShaderMapResource_InlineCode : : CreateRHIShaderOrCrash ) ;
Fix memory leak of shader code during shader compilation (during cooks, deployments, or editor). Depending on settings and project this can save a considerable amount. For example, this saved ~39GB on the test project I was cooking.
- FShaderMapResourceCode derives from FThreadSafeRefCountedObject which has a member that keeps track of the number of references to the object. We were doing deep copies using the Copy Constructor of FShaderMapResourceCode which resulted in a member wise copy of the num refs. This is not the behavior you'd expect.
- The offending line of code that caused the memory leak was in FShaderMapBase::AssignCopy:
- Code = new FShaderMapResourceCode(*Source.Code);
- Like FRefCountBase I've deleted the copy constructor and assignment operator for FRefCountedObject and FThreadSafeRefCountedObject to catch issues at compile time where we are copying across NumRefs incorrectly.
- To fix the issue I've manually created copy constructors for FGPUProfilerEventNodeStats and FShaderMapResourceCode.
#rb Devin.Doucette, Dave.Jones, Arciel.Rekman, Ben.Ingram
#review-16115628 @Devin.Doucette, @Dave.Jones, @Arciel.Rekman, @Ben.Ingram
#jira UE-108598, UE-113736
[CL 16116577 by Jason Nadro in ue5-main branch]
2021-04-26 14:03:07 -04:00
2020-02-06 13:13:41 -05:00
// we can't have this called on the wrong platform's shaders
if ( ! ArePlatformsCompatible ( GMaxRHIShaderPlatform , GetPlatform ( ) ) )
{
2022-11-07 10:15:34 -05:00
UE_LOG ( LogShaders , Fatal , TEXT ( " FShaderMapResource_InlineCode::InitRHI got platform %s but it is not compatible with %s " ) ,
* LegacyShaderPlatformToShaderFormat ( GetPlatform ( ) ) . ToString ( ) , * LegacyShaderPlatformToShaderFormat ( GMaxRHIShaderPlatform ) . ToString ( ) ) ;
// unreachable
return nullptr ;
2020-02-06 13:13:41 -05:00
}
FMemStackBase & MemStack = FMemStack : : Get ( ) ;
2024-09-10 13:06:22 -04:00
const FShaderCodeResource & ShaderCodeResource = Code - > ShaderCodeResources [ ShaderIndex ] ;
2024-10-01 19:02:22 -04:00
FSharedBuffer ShaderCode = ShaderCodeResource . GetCodeBuffer ( ) ;
TConstArrayView < uint8 > ShaderCodeView = ShaderCodeResource . GetCodeView ( ) ;
2020-02-06 13:13:41 -05:00
FMemMark Mark ( MemStack ) ;
2024-10-01 19:02:22 -04:00
int32 UncompressedSize = ShaderCodeResource . GetUncompressedSize ( ) ;
if ( ShaderCode . GetSize ( ) ! = UncompressedSize )
2020-02-06 13:13:41 -05:00
{
2024-10-01 19:02:22 -04:00
void * UncompressedCode = MemStack . Alloc ( UncompressedSize , 16 ) ;
bool bSucceed = FCompression : : UncompressMemory ( GetShaderCompressionFormat ( ) , UncompressedCode , UncompressedSize , ShaderCode . GetData ( ) , ShaderCode . GetSize ( ) ) ;
2020-02-06 13:13:41 -05:00
check ( bSucceed ) ;
2024-10-01 19:02:22 -04:00
ShaderCodeView = MakeArrayView ( reinterpret_cast < const uint8 * > ( UncompressedCode ) , UncompressedSize ) ;
2020-02-06 13:13:41 -05:00
}
const FSHAHash & ShaderHash = Code - > ShaderHashes [ ShaderIndex ] ;
2024-10-01 19:02:22 -04:00
const EShaderFrequency Frequency = ShaderCodeResource . GetFrequency ( ) ;
2020-02-06 13:13:41 -05:00
2022-11-11 13:36:14 -05:00
TRefCountPtr < FRHIShader > RHIShader ;
2020-02-06 13:13:41 -05:00
switch ( Frequency )
{
case SF_Vertex : RHIShader = RHICreateVertexShader ( ShaderCodeView , ShaderHash ) ; break ;
2021-03-18 18:42:49 -04:00
case SF_Mesh : RHIShader = RHICreateMeshShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Amplification : RHIShader = RHICreateAmplificationShader ( ShaderCodeView , ShaderHash ) ; break ;
2020-02-06 13:13:41 -05:00
case SF_Pixel : RHIShader = RHICreatePixelShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Geometry : RHIShader = RHICreateGeometryShader ( ShaderCodeView , ShaderHash ) ; break ;
case SF_Compute : RHIShader = RHICreateComputeShader ( ShaderCodeView , ShaderHash ) ; break ;
2024-04-22 14:59:28 -04:00
case SF_WorkGraphRoot : RHIShader = RHICreateWorkGraphShader ( ShaderCodeView , ShaderHash , SF_WorkGraphRoot ) ; break ;
case SF_WorkGraphComputeNode : RHIShader = RHICreateWorkGraphShader ( ShaderCodeView , ShaderHash , SF_WorkGraphComputeNode ) ; break ;
2020-02-06 13:13:41 -05:00
case SF_RayGen : case SF_RayMiss : case SF_RayHitGroup : case SF_RayCallable :
2020-09-01 14:07:48 -04:00
# if RHI_RAYTRACING
2021-11-23 10:25:31 -05:00
if ( GRHISupportsRayTracing & & GRHISupportsRayTracingShaders )
2020-02-06 13:13:41 -05:00
{
RHIShader = RHICreateRayTracingShader ( ShaderCodeView , ShaderHash , Frequency ) ;
}
# endif // RHI_RAYTRACING
2020-09-01 14:07:48 -04:00
break ;
2020-02-06 13:13:41 -05:00
default :
checkNoEntry ( ) ;
break ;
}
2022-11-07 10:15:34 -05:00
if ( UNLIKELY ( RHIShader = = nullptr ) )
2020-02-06 13:13:41 -05:00
{
2024-04-25 04:16:22 -04:00
if ( bRequired )
{
UE_LOG ( LogShaders , Fatal , TEXT ( " FShaderMapResource_InlineCode::InitRHI is unable to create a shader: frequency=%d, hash=%s. " ) , static_cast < int32 > ( Frequency ) , * ShaderHash . ToString ( ) ) ;
}
2022-11-07 10:15:34 -05:00
return nullptr ;
2020-02-06 13:13:41 -05:00
}
2022-11-07 10:15:34 -05:00
2024-05-10 11:19:30 -04:00
INC_DWORD_STAT ( STAT_Shaders_NumShadersCreated ) ;
2024-05-16 10:48:02 -04:00
2024-06-14 18:16:47 -04:00
# if (CSV_PROFILER_STATS && !UE_BUILD_SHIPPING)
2024-05-16 10:48:02 -04:00
TCsvPersistentCustomStat < int > * CsvStatNumShadersCreated = FCsvProfiler : : Get ( ) - > GetOrCreatePersistentCustomStatInt ( TEXT ( " NumShadersCreated " ) , CSV_CATEGORY_INDEX ( Shaders ) ) ;
CsvStatNumShadersCreated - > Add ( 1 ) ;
# endif
2022-11-07 10:15:34 -05:00
RHIShader - > SetHash ( ShaderHash ) ;
// contract of this function is to return a shader with an already held reference
RHIShader - > AddRef ( ) ;
2020-02-06 13:13:41 -05:00
return RHIShader ;
}
2024-05-09 09:33:32 -04:00
uint32 FShaderMapResource_InlineCode : : GetSizeBytes ( ) const
{
uint32 TotalSize = 0 ;
if ( Code )
{
TotalSize + = Code - > GetSizeBytes ( ) ;
}
TotalSize + = sizeof ( FShaderMapResource_InlineCode ) ;
TotalSize + = GetAllocatedSize ( ) ;
return TotalSize ;
}