2019-12-26 15:32:37 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "ShaderPreprocessor.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "Misc/FileHelper.h"
# include "Misc/Paths.h"
# include "Misc/ScopeLock.h"
# include "Modules/ModuleManager.h"
2014-11-21 12:21:29 -05:00
# include "PreprocessorPrivate.h"
2014-03-14 14:13:41 -04:00
2022-12-01 09:27:13 -05:00
# include "stb_preprocess/preprocessor.h"
# include "stb_preprocess/stb_alloc.h"
# include "stb_preprocess/stb_ds.h"
namespace
{
const FString PlatformHeader = TEXT ( " /Engine/Public/Platform.ush " ) ;
const FString PlatformHeaderLowerCase = PlatformHeader . ToLower ( ) ;
2023-05-03 10:17:48 -04:00
void LogMandatoryHeaderError ( const FShaderCompilerInput & Input , FShaderPreprocessOutput & Output )
2022-12-01 09:27:13 -05:00
{
2023-05-03 10:17:48 -04:00
FString Path = Input . VirtualSourceFilePath ;
FString Message = FString : : Printf ( TEXT ( " Error: Shader is required to include %s " ) , * PlatformHeader ) ;
Output . LogError ( MoveTemp ( Path ) , MoveTemp ( Message ) , 1 ) ;
2022-12-01 09:27:13 -05:00
}
}
2014-03-14 14:13:41 -04:00
2023-03-31 09:55:19 -04:00
static void AddStbDefine ( stb_arena * MacroArena , macro_definition * * & StbDefines , const TCHAR * Name , const TCHAR * Value ) ;
2023-06-21 03:26:02 -04:00
static void AddStbDefines ( stb_arena * MacroArena , macro_definition * * & StbDefines , const FShaderCompilerDefinitions & Defines ) ;
2023-03-31 09:55:19 -04:00
class FShaderPreprocessorUtilities
2019-09-14 09:45:25 -04:00
{
2023-03-31 09:55:19 -04:00
public :
2023-05-03 10:17:48 -04:00
static void DumpShaderDefinesAsCommentedCode ( const FShaderCompilerEnvironment & Environment , FString * OutDefines )
2019-09-14 09:45:25 -04:00
{
2023-06-21 03:26:02 -04:00
TArray < FString > DefinesLines ;
DefinesLines . Reserve ( Environment . Definitions . Num ( ) ) ;
for ( FShaderCompilerDefinitions : : FConstIterator DefineIt ( Environment . Definitions ) ; DefineIt ; + + DefineIt )
{
DefinesLines . Add ( FString : : Printf ( TEXT ( " // #define %s %s \n " ) , DefineIt . Key ( ) , DefineIt . Value ( ) ) ) ;
}
DefinesLines . Sort ( ) ;
2023-03-31 09:55:19 -04:00
FString Defines ;
2023-06-21 03:26:02 -04:00
for ( const FString & DefineLine : DefinesLines )
2023-03-31 09:55:19 -04:00
{
2023-06-21 03:26:02 -04:00
Defines + = DefineLine ;
2023-03-31 09:55:19 -04:00
}
2023-05-03 10:17:48 -04:00
* OutDefines + = MakeInjectedShaderCodeBlock ( TEXT ( " DumpShaderDefinesAsCommentedCode " ) , Defines ) ;
2019-09-14 09:45:25 -04:00
}
2021-08-18 16:55:41 -04:00
2023-05-19 14:50:25 -04:00
static void PopulateDefines ( const FShaderCompilerEnvironment & Environment , const FShaderCompilerDefinitions & AdditionalDefines , stb_arena * MacroArena , macro_definition * * & OutDefines )
2023-03-31 09:55:19 -04:00
{
2023-06-21 03:26:02 -04:00
AddStbDefines ( MacroArena , OutDefines , Environment . Definitions ) ;
AddStbDefines ( MacroArena , OutDefines , AdditionalDefines ) ;
2023-03-31 09:55:19 -04:00
}
} ;
2019-09-14 09:45:25 -04:00
2018-12-18 12:15:17 -05:00
//////////////////////////////////////////////////////////////////////////
2022-12-01 09:27:13 -05:00
extern " C "
{
// adapter functions for STB memory allocation
void * StbMalloc ( size_t Size )
{
void * Alloc = FMemory : : Malloc ( Size ) ;
return Alloc ;
}
void * StbRealloc ( void * Pointer , size_t Size )
{
void * Alloc = FMemory : : Realloc ( Pointer , Size ) ;
return Alloc ;
}
void StbFree ( void * Pointer )
{
return FMemory : : Free ( Pointer ) ;
}
ANSICHAR * StbStrDup ( const ANSICHAR * InString )
{
if ( InString )
{
int32 Len = FCStringAnsi : : Strlen ( InString ) + 1 ;
ANSICHAR * Result = reinterpret_cast < ANSICHAR * > ( StbMalloc ( Len ) ) ;
return FCStringAnsi : : Strncpy ( Result , InString , Len ) ;
}
return nullptr ;
}
}
struct FStbPreprocessContext
{
const FShaderCompilerInput & ShaderInput ;
2023-05-03 10:17:48 -04:00
const FShaderCompilerEnvironment & Environment ;
2022-12-01 09:27:13 -05:00
TMap < FString , TArray < ANSICHAR > > LoadedIncludesCache ;
TMap < FString , TUniquePtr < ANSICHAR [ ] > > SeenPathsLowerCase ;
bool HasIncludedMandatoryHeaders ( )
{
return SeenPathsLowerCase . Contains ( PlatformHeaderLowerCase ) ;
}
} ;
2023-05-31 11:08:31 -04:00
inline bool IsEndOfLine ( TCHAR C )
2022-12-01 09:27:13 -05:00
{
2023-05-31 11:08:31 -04:00
return C = = TEXT ( ' \r ' ) | | C = = TEXT ( ' \n ' ) ;
2022-12-01 09:27:13 -05:00
}
2023-05-31 11:08:31 -04:00
inline bool CommentStripNeedsHandling ( TCHAR C )
2022-12-01 09:27:13 -05:00
{
2023-05-31 11:08:31 -04:00
return IsEndOfLine ( C ) | | C = = TEXT ( ' / ' ) | | C = = 0 ;
2022-12-01 09:27:13 -05:00
}
2023-05-31 11:08:31 -04:00
inline int NewlineCharCount ( TCHAR First , TCHAR Second )
2022-12-01 09:27:13 -05:00
{
2023-05-31 11:08:31 -04:00
return ( ( First + Second ) = = TEXT ( ' \r ' ) + TEXT ( ' \n ' ) ) ? 2 : 1 ;
2022-12-01 09:27:13 -05:00
}
2023-05-31 11:08:31 -04:00
// Given an FString containing the contents of a shader source file, populates the given array with contents of
// that source file with all comments stripped. This is needed since the STB preprocessor itself does not strip
// comments.
2023-05-25 11:00:28 -04:00
void ConvertAndStripComments ( const FString & ShaderSource , TArray < ANSICHAR > & OutStripped )
{
// STB preprocessor does not strip comments, so we do so here before returning the loaded source
// Doing so is barely more costly than the memcopy we require anyways so has negligible overhead.
// Reserve worst case (i.e. assuming there are no comments at all) to avoid reallocation
2023-05-31 11:08:31 -04:00
int32 BufferSize = ShaderSource . Len ( ) + 1 ; // +1 to append null terminator
OutStripped . SetNumUninitialized ( BufferSize ) ;
2023-05-25 11:00:28 -04:00
ANSICHAR * CurrentOut = OutStripped . GetData ( ) ;
2023-05-31 11:08:31 -04:00
const TCHAR * const End = ShaderSource . GetCharArray ( ) . GetData ( ) + ShaderSource . Len ( ) ;
2023-05-25 11:00:28 -04:00
// We rely on null termination to avoid the need to check Current < End in some cases
2023-05-31 11:08:31 -04:00
check ( * End = = TEXT ( ' \0 ' ) ) ;
for ( const TCHAR * Current = ShaderSource . GetCharArray ( ) . GetData ( ) ; Current < End ; )
2023-05-25 11:00:28 -04:00
{
2023-05-31 11:08:31 -04:00
// sanity check that we're not overrunning the buffer
check ( CurrentOut < ( OutStripped . GetData ( ) + BufferSize ) ) ;
// CommentStripNeedsHandling returns true when *Current == '\0';
2022-12-01 09:27:13 -05:00
while ( ! CommentStripNeedsHandling ( * Current ) )
{
2023-05-31 11:08:31 -04:00
// straight cast to ansichar; since this is a character in hlsl source that's not in a comment
// we assume that it must be valid to do so. if this assumption is not valid the shader source was
// broken/corrupt anyways.
* CurrentOut + + = ( ANSICHAR ) ( * Current + + ) ;
2022-12-01 09:27:13 -05:00
}
if ( IsEndOfLine ( * Current ) )
{
* CurrentOut + + = ' \n ' ;
Current + = NewlineCharCount ( Current [ 0 ] , Current [ 1 ] ) ;
}
else if ( Current [ 0 ] = = ' / ' )
{
if ( Current [ 1 ] = = ' / ' )
{
while ( ! IsEndOfLine ( * Current ) & & Current < End )
{
+ + Current ;
}
}
else if ( Current [ 1 ] = = ' * ' )
{
Current + = 2 ;
2023-02-23 11:44:33 -05:00
while ( Current < End )
2022-12-01 09:27:13 -05:00
{
2023-02-23 11:44:33 -05:00
if ( Current [ 0 ] = = ' * ' & & Current [ 1 ] = = ' / ' )
{
Current + = 2 ;
break ;
}
else if ( IsEndOfLine ( * Current ) )
2022-12-01 09:27:13 -05:00
{
* CurrentOut + + = ' \n ' ;
Current + = NewlineCharCount ( Current [ 0 ] , Current [ 1 ] ) ;
}
else
{
+ + Current ;
}
}
}
else
{
2023-05-31 11:08:31 -04:00
* CurrentOut + + = ( ANSICHAR ) ( * Current + + ) ;
2022-12-01 09:27:13 -05:00
}
}
}
// Null terminate after comment-stripped copy
2023-05-31 11:08:31 -04:00
check ( CurrentOut < ( OutStripped . GetData ( ) + BufferSize ) ) ;
2022-12-01 09:27:13 -05:00
* CurrentOut + + = 0 ;
// Set correct length after stripping but don't bother shrinking/reallocating, minor memory overhead to save time
OutStripped . SetNum ( CurrentOut - OutStripped . GetData ( ) , /* bAllowShrinking */ false ) ;
}
2023-06-01 09:03:52 -04:00
const FString * FindInMemorySource ( const FShaderCompilerEnvironment & Environment , const FString & FilenameConverted )
2023-05-03 10:17:48 -04:00
{
2023-06-01 09:03:52 -04:00
const FString * InMemorySource = Environment . IncludeVirtualPathToContentsMap . Find ( FilenameConverted ) ;
if ( ! InMemorySource )
2023-05-03 10:17:48 -04:00
{
2023-06-01 09:03:52 -04:00
const FThreadSafeSharedStringPtr * SharedPtr = Environment . IncludeVirtualPathToExternalContentsMap . Find ( FilenameConverted ) ;
InMemorySource = SharedPtr ? SharedPtr - > Get ( ) : nullptr ;
2023-05-03 10:17:48 -04:00
}
2023-06-01 09:03:52 -04:00
return InMemorySource ;
2023-05-03 10:17:48 -04:00
}
2022-12-01 09:27:13 -05:00
static const ANSICHAR * StbLoadFile ( const ANSICHAR * Filename , void * RawContext , size_t * OutLength )
{
FStbPreprocessContext & Context = * reinterpret_cast < FStbPreprocessContext * > ( RawContext ) ;
FString FilenameConverted = StringCast < TCHAR > ( Filename ) . Get ( ) ;
2023-06-01 09:03:52 -04:00
TArray < ANSICHAR > * ContentsCached = Context . LoadedIncludesCache . Find ( FilenameConverted ) ;
if ( ! ContentsCached )
2022-12-01 09:27:13 -05:00
{
2023-06-01 09:03:52 -04:00
ContentsCached = & Context . LoadedIncludesCache . Add ( FilenameConverted ) ;
// Local FString used for the LoadShaderSourceFile path; we should consider retrieving source from the shader file cache as a reference
// (avoid an extra alloc+copy)
FString SourceCopy ;
2023-05-31 11:08:31 -04:00
2023-06-01 09:03:52 -04:00
const FString * InMemorySource = FindInMemorySource ( Context . Environment , FilenameConverted ) ;
if ( ! InMemorySource )
{
CheckShaderHashCacheInclude ( FilenameConverted , Context . ShaderInput . Target . GetPlatform ( ) , Context . ShaderInput . ShaderFormat . ToString ( ) ) ;
LoadShaderSourceFile ( * FilenameConverted , Context . ShaderInput . Target . GetPlatform ( ) , & SourceCopy , nullptr ) ;
InMemorySource = & SourceCopy ;
}
check ( InMemorySource & & ! InMemorySource - > IsEmpty ( ) ) ;
ConvertAndStripComments ( * InMemorySource , * ContentsCached ) ;
}
check ( ContentsCached ) ;
* OutLength = ContentsCached - > Num ( ) ;
return ContentsCached - > GetData ( ) ;
2022-12-01 09:27:13 -05:00
}
static void StbFreeFile ( const ANSICHAR * Filename , const ANSICHAR * Contents , void * RawContext )
{
2023-06-01 09:03:52 -04:00
// No-op; stripped/converted shader source will be freed from the cache in FStbPreprocessContext when it's destructed;
// we want to keep it around until that point in case includes are loaded multiple times from different source locations
2022-12-01 09:27:13 -05:00
}
static const ANSICHAR * StbResolveInclude ( const ANSICHAR * PathInSource , uint32 PathLen , const ANSICHAR * ParentPathAnsi , void * RawContext )
{
FStbPreprocessContext & Context = * reinterpret_cast < FStbPreprocessContext * > ( RawContext ) ;
FString PathModified ( PathLen , PathInSource ) ;
FString ParentFolder ( ParentPathAnsi ) ;
ParentFolder = FPaths : : GetPath ( ParentFolder ) ;
if ( ! PathModified . StartsWith ( TEXT ( " / " ) ) ) // if path doesn't start with / it's relative, if so append the parent's folder and collapse any relative dirs
{
PathModified = ParentFolder / PathModified ;
FPaths : : CollapseRelativeDirectories ( PathModified ) ;
}
2023-05-31 11:08:31 -04:00
FixupShaderFilePath ( PathModified , Context . ShaderInput . Target . GetPlatform ( ) , & Context . ShaderInput . ShaderPlatformName ) ;
2022-12-01 09:27:13 -05:00
FString PathModifiedLowerCase = PathModified . ToLower ( ) ;
const TUniquePtr < ANSICHAR [ ] > * SeenPath = Context . SeenPathsLowerCase . Find ( PathModifiedLowerCase ) ;
// Keep track of previously resolved paths in a case insensitive manner so preprocessor will handle #pragma once with files included with inconsistent casing correctly
// (we store the first correctly resolved path with original casing so we get "nice" line directives)
if ( SeenPath )
{
return SeenPath - > Get ( ) ;
}
bool bExists =
2023-05-03 10:17:48 -04:00
Context . Environment . IncludeVirtualPathToContentsMap . Contains ( PathModified ) | |
Context . Environment . IncludeVirtualPathToExternalContentsMap . Contains ( PathModified ) | |
2023-06-01 09:03:52 -04:00
// LoadShaderSourceFile will load the file if it exists, but then cache it internally, so the next call in StbLoadFile will be cheap
2023-05-31 11:08:31 -04:00
// (and hence this is not wasteful, just performs the loading earlier)
2023-06-01 09:03:52 -04:00
LoadShaderSourceFile ( * PathModified , Context . ShaderInput . Target . GetPlatform ( ) , nullptr , nullptr ) ;
2022-12-01 09:27:13 -05:00
if ( bExists )
{
int32 Length = FPlatformString : : ConvertedLength < ANSICHAR > ( * PathModified ) ;
TUniquePtr < ANSICHAR [ ] > & OutPath = Context . SeenPathsLowerCase . Add ( PathModifiedLowerCase , MakeUnique < ANSICHAR [ ] > ( Length ) ) ;
FPlatformString : : Convert < TCHAR , ANSICHAR > ( OutPath . Get ( ) , Length , * PathModified ) ;
return OutPath . Get ( ) ;
}
return nullptr ;
}
class FShaderPreprocessorModule : public IModuleInterface
{
virtual void StartupModule ( ) override
{
init_preprocessor ( & StbLoadFile , & StbFreeFile , & StbResolveInclude ) ;
// disable the "directive not at start of line" error; this allows a few things:
// 1. #define'ing #pragma messages - consumed by the preprocessor (to handle UESHADERMETADATA hackery)
// 2. #define'ing other #pragmas (those not processed explicitly by the preprocessor are copied into the preprocessed code
// 3. handling the HLSL infinity constant (1.#INF); STB preprocessor interprets any use of # as a directive which is not the case here
pp_set_warning_mode ( PP_RESULT_directive_not_at_start_of_line , PP_RESULT_MODE_no_warning ) ;
}
} ;
IMPLEMENT_MODULE ( FShaderPreprocessorModule , ShaderPreprocessor ) ;
static void AddStbDefine ( stb_arena * MacroArena , macro_definition * * & StbDefines , const TCHAR * Name , const TCHAR * Value )
{
FString Define ( FString : : Printf ( TEXT ( " %s %s " ) , Name , Value ) ) ;
auto ConvertedDefine = StringCast < ANSICHAR > ( * Define ) ;
arrput ( StbDefines , pp_define ( MacroArena , ( ANSICHAR * ) ConvertedDefine . Get ( ) ) ) ;
}
2023-06-21 03:26:02 -04:00
static void AddStbDefines ( stb_arena * MacroArena , macro_definition * * & StbDefines , const FShaderCompilerDefinitions & Defines )
2022-12-01 09:27:13 -05:00
{
2023-06-21 03:26:02 -04:00
for ( FShaderCompilerDefinitions : : FConstIterator It ( Defines ) ; It ; + + It )
2022-12-01 09:27:13 -05:00
{
2023-06-21 03:26:02 -04:00
AddStbDefine ( MacroArena , StbDefines , It . Key ( ) , It . Value ( ) ) ;
2022-12-01 09:27:13 -05:00
}
}
bool InnerPreprocessShaderStb (
2023-05-03 10:17:48 -04:00
FShaderPreprocessOutput & Output ,
const FShaderCompilerInput & Input ,
const FShaderCompilerEnvironment & Environment ,
2022-12-01 09:27:13 -05:00
const FShaderCompilerDefinitions & AdditionalDefines
)
{
stb_arena MacroArena = { 0 } ;
macro_definition * * StbDefines = nullptr ;
2023-05-19 14:50:25 -04:00
FShaderPreprocessorUtilities : : PopulateDefines ( Environment , AdditionalDefines , & MacroArena , StbDefines ) ;
2022-12-01 09:27:13 -05:00
2023-05-03 10:17:48 -04:00
FStbPreprocessContext Context { Input , Environment } ;
2022-12-01 09:27:13 -05:00
2023-05-03 10:17:48 -04:00
auto InFilename = StringCast < ANSICHAR > ( * Input . VirtualSourceFilePath ) ;
2022-12-01 09:27:13 -05:00
int NumDiagnostics = 0 ;
pp_diagnostic * Diagnostics = nullptr ;
char * OutPreprocessedAnsi = preprocess_file ( nullptr , InFilename . Get ( ) , & Context , StbDefines , arrlen ( StbDefines ) , & Diagnostics , & NumDiagnostics ) ;
bool HasError = false ;
if ( Diagnostics ! = nullptr )
{
for ( int DiagIndex = 0 ; DiagIndex < NumDiagnostics ; + + DiagIndex )
{
pp_diagnostic * Diagnostic = & Diagnostics [ DiagIndex ] ;
HasError | = ( Diagnostic - > error_level = = PP_RESULT_MODE_error ) ;
FString Message = Diagnostic - > message ;
2023-05-19 14:50:25 -04:00
// ignore stb warnings (for now?)
2022-12-01 09:27:13 -05:00
if ( Diagnostic - > error_level = = PP_RESULT_MODE_error )
{
2023-05-03 10:17:48 -04:00
FString Filename = Diagnostic - > where - > filename ;
Output . LogError ( MoveTemp ( Filename ) , MoveTemp ( Message ) , Diagnostic - > where - > line_number ) ;
2022-12-01 09:27:13 -05:00
}
else
{
EMessageType Type = FilterPreprocessorError ( Message ) ;
if ( Type = = EMessageType : : ShaderMetaData )
{
FString Directive ;
ExtractDirective ( Directive , Message ) ;
2023-05-03 10:17:48 -04:00
Output . AddDirective ( MoveTemp ( Directive ) ) ;
2022-12-01 09:27:13 -05:00
}
}
}
}
2023-05-03 10:17:48 -04:00
if ( ! HasError )
{
Output . EditSource ( ) . Append ( OutPreprocessedAnsi ) ;
}
2022-12-01 09:27:13 -05:00
if ( ! HasError & & ! Context . HasIncludedMandatoryHeaders ( ) )
{
2023-05-03 10:17:48 -04:00
LogMandatoryHeaderError ( Input , Output ) ;
2022-12-01 09:27:13 -05:00
HasError = true ;
}
preprocessor_file_free ( OutPreprocessedAnsi , Diagnostics ) ;
stbds_arrfree ( StbDefines ) ;
stb_arena_free ( & MacroArena ) ;
return ! HasError ;
}
2023-05-03 10:17:48 -04:00
bool PreprocessShader (
FString & OutPreprocessedShader ,
FShaderCompilerOutput & ShaderOutput ,
const FShaderCompilerInput & ShaderInput ,
const FShaderCompilerDefinitions & AdditionalDefines ,
EDumpShaderDefines DefinesPolicy )
{
FShaderPreprocessOutput Output ;
// when called via this overload, environment is assumed to be already merged in input struct
const FShaderCompilerEnvironment & Environment = ShaderInput . Environment ;
bool bSucceeded = PreprocessShader ( Output , ShaderInput , Environment , AdditionalDefines , DefinesPolicy ) ;
OutPreprocessedShader = MoveTemp ( Output . EditSource ( ) ) ;
Output . MoveDirectives ( ShaderOutput . PragmaDirectives ) ;
for ( FShaderCompilerError & Error : Output . EditErrors ( ) )
{
ShaderOutput . Errors . Add ( MoveTemp ( Error ) ) ;
}
return bSucceeded ;
}
2022-12-01 09:27:13 -05:00
/**
* Preprocess a shader .
* @ param OutPreprocessedShader - Upon return contains the preprocessed source code .
* @ param ShaderOutput - ShaderOutput to which errors can be added .
* @ param ShaderInput - The shader compiler input .
* @ param AdditionalDefines - Additional defines with which to preprocess the shader .
* @ param DefinesPolicy - Whether to add shader definitions as comments .
* @ returns true if the shader is preprocessed without error .
*/
bool PreprocessShader (
2023-05-03 10:17:48 -04:00
FShaderPreprocessOutput & Output ,
const FShaderCompilerInput & Input ,
const FShaderCompilerEnvironment & Environment ,
2022-12-01 09:27:13 -05:00
const FShaderCompilerDefinitions & AdditionalDefines ,
EDumpShaderDefines DefinesPolicy
)
{
TRACE_CPUPROFILER_EVENT_SCOPE ( PreprocessShader ) ;
// Skip the cache system and directly load the file path (used for debugging)
2023-05-03 10:17:48 -04:00
if ( Input . bSkipPreprocessedCache )
2022-12-01 09:27:13 -05:00
{
2023-05-03 10:17:48 -04:00
return FFileHelper : : LoadFileToString ( Output . EditSource ( ) , * Input . VirtualSourceFilePath ) ;
2022-12-01 09:27:13 -05:00
}
2023-06-07 16:52:24 -04:00
check ( CheckVirtualShaderFilePath ( Input . VirtualSourceFilePath ) ) ;
Output . EditSource ( ) . Empty ( ) ;
2023-05-03 10:17:48 -04:00
// List the defines used for compilation in the preprocessed shaders, especially to know which permutation vector this shader is.
if ( DefinesPolicy = = EDumpShaderDefines : : AlwaysIncludeDefines | | ( DefinesPolicy = = EDumpShaderDefines : : DontCare & & Input . DumpDebugInfoPath . Len ( ) > 0 ) )
{
FShaderPreprocessorUtilities : : DumpShaderDefinesAsCommentedCode ( Environment , & Output . EditSource ( ) ) ;
2022-12-01 09:27:13 -05:00
}
2023-05-19 14:50:25 -04:00
return InnerPreprocessShaderStb ( Output , Input , Environment , AdditionalDefines ) ;
2014-03-14 14:13:41 -04:00
}