2020-12-08 11:40:10 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "ShaderConductorContext.h"
# include "HAL/ExceptionHandling.h"
2023-08-03 13:40:32 -04:00
# include "ShaderCompilerDefinitions.h"
2024-01-12 11:06:50 -05:00
# include "Containers/AnsiString.h"
2020-12-08 11:40:10 -04:00
# if PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
THIRD_PARTY_INCLUDES_START
# include "ShaderConductor/ShaderConductor.hpp"
THIRD_PARTY_INCLUDES_END
# endif
namespace CrossCompiler
{
# if PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
2022-10-20 09:43:50 -04:00
static void ScRewriteWrapper (
2020-12-08 11:40:10 -04:00
const ShaderConductor : : Compiler : : SourceDesc & InSourceDesc ,
const ShaderConductor : : Compiler : : Options & InOptions ,
ShaderConductor : : Compiler : : ResultDesc & OutResultDesc )
{
OutResultDesc = ShaderConductor : : Compiler : : Rewrite ( InSourceDesc , InOptions ) ;
}
2022-10-20 09:43:50 -04:00
static void ScCompileWrapper (
2020-12-08 11:40:10 -04:00
const ShaderConductor : : Compiler : : SourceDesc & InSourceDesc ,
const ShaderConductor : : Compiler : : Options & InOptions ,
const ShaderConductor : : Compiler : : TargetDesc & InTargetDesc ,
ShaderConductor : : Compiler : : ResultDesc & OutResultDesc )
{
OutResultDesc = ShaderConductor : : Compiler : : Compile ( InSourceDesc , InOptions , InTargetDesc ) ;
}
2022-10-20 09:43:50 -04:00
static void ScConvertBinaryWrapper (
2020-12-08 11:40:10 -04:00
const ShaderConductor : : Compiler : : ResultDesc & InBinaryDesc ,
const ShaderConductor : : Compiler : : SourceDesc & InSourceDesc ,
const ShaderConductor : : Compiler : : TargetDesc & InTargetDesc ,
2021-09-08 13:00:48 -04:00
const ShaderConductor : : Compiler : : Options & InOptions ,
2020-12-08 11:40:10 -04:00
ShaderConductor : : Compiler : : ResultDesc & OutResultDesc )
{
2021-09-08 13:00:48 -04:00
OutResultDesc = ShaderConductor : : Compiler : : ConvertBinary ( InBinaryDesc , InSourceDesc , InOptions , InTargetDesc ) ;
2020-12-08 11:40:10 -04:00
}
// Converts the specified ShaderConductor blob to FString.
static bool ConvertScBlobToFString ( ShaderConductor : : Blob * Blob , FString & OutString )
{
if ( Blob & & Blob - > Size ( ) > 0 )
{
2024-01-12 11:06:50 -05:00
OutString = StringCast < TCHAR > ( reinterpret_cast < const ANSICHAR * > ( Blob - > Data ( ) ) , Blob - > Size ( ) ) ;
return true ;
2020-12-08 11:40:10 -04:00
}
return false ;
}
2021-09-02 16:41:03 -04:00
static ShaderConductor : : ShaderStage ToShaderConductorShaderStage ( EShaderFrequency Frequency )
2020-12-08 11:40:10 -04:00
{
2021-09-02 16:41:03 -04:00
check ( Frequency > = SF_Vertex & & Frequency < = SF_RayCallable ) ;
2020-12-08 11:40:10 -04:00
switch ( Frequency )
{
2021-09-02 16:41:03 -04:00
case SF_Vertex : return ShaderConductor : : ShaderStage : : VertexShader ;
2024-02-15 13:52:17 -05:00
case SF_Mesh : return ShaderConductor : : ShaderStage : : MeshShader ;
case SF_Amplification : return ShaderConductor : : ShaderStage : : AmplificationShader ;
2021-09-02 16:41:03 -04:00
case SF_Pixel : return ShaderConductor : : ShaderStage : : PixelShader ;
case SF_Geometry : return ShaderConductor : : ShaderStage : : GeometryShader ;
case SF_Compute : return ShaderConductor : : ShaderStage : : ComputeShader ;
2021-04-22 17:38:43 -04:00
2021-09-02 16:41:03 -04:00
case SF_RayGen : return ShaderConductor : : ShaderStage : : RayGen ;
case SF_RayMiss : return ShaderConductor : : ShaderStage : : RayMiss ;
case SF_RayHitGroup : return ShaderConductor : : ShaderStage : : RayHitGroup ;
case SF_RayCallable : return ShaderConductor : : ShaderStage : : RayCallable ;
default : break ;
2020-12-08 11:40:10 -04:00
}
2021-09-02 16:41:03 -04:00
return ShaderConductor : : ShaderStage : : NumShaderStages ;
2020-12-08 11:40:10 -04:00
}
2024-01-12 11:06:50 -05:00
struct FOptionalConvertedAnsiString
{
FOptionalConvertedAnsiString & operator = ( FStringView WideView )
{
Storage . Empty ( ) ;
Storage . Append ( WideView ) ;
AnsiView = FAnsiStringView ( Storage ) ;
return * this ;
}
FOptionalConvertedAnsiString & operator = ( FAnsiStringView InAnsiView )
{
AnsiView = InAnsiView ;
return * this ;
}
void CopyAnsi ( FAnsiStringView InAnsiView )
{
Storage = InAnsiView ;
AnsiView = FAnsiStringView ( Storage ) ;
}
FAnsiString Storage ;
FAnsiStringView AnsiView ;
} ;
2020-12-08 11:40:10 -04:00
// Wrapper structure to hold all intermediate buffers for ShaderConductor
struct FShaderConductorContext : : FShaderConductorIntermediates
{
FShaderConductorIntermediates ( )
: Stage ( ShaderConductor : : ShaderStage : : NumShaderStages )
2024-02-20 10:23:08 -05:00
, bIsIntermediateCode ( false )
2020-12-08 11:40:10 -04:00
{
}
2024-01-12 11:06:50 -05:00
FOptionalConvertedAnsiString ShaderSource ;
FOptionalConvertedAnsiString Filename ;
FOptionalConvertedAnsiString EntryPoint ;
2020-12-08 11:40:10 -04:00
ShaderConductor : : ShaderStage Stage ;
2024-01-12 11:06:50 -05:00
TArray < TPair < FAnsiString , FAnsiString > > Defines ;
2020-12-08 11:40:10 -04:00
TArray < ShaderConductor : : MacroDefine > DefineRefs ;
2024-01-12 11:06:50 -05:00
TArray < TPair < FAnsiString , FAnsiString > > Flags ;
2020-12-08 11:40:10 -04:00
TArray < ShaderConductor : : MacroDefine > FlagRefs ;
2024-01-12 11:06:50 -05:00
FAnsiString InternalDxcArgs ;
TArray < FAnsiString > CustomDxcArgs ;
2021-11-23 14:28:47 -05:00
TArray < ANSICHAR const * > CustomDxcArgRefs ;
TArray < ANSICHAR const * > DxcArgRefs ;
2024-02-20 10:23:08 -05:00
bool bIsIntermediateCode ; // Is the current shader source the result of intermediate compilation such as the DXC rewriter?
2020-12-08 11:40:10 -04:00
} ;
static void ConvertScSourceDesc ( const FShaderConductorContext : : FShaderConductorIntermediates & Intermediates , ShaderConductor : : Compiler : : SourceDesc & OutSourceDesc )
{
// Convert descriptor with pointers to the ANSI strings
2024-01-12 11:06:50 -05:00
OutSourceDesc . source = Intermediates . ShaderSource . AnsiView . GetData ( ) ;
OutSourceDesc . fileName = Intermediates . Filename . AnsiView . GetData ( ) ;
OutSourceDesc . entryPoint = Intermediates . EntryPoint . AnsiView . GetData ( ) ;
2020-12-08 11:40:10 -04:00
OutSourceDesc . stage = Intermediates . Stage ;
if ( Intermediates . DefineRefs . Num ( ) > 0 )
{
OutSourceDesc . defines = Intermediates . DefineRefs . GetData ( ) ;
OutSourceDesc . numDefines = static_cast < uint32 > ( Intermediates . DefineRefs . Num ( ) ) ;
}
else
{
OutSourceDesc . defines = nullptr ;
OutSourceDesc . numDefines = 0 ;
}
}
2021-08-24 15:34:07 -04:00
static const ANSICHAR * GetHlslVersionString ( int32 Version )
{
switch ( Version )
{
case 50 : return " 50 " ;
case 60 : return " 60 " ;
case 61 : return " 61 " ;
case 62 : return " 62 " ;
case 63 : return " 63 " ;
case 64 : return " 64 " ;
case 65 : return " 65 " ;
case 66 : return " 66 " ;
default : return nullptr ;
}
}
static void ConvertScTargetDescLanguageHlsl ( const FShaderConductorTarget & InTarget , ShaderConductor : : Compiler : : TargetDesc & OutTargetDesc )
{
OutTargetDesc . language = ShaderConductor : : ShadingLanguage : : Hlsl ;
OutTargetDesc . version = GetHlslVersionString ( InTarget . Version ) ;
2023-08-28 17:50:38 -04:00
checkf ( OutTargetDesc . version ! = nullptr , TEXT ( " Unsupported target shader version for HLSL: SM%d.%d " ) , InTarget . Version / 10 , InTarget . Version % 10 ) ;
2021-08-24 15:34:07 -04:00
}
2020-12-08 11:40:10 -04:00
static const ANSICHAR * GetGlslFamilyVersionString ( int32 Version )
{
switch ( Version )
{
2021-10-19 13:00:13 -04:00
//ESSL
2020-12-08 11:40:10 -04:00
case 310 : return " 310 " ;
case 320 : return " 320 " ;
2021-10-19 13:00:13 -04:00
//GLSL
2020-12-08 11:40:10 -04:00
case 330 : return " 330 " ;
case 430 : return " 430 " ;
2021-10-19 13:00:13 -04:00
case 440 : return " 440 " ;
case 450 : return " 450 " ;
case 460 : return " 460 " ;
2020-12-08 11:40:10 -04:00
default : return nullptr ;
}
}
static void ConvertScTargetDescLanguageGlslFamily ( const FShaderConductorTarget & InTarget , ShaderConductor : : Compiler : : TargetDesc & OutTargetDesc )
{
OutTargetDesc . language = ( InTarget . Language = = EShaderConductorLanguage : : Glsl ? ShaderConductor : : ShadingLanguage : : Glsl : ShaderConductor : : ShadingLanguage : : Essl ) ;
OutTargetDesc . version = GetGlslFamilyVersionString ( InTarget . Version ) ;
2023-08-28 17:50:38 -04:00
checkf ( OutTargetDesc . version ! = nullptr , TEXT ( " Unsupported target shader version for GLSL family: %d " ) , InTarget . Version ) ;
2020-12-08 11:40:10 -04:00
}
static const ANSICHAR * GetMetalFamilyVersionString ( int32 Version )
{
switch ( Version )
{
2022-11-29 05:55:31 -05:00
case 30000 : return " 30000 " ;
2021-11-02 10:36:33 -04:00
case 20400 : return " 20400 " ;
2021-03-11 21:32:06 -04:00
case 20300 : return " 20300 " ;
case 20200 : return " 20200 " ;
2020-12-08 11:40:10 -04:00
case 20100 : return " 20100 " ;
case 20000 : return " 20000 " ;
case 10200 : return " 10200 " ;
case 10100 : return " 10100 " ;
case 10000 : return " 10000 " ;
default : return nullptr ;
}
}
static void ConvertScTargetDescLanguageMetalFamily ( const FShaderConductorTarget & InTarget , ShaderConductor : : Compiler : : TargetDesc & OutTargetDesc )
{
OutTargetDesc . language = ( InTarget . Language = = EShaderConductorLanguage : : Metal_macOS ? ShaderConductor : : ShadingLanguage : : Msl_macOS : ShaderConductor : : ShadingLanguage : : Msl_iOS ) ;
OutTargetDesc . version = GetMetalFamilyVersionString ( InTarget . Version ) ;
2023-08-28 17:50:38 -04:00
checkf ( OutTargetDesc . version ! = nullptr , TEXT ( " Unsupported target shader version for Metal family: %d " ) , InTarget . Version ) ;
2020-12-08 11:40:10 -04:00
}
2021-02-17 12:29:50 -04:00
// Converts an array of FString to a C-style array of char* pointers
2024-01-12 11:06:50 -05:00
static void ConvertStringArrayToAnsiArray ( const TArray < FString > & InPairs , TArray < FAnsiString > & OutPairs , TArray < const char * > & OutPairRefs )
2021-02-17 12:29:50 -04:00
{
// Convert map into an array container
TArray < ANSICHAR > Value ;
for ( const FString & Iter : InPairs )
{
2024-01-12 11:06:50 -05:00
OutPairs . Emplace ( Iter ) ;
2021-02-17 12:29:50 -04:00
}
// Store references after all elements have been added to the container so the pointers remain valid
OutPairRefs . SetNum ( OutPairs . Num ( ) ) ;
for ( int32 Index = 0 ; Index < OutPairs . Num ( ) ; + + Index )
{
2024-01-12 11:06:50 -05:00
OutPairRefs [ Index ] = * OutPairs [ Index ] ;
2021-02-17 12:29:50 -04:00
}
}
2023-07-22 06:35:10 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
2021-02-09 17:40:13 -04:00
// Converts a map of string pairs to a C-Style macro defines array
2024-01-12 11:06:50 -05:00
static void ConvertDefineMapToMacroDefines ( const FShaderCompilerDefinitions & Definitions , TArray < TPair < FAnsiString , FAnsiString > > & OutPairs , TArray < ShaderConductor : : MacroDefine > & OutPairRefs )
2021-02-09 17:40:13 -04:00
{
// Convert map into an array container
2023-06-21 03:26:02 -04:00
for ( FShaderCompilerDefinitions : : FConstIterator Iter ( Definitions ) ; Iter ; + + Iter )
2021-02-09 17:40:13 -04:00
{
2024-01-12 11:06:50 -05:00
OutPairs . Emplace ( Iter . Key ( ) , Iter . Value ( ) ) ;
2021-02-09 17:40:13 -04:00
}
// Store references after all elements have been added to the container so the pointers remain valid
OutPairRefs . SetNum ( OutPairs . Num ( ) ) ;
for ( int32 Index = 0 ; Index < OutPairs . Num ( ) ; + + Index )
{
2024-01-12 11:06:50 -05:00
OutPairRefs [ Index ] . name = * OutPairs [ Index ] . Key ;
OutPairRefs [ Index ] . value = * OutPairs [ Index ] . Value ;
2021-02-09 17:40:13 -04:00
}
}
2023-07-22 06:35:10 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2021-02-09 17:40:13 -04:00
2020-12-08 11:40:10 -04:00
static void ConvertScTargetDesc ( FShaderConductorContext : : FShaderConductorIntermediates & Intermediates , const FShaderConductorTarget & InTarget , ShaderConductor : : Compiler : : TargetDesc & OutTargetDesc )
{
// Convert FString to ANSI string and store them as intermediates
FMemory : : Memzero ( OutTargetDesc ) ;
2022-02-09 18:32:08 -05:00
Intermediates . Flags . Empty ( ) ;
Intermediates . FlagRefs . Empty ( ) ;
2020-12-08 11:40:10 -04:00
switch ( InTarget . Language )
{
2021-08-24 15:34:07 -04:00
case EShaderConductorLanguage : : Hlsl :
ConvertScTargetDescLanguageHlsl ( InTarget , OutTargetDesc ) ;
break ;
2020-12-08 11:40:10 -04:00
case EShaderConductorLanguage : : Glsl :
case EShaderConductorLanguage : : Essl :
ConvertScTargetDescLanguageGlslFamily ( InTarget , OutTargetDesc ) ;
break ;
case EShaderConductorLanguage : : Metal_macOS :
case EShaderConductorLanguage : : Metal_iOS :
ConvertScTargetDescLanguageMetalFamily ( InTarget , OutTargetDesc ) ;
break ;
}
// Convert flags map into an array container
2023-07-22 06:35:10 -04:00
ConvertDefineMapToMacroDefines ( * InTarget . CompileFlags , Intermediates . Flags , Intermediates . FlagRefs ) ;
2020-12-08 11:40:10 -04:00
OutTargetDesc . options = Intermediates . FlagRefs . GetData ( ) ;
OutTargetDesc . numOptions = static_cast < uint32 > ( Intermediates . FlagRefs . Num ( ) ) ;
// Wrap input function into lambda to convert to ShaderConductor interface
if ( InTarget . VariableTypeRenameCallback )
{
OutTargetDesc . variableTypeRenameCallback = [ InnerCallback = InTarget . VariableTypeRenameCallback ] ( const char * VariableName , const char * TypeName ) - > ShaderConductor : : Blob
{
// Forward callback to public interface callback
FString RenamedTypeName ;
if ( InnerCallback ( FAnsiStringView ( VariableName ) , FAnsiStringView ( TypeName ) , RenamedTypeName ) )
{
if ( ! RenamedTypeName . IsEmpty ( ) )
{
// Convert renamed type name from FString to ShaderConductor::Blob
return ShaderConductor : : Blob ( TCHAR_TO_ANSI ( * RenamedTypeName ) , RenamedTypeName . Len ( ) + 1 ) ;
}
}
return ShaderConductor : : Blob { } ;
} ;
}
}
2023-09-19 10:25:17 -04:00
/*
* Reduced list of SPIRV - Tools optimization passes to avoid nested expressions in GLSL output .
* The order of passes has been adopted from the standard ' - O ' optimization configuration with the following passes removed :
* - LocalSingleBlockLoadStoreElimPass
* - LocalSingleStoreElimPass
* - LocalMultiStoreElimPass
* - SSARewritePass
*/
static const TCHAR * GSpirvTools_OptPasses_PresetRelaxNestedExpr = TEXT (
" --wrap-opkill, "
" --eliminate-dead-branches, "
" --merge-return, "
" --inline-entry-points-exhaustive, "
" --eliminate-dead-functions, "
" --eliminate-dead-code-aggressive, "
" --private-to-local, "
" --eliminate-dead-code-aggressive, "
" --scalar-replacement, "
" --convert-local-access-chains, "
" --eliminate-dead-code-aggressive, "
" --ccp, "
" --eliminate-dead-code-aggressive, "
" --loop-unroll, "
" --eliminate-dead-branches, "
" --redundancy-elimination, "
" --combine-access-chains, "
" --simplify-instructions, "
" --scalar-replacement, "
" --convert-local-access-chains, "
" --eliminate-dead-code-aggressive, "
" --vector-dce, "
" --eliminate-dead-inserts, "
" --eliminate-dead-branches, "
" --simplify-instructions, "
" --if-conversion, "
" --copy-propagate-arrays, "
" --reduce-load-size, "
" --eliminate-dead-code-aggressive, "
" --merge-blocks, "
" --redundancy-elimination, "
" --eliminate-dead-branches, "
" --merge-blocks, "
" --simplify-instructions, "
" --eliminate-dead-members, "
" --merge-blocks, "
" --redundancy-elimination, "
" --simplify-instructions, "
" --eliminate-dead-code-aggressive, "
" --cfg-cleanup "
) ;
static const TCHAR * SelectSpirvCustomOptimizationPasses ( const FString & OptimizationPasses )
{
if ( OptimizationPasses = = TEXT ( " preset(relax-nested-expr) " ) )
{
return GSpirvTools_OptPasses_PresetRelaxNestedExpr ;
}
else
{
// Interpret input argument as set of optimization passes
return * OptimizationPasses ;
}
}
2024-02-20 10:23:08 -05:00
static void AppendDxcArguments ( const FShaderConductorOptions & InOptions , TArray < const ANSICHAR * > & DxcArguments , bool bIsIntermediateCode = false , bool bGenerateSpirv = true )
2023-11-08 14:23:36 -05:00
{
2024-02-15 13:52:17 -05:00
if ( bGenerateSpirv )
{
DxcArguments . Add ( " -spirv " ) ;
}
2023-11-08 14:23:36 -05:00
DxcArguments . Add ( " -Qunused-arguments " ) ;
switch ( InOptions . HlslVersion )
{
case 2015 :
DxcArguments . Add ( " -HV " ) ;
DxcArguments . Add ( " 2015 " ) ;
break ;
case 2016 :
DxcArguments . Add ( " -HV " ) ;
DxcArguments . Add ( " 2016 " ) ;
break ;
case 2017 :
DxcArguments . Add ( " -HV " ) ;
DxcArguments . Add ( " 2017 " ) ;
break ;
case 2018 :
DxcArguments . Add ( " -HV " ) ;
DxcArguments . Add ( " 2018 " ) ;
break ;
case 2021 :
DxcArguments . Add ( " -HV " ) ;
DxcArguments . Add ( " 2021 " ) ;
break ;
default :
checkf ( false , TEXT ( " Invalid HLSL version: expected 2015, 2016, 2017, 2018, or 2021 but %u was specified " ) , InOptions . HlslVersion ) ;
break ;
}
2024-02-20 10:23:08 -05:00
// We only treat warnings as errors for input source code, not intermediate source since DXC rewriter might produce new warnings the shader authors don't have control over.
if ( InOptions . bWarningsAsErrors & & ! bIsIntermediateCode )
{
DxcArguments . Add ( " -WX " ) ;
}
2023-11-08 14:23:36 -05:00
// Add additional DXC arguments that are not exposed by ShaderConductor API directly
if ( ! InOptions . bDisableScalarBlockLayout )
{
DxcArguments . Add ( " -fvk-use-scalar-layout " ) ;
}
if ( InOptions . bPreserveStorageInput )
{
DxcArguments . Add ( " -fspv-preserve-storage-input " ) ;
}
if ( InOptions . bForceStorageImageFormat )
{
DxcArguments . Add ( " -fvk-force-storage-image-format " ) ;
}
if ( InOptions . bSvPositionImplicitInvariant )
{
DxcArguments . Add ( " -fspv-svposition-implicit-invariant " ) ;
}
if ( InOptions . bSupportPreciseOutputs )
{
DxcArguments . Add ( " -fspv-support-precise-outputs " ) ;
}
using ETargetEnvironment = CrossCompiler : : FShaderConductorOptions : : ETargetEnvironment ;
if ( InOptions . bEnable16bitTypes )
{
DxcArguments . Add ( " -fspv-target-env=universal1.5 " ) ;
// ShaderConductor.cpp forgot to pipedown enable16bitTypes, so work arround by adding the parameter manually in here.
DxcArguments . Add ( " -enable-16bit-types " ) ;
}
else
{
switch ( InOptions . TargetEnvironment )
{
default :
checkf ( false , TEXT ( " Unexpected SPIR-V target environment: %d " ) , ( uint32 ) InOptions . TargetEnvironment ) ;
case ETargetEnvironment : : Vulkan_1_0 :
DxcArguments . Add ( " -fspv-target-env=vulkan1.0 " ) ;
break ;
case ETargetEnvironment : : Vulkan_1_1 :
DxcArguments . Add ( " -fspv-target-env=vulkan1.1 " ) ;
break ;
case ETargetEnvironment : : Vulkan_1_2 :
DxcArguments . Add ( " -fspv-target-env=vulkan1.2 " ) ;
break ;
case ETargetEnvironment : : Vulkan_1_3 :
DxcArguments . Add ( " -fspv-target-env=vulkan1.3 " ) ;
break ;
}
}
}
2024-02-20 10:23:08 -05:00
static void ConvertScOptions ( FShaderConductorContext : : FShaderConductorIntermediates & Intermediates , const FShaderConductorOptions & InOptions , ShaderConductor : : Compiler : : Options & OutOptions , bool bIgnoreCustomDxcArgs = false , bool bGenerateSpirv = true )
2020-12-08 11:40:10 -04:00
{
2021-10-14 12:05:06 -04:00
// Validate input shader model with respect to certain language features.
checkf (
( ! InOptions . bEnable16bitTypes | | InOptions . ShaderModel > = FHlslShaderModel { 6 , 2 } ) ,
TEXT ( " DXC option '-enable-16bit-types' only supported with SM6.2+ but SM%u.%u was specified " ) ,
InOptions . ShaderModel . Major , InOptions . ShaderModel . Minor
) ;
2020-12-08 11:40:10 -04:00
OutOptions . removeUnusedGlobals = InOptions . bRemoveUnusedGlobals ;
OutOptions . packMatricesInRowMajor = InOptions . bPackMatricesInRowMajor ;
OutOptions . enable16bitTypes = InOptions . bEnable16bitTypes ;
OutOptions . enableDebugInfo = InOptions . bEnableDebugInfo ;
OutOptions . disableOptimizations = InOptions . bDisableOptimizations ;
OutOptions . enableFMAPass = InOptions . bEnableFMAPass ;
2021-10-19 13:00:13 -04:00
OutOptions . enableSeparateSamplers = InOptions . bEnableSeparateSamplersInGlsl ;
2021-12-09 15:02:07 -05:00
OutOptions . remapAttributeLocations = InOptions . bRemapAttributeLocations ;
2021-10-14 12:05:06 -04:00
OutOptions . shaderModel = ShaderConductor : : Compiler : : ShaderModel
2020-12-08 11:40:10 -04:00
{
2021-10-14 12:05:06 -04:00
static_cast < uint8 > ( InOptions . ShaderModel . Major ) ,
static_cast < uint8 > ( InOptions . ShaderModel . Minor )
} ;
2021-02-17 12:29:50 -04:00
2023-09-14 11:39:49 -04:00
TArray < ANSICHAR const * > & DxcArgRefs = Intermediates . DxcArgRefs ;
2021-11-23 14:28:47 -05:00
DxcArgRefs . Empty ( ) ;
2022-03-09 09:47:28 -05:00
2024-02-20 10:23:08 -05:00
AppendDxcArguments ( InOptions , DxcArgRefs , Intermediates . bIsIntermediateCode , bGenerateSpirv ) ;
2023-09-14 11:39:49 -04:00
if ( ! InOptions . SpirvCustomOptimizationPasses . IsEmpty ( ) )
{
2024-01-12 11:06:50 -05:00
Intermediates . InternalDxcArgs = FAnsiString : : Printf ( " -Oconfig=%ls " , SelectSpirvCustomOptimizationPasses ( InOptions . SpirvCustomOptimizationPasses ) ) ;
DxcArgRefs . Add ( * Intermediates . InternalDxcArgs ) ;
2023-09-14 11:39:49 -04:00
}
2021-11-23 14:28:47 -05:00
if ( DxcArgRefs . Num ( ) > 0 )
{
// Use DXC argument container and append custom arguments
2023-09-14 11:39:49 -04:00
if ( ! bIgnoreCustomDxcArgs )
{
DxcArgRefs . Append ( Intermediates . CustomDxcArgRefs ) ;
}
2021-11-23 14:28:47 -05:00
OutOptions . numDXCArgs = DxcArgRefs . Num ( ) ;
OutOptions . DXCArgs = ( const char * * ) DxcArgRefs . GetData ( ) ;
}
2023-09-14 11:39:49 -04:00
else if ( ! bIgnoreCustomDxcArgs )
2021-11-23 14:28:47 -05:00
{
// Use custom DXC arguments only
2023-09-14 11:39:49 -04:00
OutOptions . numDXCArgs = Intermediates . CustomDxcArgRefs . Num ( ) ;
OutOptions . DXCArgs = ( const char * * ) Intermediates . CustomDxcArgRefs . GetData ( ) ;
2021-02-17 12:29:50 -04:00
}
else
{
2021-11-23 14:28:47 -05:00
// No additional DXC arguments
2021-02-17 12:29:50 -04:00
OutOptions . numDXCArgs = 0 ;
OutOptions . DXCArgs = nullptr ;
}
2020-12-08 11:40:10 -04:00
}
// Returns whether the specified line of text contains only these characters, making it a valid line marker from DXC: ' ', '\t', '~', '^'
static bool IsTextLineDxcLineMarker ( const FString & Line )
{
bool bContainsLineMarkerChars = false ;
for ( TCHAR Char : Line )
{
if ( Char = = TCHAR ( ' ~ ' ) | | Char = = TCHAR ( ' ^ ' ) )
{
// Line contains at least one of the necessary characters to be a potential DXC line marker.
bContainsLineMarkerChars = true ;
}
else if ( ! ( Char = = TCHAR ( ' ' ) | | Char = = TCHAR ( ' \t ' ) ) )
{
// Illegal character for a potential DXC line marker.
return false ;
}
}
return bContainsLineMarkerChars ;
}
// Converts the error blob from ShaderConductor into an array of error reports (of type FShaderCompilerError).
static void ConvertScCompileErrors ( ShaderConductor : : Blob & ErrorBlob , TArray < FShaderCompilerError > & OutErrors )
{
// Convert blob into FString
FString ErrorString ;
if ( ConvertScBlobToFString ( & ErrorBlob , ErrorString ) )
{
// Convert FString into array of FString (one for each line)
TArray < FString > ErrorStringLines ;
ErrorString . ParseIntoArray ( ErrorStringLines , TEXT ( " \n " ) ) ;
// Forward parsed array of lines to primary conversion function
FShaderConductorContext : : ConvertCompileErrors ( MoveTemp ( ErrorStringLines ) , OutErrors ) ;
}
}
2023-07-22 06:35:10 -04:00
FShaderConductorTarget : : FShaderConductorTarget ( )
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
CompileFlags = MakePimpl < FShaderCompilerDefinitions > ( ) ;
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
2020-12-08 11:40:10 -04:00
FShaderConductorContext : : FShaderConductorContext ( )
: Intermediates ( new FShaderConductorIntermediates ( ) )
{
}
FShaderConductorContext : : ~ FShaderConductorContext ( )
{
delete Intermediates ;
}
FShaderConductorContext : : FShaderConductorContext ( FShaderConductorContext & & Rhs )
: Errors ( MoveTemp ( Rhs . Errors ) )
, Intermediates ( Rhs . Intermediates )
{
Rhs . Intermediates = nullptr ;
}
FShaderConductorContext & FShaderConductorContext : : operator = ( FShaderConductorContext & & Rhs )
{
Errors = MoveTemp ( Rhs . Errors ) ;
delete Intermediates ;
Intermediates = Rhs . Intermediates ;
Rhs . Intermediates = nullptr ;
return * this ;
}
2023-07-22 06:35:10 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
2023-12-15 15:28:27 -05:00
bool FShaderConductorContext : : LoadSource ( FStringView ShaderSource , const FString & Filename , const FString & EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
2023-07-22 06:35:10 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2020-12-08 11:40:10 -04:00
{
// Convert FString to ANSI string and store them as intermediates
2024-01-12 11:06:50 -05:00
Intermediates - > ShaderSource = ShaderSource ;
Intermediates - > Filename = Filename ;
Intermediates - > EntryPoint = EntryPoint ;
2020-12-08 11:40:10 -04:00
// Convert macro definitions map into an array container
if ( Definitions ! = nullptr )
{
2023-06-21 03:26:02 -04:00
ConvertDefineMapToMacroDefines ( * Definitions , Intermediates - > Defines , Intermediates - > DefineRefs ) ;
2020-12-08 11:40:10 -04:00
}
2021-02-17 12:29:50 -04:00
if ( ExtraDxcArgs & & ExtraDxcArgs - > Num ( ) > 0 )
{
2021-11-23 14:28:47 -05:00
ConvertStringArrayToAnsiArray ( * ExtraDxcArgs , Intermediates - > CustomDxcArgs , Intermediates - > CustomDxcArgRefs ) ;
2021-02-17 12:29:50 -04:00
}
2020-12-08 11:40:10 -04:00
// Convert shader stage
Intermediates - > Stage = ToShaderConductorShaderStage ( ShaderStage ) ;
return true ;
}
2024-01-12 11:06:50 -05:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
bool FShaderConductorContext : : LoadSource ( FAnsiStringView ShaderSource , const FString & Filename , const FString & EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
PRAGMA_ENABLE_DEPRECATION_WARNINGS
{
Intermediates - > ShaderSource = ShaderSource ;
Intermediates - > Filename = Filename ;
Intermediates - > EntryPoint = EntryPoint ;
// Convert macro definitions map into an array container
if ( Definitions ! = nullptr )
{
ConvertDefineMapToMacroDefines ( * Definitions , Intermediates - > Defines , Intermediates - > DefineRefs ) ;
}
if ( ExtraDxcArgs & & ExtraDxcArgs - > Num ( ) > 0 )
{
ConvertStringArrayToAnsiArray ( * ExtraDxcArgs , Intermediates - > CustomDxcArgs , Intermediates - > CustomDxcArgRefs ) ;
}
// Convert shader stage
Intermediates - > Stage = ToShaderConductorShaderStage ( ShaderStage ) ;
return true ;
}
2023-12-15 15:28:27 -05:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
bool FShaderConductorContext : : LoadSource ( const FString & ShaderSource , const FString & Filename , const FString & EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
PRAGMA_ENABLE_DEPRECATION_WARNINGS
{
return LoadSource ( FStringView ( ShaderSource ) , Filename , EntryPoint , ShaderStage , Definitions , ExtraDxcArgs ) ;
}
2023-07-22 06:35:10 -04:00
PRAGMA_DISABLE_DEPRECATION_WARNINGS // FShaderCompilerDefinitions will be made internal in the future, marked deprecated until then
2021-09-02 16:41:03 -04:00
bool FShaderConductorContext : : LoadSource ( const ANSICHAR * ShaderSource , const ANSICHAR * Filename , const ANSICHAR * EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
2023-07-22 06:35:10 -04:00
PRAGMA_ENABLE_DEPRECATION_WARNINGS
2020-12-08 11:40:10 -04:00
{
2024-01-12 11:06:50 -05:00
Intermediates - > ShaderSource = ShaderSource ;
Intermediates - > Filename = Filename ;
Intermediates - > EntryPoint = EntryPoint ;
2020-12-08 11:40:10 -04:00
// Convert macro definitions map into an array container
if ( Definitions ! = nullptr )
{
2023-06-21 03:26:02 -04:00
ConvertDefineMapToMacroDefines ( * Definitions , Intermediates - > Defines , Intermediates - > DefineRefs ) ;
2020-12-08 11:40:10 -04:00
}
2021-02-17 12:29:50 -04:00
if ( ExtraDxcArgs & & ExtraDxcArgs - > Num ( ) > 0 )
{
2021-11-23 14:28:47 -05:00
ConvertStringArrayToAnsiArray ( * ExtraDxcArgs , Intermediates - > CustomDxcArgs , Intermediates - > CustomDxcArgRefs ) ;
2021-02-17 12:29:50 -04:00
}
2020-12-08 11:40:10 -04:00
// Convert shader stage
Intermediates - > Stage = ToShaderConductorShaderStage ( ShaderStage ) ;
return true ;
}
bool FShaderConductorContext : : RewriteHlsl ( const FShaderConductorOptions & Options , FString * OutSource )
{
// Convert descriptors for ShaderConductor interface
ShaderConductor : : Compiler : : SourceDesc ScSourceDesc ;
ConvertScSourceDesc ( * Intermediates , ScSourceDesc ) ;
ShaderConductor : : Compiler : : Options ScOptions ;
2023-09-14 11:39:49 -04:00
constexpr bool bIgnoreExtraDxcArgs = true ;
ConvertScOptions ( * Intermediates , Options , ScOptions , bIgnoreExtraDxcArgs ) ;
2023-06-27 16:32:12 -04:00
2020-12-08 11:40:10 -04:00
// Rewrite HLSL with wrapper function to catch exceptions from ShaderConductor
bool bSucceeded = false ;
ShaderConductor : : Compiler : : ResultDesc ResultDesc ;
2022-10-20 09:43:50 -04:00
ScRewriteWrapper ( ScSourceDesc , ScOptions , ResultDesc ) ;
2020-12-08 11:40:10 -04:00
2024-02-08 18:28:52 -05:00
if ( ! ResultDesc . hasError & & ResultDesc . target . Size ( ) > 1 )
2020-12-08 11:40:10 -04:00
{
2024-02-08 18:28:52 -05:00
// Note: We don't want to include the '\0' included in the result string (thanks to DxcCreateBlob), hence the -1
check ( reinterpret_cast < const ANSICHAR * > ( ResultDesc . target . Data ( ) ) [ ResultDesc . target . Size ( ) - 1 ] = = ' \0 ' ) ;
FAnsiStringView ResultView ( reinterpret_cast < const ANSICHAR * > ( ResultDesc . target . Data ( ) ) , ResultDesc . target . Size ( ) - 1 ) ;
2020-12-08 11:40:10 -04:00
// Copy rewritten HLSL code into intermediate source code.
2024-01-12 11:06:50 -05:00
Intermediates - > ShaderSource . CopyAnsi ( ResultView ) ;
2020-12-08 11:40:10 -04:00
2024-02-20 10:23:08 -05:00
// Mark the internal shader source as intermediate code
Intermediates - > bIsIntermediateCode = true ;
2020-12-08 11:40:10 -04:00
// If output source is specified, also convert to TCHAR string
if ( OutSource ! = nullptr )
{
2024-01-12 11:06:50 -05:00
OutSource - > Empty ( ) ;
OutSource - > Append ( ResultView ) ;
2020-12-08 11:40:10 -04:00
}
bSucceeded = true ;
}
// Append compile error and warning to output reports
ConvertScCompileErrors ( ResultDesc . errorWarningMsg , Errors ) ;
return bSucceeded ;
}
2024-02-15 13:52:17 -05:00
bool FShaderConductorContext : : CompileHlslToDxil ( const FShaderConductorOptions & Options , TArray < uint32 > & OutDxil )
{
constexpr bool bGenerateSpirv = false ;
// Convert descriptors for ShaderConductor interface
ShaderConductor : : Compiler : : SourceDesc ScSourceDesc ;
ConvertScSourceDesc ( * Intermediates , ScSourceDesc ) ;
ShaderConductor : : Compiler : : TargetDesc ScTargetDesc ;
FMemory : : Memzero ( ScTargetDesc ) ;
ScTargetDesc . language = ShaderConductor : : ShadingLanguage : : Dxil ;
ShaderConductor : : Compiler : : Options ScOptions ;
ConvertScOptions ( * Intermediates , Options , ScOptions , false , bGenerateSpirv ) ;
// Force PDB generation (required to generate DXIL reflection).
ScOptions . enableDebugInfo = true ;
// Compile HLSL source code to DXIL
bool bSucceeded = false ;
ShaderConductor : : Compiler : : ResultDesc ResultDesc ;
ScCompileWrapper ( ScSourceDesc , ScOptions , ScTargetDesc , ResultDesc ) ;
if ( ! ResultDesc . hasError & & ResultDesc . target . Size ( ) > 0 )
{
// Copy result blob into output DXIL module
OutDxil = TArray < uint32 > ( reinterpret_cast < const uint32 * > ( ResultDesc . target . Data ( ) ) , ResultDesc . target . Size ( ) / 4 ) ;
bSucceeded = true ;
}
else
{
bSucceeded = false ;
}
// Append compile error and warning to output reports
ConvertScCompileErrors ( ResultDesc . errorWarningMsg , Errors ) ;
return bSucceeded ;
}
2020-12-08 11:40:10 -04:00
bool FShaderConductorContext : : CompileHlslToSpirv ( const FShaderConductorOptions & Options , TArray < uint32 > & OutSpirv )
{
// Convert descriptors for ShaderConductor interface
ShaderConductor : : Compiler : : SourceDesc ScSourceDesc ;
ConvertScSourceDesc ( * Intermediates , ScSourceDesc ) ;
ShaderConductor : : Compiler : : TargetDesc ScTargetDesc ;
FMemory : : Memzero ( ScTargetDesc ) ;
ScTargetDesc . language = ShaderConductor : : ShadingLanguage : : SpirV ;
ShaderConductor : : Compiler : : Options ScOptions ;
2023-09-14 11:39:49 -04:00
ConvertScOptions ( * Intermediates , Options , ScOptions ) ;
2020-12-08 11:40:10 -04:00
// Compile HLSL source code to SPIR-V
bool bSucceeded = false ;
ShaderConductor : : Compiler : : ResultDesc ResultDesc ;
2022-10-20 09:43:50 -04:00
ScCompileWrapper ( ScSourceDesc , ScOptions , ScTargetDesc , ResultDesc ) ;
2020-12-08 11:40:10 -04:00
2022-10-20 09:43:50 -04:00
if ( ! ResultDesc . hasError & & ResultDesc . target . Size ( ) > 0 )
2020-12-08 11:40:10 -04:00
{
// Copy result blob into output SPIR-V module
OutSpirv = TArray < uint32 > ( reinterpret_cast < const uint32 * > ( ResultDesc . target . Data ( ) ) , ResultDesc . target . Size ( ) / 4 ) ;
bSucceeded = true ;
}
2022-10-20 09:43:50 -04:00
2020-12-08 11:40:10 -04:00
// Append compile error and warning to output reports
ConvertScCompileErrors ( ResultDesc . errorWarningMsg , Errors ) ;
return bSucceeded ;
}
2021-03-29 09:45:48 -04:00
bool FShaderConductorContext : : OptimizeSpirv ( TArray < uint32 > & Spirv , const ANSICHAR * const * OptConfigs , int32 OptConfigCount )
{
// Ignore this call if no optimization configurations were specified
if ( OptConfigCount > 0 )
{
check ( OptConfigs ! = nullptr ) ;
// Convert input SPIR-V module to Blob instance for ShaderConductor interface
ShaderConductor : : Compiler : : ResultDesc SpirvInput ;
SpirvInput . target = ShaderConductor : : Blob ( Spirv . GetData ( ) , Spirv . Num ( ) * sizeof ( uint32 ) ) ;
SpirvInput . isText = false ;
SpirvInput . hasError = false ;
// Run optimization passes through ShaderConductor
ShaderConductor : : Compiler : : ResultDesc SpirvOutput = ShaderConductor : : Compiler : : Optimize ( SpirvInput , OptConfigs , static_cast < uint32_t > ( OptConfigCount ) ) ;
if ( ! SpirvOutput . hasError & & SpirvOutput . target . Size ( ) > 0 )
{
// Convert Blob instance back to our SPIR-V module
Spirv = TArray < uint32 > ( reinterpret_cast < const uint32 * > ( SpirvOutput . target . Data ( ) ) , SpirvOutput . target . Size ( ) / 4 ) ;
}
else
{
// Extract errors
if ( SpirvOutput . errorWarningMsg . Size ( ) > 0 )
{
FString ErrorString ;
if ( ConvertScBlobToFString ( & SpirvOutput . errorWarningMsg , ErrorString ) )
{
Errors . Add ( * ErrorString ) ;
}
}
return false ;
}
}
return true ;
}
2020-12-08 11:40:10 -04:00
bool FShaderConductorContext : : CompileSpirvToSource ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , FString & OutSource )
{
return CompileSpirvToSourceBuffer (
Options , Target , InSpirv , InSpirvByteSize ,
[ & OutSource ] ( const void * Data , uint32 Size )
{
// Convert source buffer to FString
2024-01-12 11:06:50 -05:00
FString Converted ( reinterpret_cast < const ANSICHAR * > ( Data ) , Size ) ;
OutSource = MoveTemp ( Converted ) ;
2020-12-08 11:40:10 -04:00
}
) ;
}
bool FShaderConductorContext : : CompileSpirvToSourceAnsi ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , TArray < ANSICHAR > & OutSource )
{
return CompileSpirvToSourceBuffer (
Options , Target , InSpirv , InSpirvByteSize ,
[ & OutSource ] ( const void * Data , uint32 Size )
{
// Convert source buffer to ANSI string
2024-01-12 11:06:50 -05:00
FAnsiString Copy = FAnsiString : : ConstructFromPtrSize ( reinterpret_cast < const ANSICHAR * > ( Data ) , Size ) ;
OutSource = MoveTemp ( Copy . GetCharArray ( ) ) ;
2020-12-08 11:40:10 -04:00
}
) ;
}
bool FShaderConductorContext : : CompileSpirvToSourceBuffer ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , const TFunction < void ( const void * Data , uint32 Size ) > & OutputCallback )
{
check ( OutputCallback ! = nullptr ) ;
check ( InSpirv ! = nullptr ) ;
check ( InSpirvByteSize > 0 ) ;
checkf ( InSpirvByteSize % 4 = = 0 , TEXT ( " SPIR-V code unaligned. Size must be a multiple of 4, but %u was specified. " ) , InSpirvByteSize ) ;
// Convert descriptors for ShaderConductor interface
ShaderConductor : : Compiler : : SourceDesc ScSourceDesc ;
ConvertScSourceDesc ( * Intermediates , ScSourceDesc ) ;
ShaderConductor : : Compiler : : TargetDesc ScTargetDesc ;
ConvertScTargetDesc ( * Intermediates , Target , ScTargetDesc ) ;
ShaderConductor : : Compiler : : Options ScOptions ;
2023-09-14 11:39:49 -04:00
ConvertScOptions ( * Intermediates , Options , ScOptions ) ;
2020-12-08 11:40:10 -04:00
ShaderConductor : : Compiler : : ResultDesc ScBinaryDesc ;
ScBinaryDesc . target . Reset ( InSpirv , InSpirvByteSize ) ;
ScBinaryDesc . isText = false ;
ScBinaryDesc . hasError = false ;
// Convert the input SPIR-V into Metal high level source
bool bSucceeded = false ;
ShaderConductor : : Compiler : : ResultDesc ResultDesc ;
2022-10-20 09:43:50 -04:00
ScConvertBinaryWrapper ( ScBinaryDesc , ScSourceDesc , ScTargetDesc , ScOptions , ResultDesc ) ;
2020-12-08 11:40:10 -04:00
2022-10-20 09:43:50 -04:00
if ( ! ResultDesc . hasError & & ResultDesc . target . Size ( ) > 0 )
2020-12-08 11:40:10 -04:00
{
// Copy result blob into output SPIR-V module
OutputCallback ( ResultDesc . target . Data ( ) , ResultDesc . target . Size ( ) ) ;
bSucceeded = true ;
}
2022-10-20 09:43:50 -04:00
2020-12-08 11:40:10 -04:00
// Append compile error and warning to output reports
if ( ResultDesc . errorWarningMsg . Size ( ) > 0 )
{
FString ErrorString ;
if ( ConvertScBlobToFString ( & ResultDesc . errorWarningMsg , ErrorString ) )
{
Errors . Add ( * ErrorString ) ;
}
}
return bSucceeded ;
}
void FShaderConductorContext : : FlushErrors ( TArray < FShaderCompilerError > & OutErrors )
{
if ( OutErrors . Num ( ) > 0 )
{
// Append internal list of errors to output list, then clear internal list
for ( const FShaderCompilerError & ErrorEntry : Errors )
{
OutErrors . Add ( ErrorEntry ) ;
}
Errors . Empty ( ) ;
}
else
{
// Move internal list of errors into output list
OutErrors = MoveTemp ( Errors ) ;
}
}
const ANSICHAR * FShaderConductorContext : : GetSourceString ( ) const
{
2024-01-12 11:06:50 -05:00
return ( Intermediates - > ShaderSource . AnsiView . Len ( ) > 0 ? Intermediates - > ShaderSource . AnsiView . GetData ( ) : nullptr ) ;
2020-12-08 11:40:10 -04:00
}
int32 FShaderConductorContext : : GetSourceLength ( ) const
{
2024-01-12 11:06:50 -05:00
return Intermediates - > ShaderSource . AnsiView . Len ( ) ;
2020-12-08 11:40:10 -04:00
}
2023-11-08 14:23:36 -05:00
static const TCHAR * GetHlslShaderModelProfile ( ShaderConductor : : ShaderStage Stage )
{
switch ( Stage )
{
case ShaderConductor : : ShaderStage : : VertexShader : return TEXT ( " vs " ) ;
case ShaderConductor : : ShaderStage : : PixelShader : return TEXT ( " ps " ) ;
case ShaderConductor : : ShaderStage : : GeometryShader : return TEXT ( " gs " ) ;
case ShaderConductor : : ShaderStage : : HullShader : return TEXT ( " hl " ) ;
case ShaderConductor : : ShaderStage : : DomainShader : return TEXT ( " ds " ) ;
case ShaderConductor : : ShaderStage : : ComputeShader : return TEXT ( " cs " ) ;
default : return TEXT ( " lib " ) ;
}
}
FString FShaderConductorContext : : GenerateDxcArguments ( const FShaderConductorOptions & Options ) const
{
FString CmdLineArgs = FString : : Printf (
2024-01-12 11:06:50 -05:00
TEXT ( " -E %hs -T %s_%d_%d " ) ,
Intermediates - > EntryPoint . AnsiView . GetData ( ) , GetHlslShaderModelProfile ( Intermediates - > Stage ) , ( int32 ) Options . ShaderModel . Major , ( int32 ) Options . ShaderModel . Minor
2023-11-08 14:23:36 -05:00
) ;
TArray < const ANSICHAR * > DxcArguments ;
AppendDxcArguments ( Options , DxcArguments ) ;
for ( const ANSICHAR * Argument : DxcArguments )
{
CmdLineArgs + = TEXT ( " " ) ;
CmdLineArgs + = ANSI_TO_TCHAR ( Argument ) ;
}
return CmdLineArgs ;
}
2020-12-08 11:40:10 -04:00
void FShaderConductorContext : : ConvertCompileErrors ( TArray < FString > & & ErrorStringLines , TArray < FShaderCompilerError > & OutErrors )
{
// Returns whether the specified line in the 'ErrorStringLines' array has a line marker.
auto HasErrorLineMarker = [ & ErrorStringLines ] ( int32 LineIndex )
{
if ( LineIndex + 2 < ErrorStringLines . Num ( ) )
{
return IsTextLineDxcLineMarker ( ErrorStringLines [ LineIndex + 2 ] ) ;
}
return false ;
} ;
// Iterate over all errors. Most (but not all) contain a highlighted line and line marker.
for ( int32 LineIndex = 0 ; LineIndex < ErrorStringLines . Num ( ) ; )
{
if ( HasErrorLineMarker ( LineIndex ) )
{
// Add current line as error with highlighted source line (LineIndex+1) and line marker (LineIndex+2)
OutErrors . Emplace ( MoveTemp ( ErrorStringLines [ LineIndex ] ) , MoveTemp ( ErrorStringLines [ LineIndex + 1 ] ) , MoveTemp ( ErrorStringLines [ LineIndex + 2 ] ) ) ;
LineIndex + = 3 ;
}
else
{
// Add current line as single error
OutErrors . Emplace ( MoveTemp ( ErrorStringLines [ LineIndex ] ) ) ;
LineIndex + = 1 ;
}
}
}
2021-04-26 17:13:29 -04:00
bool FShaderConductorContext : : Disassemble ( EShaderConductorIR Language , const void * Binary , uint32 BinaryByteSize , TArray < ANSICHAR > & OutAssemblyText )
2021-04-12 11:25:06 -04:00
{
// Initialize Blob with input SPIR-V code
2021-04-26 17:13:29 -04:00
ShaderConductor : : Compiler : : DisassembleDesc BinaryDesc ;
switch ( Language )
{
case EShaderConductorIR : : Spirv :
BinaryDesc . language = ShaderConductor : : ShadingLanguage : : SpirV ;
break ;
case EShaderConductorIR : : Dxil :
BinaryDesc . language = ShaderConductor : : ShadingLanguage : : Dxil ;
break ;
}
BinaryDesc . binary = reinterpret_cast < const uint8_t * > ( Binary ) ;
BinaryDesc . binarySize = BinaryByteSize ;
2021-04-12 11:25:06 -04:00
// Disassemble via ShaderConductor interface
2021-04-26 17:13:29 -04:00
ShaderConductor : : Compiler : : ResultDesc TextOutput = ShaderConductor : : Compiler : : Disassemble ( BinaryDesc ) ;
2021-04-12 11:25:06 -04:00
if ( TextOutput . isText & & ! TextOutput . hasError )
{
// Convert and return output to ANSI string
2024-01-12 11:06:50 -05:00
FAnsiString Copy = FAnsiString : : ConstructFromPtrSize ( reinterpret_cast < const ANSICHAR * > ( TextOutput . target . Data ( ) ) , TextOutput . target . Size ( ) ) ;
OutAssemblyText = MoveTemp ( Copy . GetCharArray ( ) ) ;
2021-04-12 11:25:06 -04:00
return true ;
}
2021-04-26 17:13:29 -04:00
2021-04-12 11:25:06 -04:00
return false ;
}
2020-12-08 11:40:10 -04:00
# else // PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
FShaderConductorContext : : FShaderConductorContext ( )
{
checkf ( 0 , TEXT ( " Cannot instantiate FShaderConductorContext for unsupported platform " ) ) ;
}
FShaderConductorContext : : ~ FShaderConductorContext ( )
{
// Dummy
}
FShaderConductorContext : : FShaderConductorContext ( FShaderConductorContext & & Rhs )
{
// Dummy
}
FShaderConductorContext & FShaderConductorContext : : operator = ( FShaderConductorContext & & Rhs )
{
return * this ; // Dummy
}
2021-09-02 16:41:03 -04:00
bool FShaderConductorContext : : LoadSource ( const FString & ShaderSource , const FString & Filename , const FString & EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
2020-12-08 11:40:10 -04:00
{
return false ; // Dummy
2023-12-15 15:28:27 -05:00
}
bool FShaderConductorContext : : LoadSource ( FStringView ShaderSource , const FString & Filename , const FString & EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
{
return false ; // Dummy
2020-12-08 11:40:10 -04:00
}
2021-09-02 16:41:03 -04:00
bool FShaderConductorContext : : LoadSource ( const ANSICHAR * ShaderSource , const ANSICHAR * Filename , const ANSICHAR * EntryPoint , EShaderFrequency ShaderStage , const FShaderCompilerDefinitions * Definitions , const TArray < FString > * ExtraDxcArgs )
2020-12-08 11:40:10 -04:00
{
return false ; // Dummy
}
bool FShaderConductorContext : : RewriteHlsl ( const FShaderConductorOptions & Options , FString * OutSource )
{
return false ; // Dummy
}
2024-02-15 13:52:17 -05:00
bool FShaderConductorContext : : CompileHlslToDxil ( const FShaderConductorOptions & Options , TArray < uint32 > & OutDxil )
{
return false ; // Dummy
}
2020-12-08 11:40:10 -04:00
bool FShaderConductorContext : : CompileHlslToSpirv ( const FShaderConductorOptions & Options , TArray < uint32 > & OutSpirv )
{
return false ; // Dummy
}
bool FShaderConductorContext : : CompileSpirvToSource ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , FString & OutSource )
{
return false ; // Dummy
}
bool FShaderConductorContext : : CompileSpirvToSourceAnsi ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , TArray < ANSICHAR > & OutSource )
{
return false ; // Dummy
}
bool FShaderConductorContext : : CompileSpirvToSourceBuffer ( const FShaderConductorOptions & Options , const FShaderConductorTarget & Target , const void * InSpirv , uint32 InSpirvByteSize , const TFunction < void ( const void * Data , uint32 Size ) > & OutputCallback )
{
return false ; // Dummy
}
void FShaderConductorContext : : FlushErrors ( TArray < FShaderCompilerError > & OutErrors )
{
// Dummy
}
const ANSICHAR * FShaderConductorContext : : GetSourceString ( ) const
{
return nullptr ; // Dummy
}
int32 FShaderConductorContext : : GetSourceLength ( ) const
{
return 0 ; // Dummy
}
void FShaderConductorContext : : ConvertCompileErrors ( const TArray < FString > & ErrorStringLines , TArray < FShaderCompilerError > & OutErrors )
{
// Dummy
}
2021-04-26 17:13:29 -04:00
bool FShaderConductorContext : : Disassemble ( EShaderConductorIR Language , const void * Binary , uint32 BinaryByteSize , TArray < ANSICHAR > & OutAssemblyText )
2021-04-12 11:25:06 -04:00
{
return false ; // Dummy
}
2020-12-08 11:40:10 -04:00
# endif // PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
bool FShaderConductorContext : : IsIntermediateSpirvOutputVariable ( const ANSICHAR * SpirvVariableName )
{
// This is only true for "temp.var.hullMainRetVal" which is generated by DXC as intermediate output variable to communicate patch constant data in a Hull Shader.
2021-04-08 10:09:56 -04:00
return ( SpirvVariableName ! = nullptr & & FCStringAnsi : : Strcmp ( SpirvVariableName , FShaderConductorContext : : GetIdentifierTable ( ) . IntermediateTessControlOutput ) = = 0 ) ;
}
const FShaderConductorIdentifierTable & FShaderConductorContext : : GetIdentifierTable ( )
{
static const FShaderConductorIdentifierTable IdentifierTable
{
/*InputAttribute:*/ " in.var.ATTRIBUTE " ,
/*GlobalsUniformBuffer:*/ " $Globals " ,
/*IntermediateTessControlOutput:*/ " temp.var.hullMainRetVal " ,
2021-10-12 10:42:28 -04:00
/*DummySampler:*/ " SPIRV_Cross_DummySampler " ,
2021-04-08 10:09:56 -04:00
} ;
return IdentifierTable ;
2020-12-08 11:40:10 -04:00
}
2021-09-02 16:41:03 -04:00
static const TCHAR * GetGlslShaderFileExt ( EShaderFrequency ShaderStage )
2021-08-26 10:22:08 -04:00
{
2021-09-02 16:41:03 -04:00
switch ( ShaderStage )
2021-08-26 10:22:08 -04:00
{
2021-09-02 16:41:03 -04:00
case SF_Vertex : return TEXT ( " vert " ) ;
case SF_Mesh : return TEXT ( " mesh " ) ;
case SF_Amplification : return TEXT ( " task " ) ;
case SF_Pixel : return TEXT ( " frag " ) ;
case SF_Geometry : return TEXT ( " geom " ) ;
case SF_Compute : return TEXT ( " comp " ) ;
case SF_RayGen : return TEXT ( " rgen " ) ;
case SF_RayMiss : return TEXT ( " rmiss " ) ;
case SF_RayHitGroup : return TEXT ( " rahit " ) ; // rahit/rchit
case SF_RayCallable : return TEXT ( " rcall " ) ;
default : return TEXT ( " glsl " ) ;
}
}
const TCHAR * FShaderConductorContext : : GetShaderFileExt ( EShaderConductorLanguage Language , EShaderFrequency ShaderStage )
{
switch ( Language )
{
case EShaderConductorLanguage : : Hlsl : return TEXT ( " hlsl " ) ;
case EShaderConductorLanguage : : Glsl : [[fallthrough]] ;
case EShaderConductorLanguage : : Essl : return GetGlslShaderFileExt ( ShaderStage ) ;
case EShaderConductorLanguage : : Metal_macOS : [[fallthrough]] ;
case EShaderConductorLanguage : : Metal_iOS : return TEXT ( " metal " ) ;
default : return TEXT ( " " ) ;
}
2021-08-26 10:22:08 -04:00
}
2021-11-07 23:43:01 -05:00
void FShaderConductorContext : : Shutdown ( )
{
# if PLATFORM_LINUX
ShaderConductor : : Compiler : : Shutdown ( ) ;
# endif
}
2020-12-08 11:40:10 -04:00
} // namespace CrossCompiler