2020-06-23 18:40:00 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "ShaderFormatD3D.h"
# include "ShaderPreprocessor.h"
# include "ShaderCompilerCommon.h"
# include "D3D11ShaderResources.h"
# include "D3D12RHI.h"
# include "Misc/Paths.h"
# include "Misc/FileHelper.h"
# include "HAL/FileManager.h"
# include "Serialization/MemoryWriter.h"
# include "RayTracingDefinitions.h"
DEFINE_LOG_CATEGORY_STATIC ( LogD3D12ShaderCompiler , Log , All ) ;
// D3D doesn't define a mask for this, so we do so here
2020-09-25 12:21:25 -04:00
# define SHADER_OPTIMIZATION_LEVEL_MASK (D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_OPTIMIZATION_LEVEL1 | D3DCOMPILE_OPTIMIZATION_LEVEL2 | D3DCOMPILE_OPTIMIZATION_LEVEL3)
2020-06-23 18:40:00 -04:00
// Disable macro redefinition warning for compatibility with Windows SDK 8+
# pragma warning(push)
# pragma warning(disable : 4005) // macro redefinition
# include "Windows/AllowWindowsPlatformTypes.h"
# include <D3D11.h>
# include <D3Dcompiler.h>
# include <d3d11Shader.h>
2020-07-06 18:58:26 -04:00
# include "amd_ags.h"
2020-06-23 18:40:00 -04:00
# include "Windows/HideWindowsPlatformTypes.h"
# undef DrawText
# pragma warning(pop)
MSVC_PRAGMA ( warning ( push ) )
MSVC_PRAGMA ( warning ( disable : 4191 ) ) // warning C4191: 'type cast': unsafe conversion from 'FARPROC' to 'DxcCreateInstanceProc'
# include <dxc/dxcapi.h>
# include <dxc/Support/dxcapi.use.h>
# include <d3d12shader.h>
MSVC_PRAGMA ( warning ( pop ) )
THIRD_PARTY_INCLUDES_START
# include <string>
# include "ShaderConductor/ShaderConductor.hpp"
THIRD_PARTY_INCLUDES_END
# include "D3DShaderCompiler.inl"
FORCENOINLINE static void DXCFilterShaderCompileWarnings ( const FString & CompileWarnings , TArray < FString > & FilteredWarnings )
{
CompileWarnings . ParseIntoArray ( FilteredWarnings , TEXT ( " \n " ) , true ) ;
}
static bool IsGlobalConstantBufferSupported ( const FShaderTarget & Target )
{
switch ( Target . Frequency )
{
case SF_RayGen :
case SF_RayMiss :
case SF_RayCallable :
// Global CB is not currently implemented for RayGen, Miss and Callable ray tracing shaders.
return false ;
default :
return true ;
}
}
static uint32 GetAutoBindingSpace ( const FShaderTarget & Target )
{
switch ( Target . Frequency )
{
case SF_RayGen :
return RAY_TRACING_REGISTER_SPACE_GLOBAL ;
case SF_RayMiss :
case SF_RayHitGroup :
case SF_RayCallable :
return RAY_TRACING_REGISTER_SPACE_LOCAL ;
default :
return 0 ;
}
}
// Utility variable so we can place a breakpoint while debugging
static int32 GBreakpointDXC = 0 ;
# define VERIFYHRESULT(expr) { HRESULT HR##__LINE__ = expr; if (FAILED(HR##__LINE__)) { UE_LOG(LogD3D12ShaderCompiler, Fatal, TEXT(#expr " failed: Result=%08x"), HR##__LINE__); } }
static dxc : : DxcDllSupport & GetDxcDllHelper ( )
{
static dxc : : DxcDllSupport DxcDllSupport ;
static bool DxcDllInitialized = false ;
if ( ! DxcDllInitialized )
{
VERIFYHRESULT ( DxcDllSupport . Initialize ( ) ) ;
DxcDllInitialized = true ;
}
return DxcDllSupport ;
}
static FString DxcBlobEncodingToFString ( TRefCountPtr < IDxcBlobEncoding > DxcBlob )
{
FString OutString ;
if ( DxcBlob & & DxcBlob - > GetBufferSize ( ) )
{
ANSICHAR * Chars = new ANSICHAR [ DxcBlob - > GetBufferSize ( ) + 1 ] ;
FMemory : : Memcpy ( Chars , DxcBlob - > GetBufferPointer ( ) , DxcBlob - > GetBufferSize ( ) ) ;
Chars [ DxcBlob - > GetBufferSize ( ) ] = 0 ;
OutString = Chars ;
delete [ ] Chars ;
}
return OutString ;
}
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED && PLATFORM_WINDOWS
# include "Windows/WindowsPlatformCrashContext.h"
# include "HAL/PlatformStackWalk.h"
static char GDxcStackTrace [ 65536 ] = " " ;
static int32 HandleException ( LPEXCEPTION_POINTERS ExceptionInfo )
{
constexpr int32 NumStackFramesToIgnore = 1 ;
GDxcStackTrace [ 0 ] = 0 ;
FPlatformStackWalk : : StackWalkAndDump ( GDxcStackTrace , UE_ARRAY_COUNT ( GDxcStackTrace ) , NumStackFramesToIgnore , nullptr ) ;
return EXCEPTION_EXECUTE_HANDLER ;
}
# else
static const char * GDxcStackTrace = " " ;
# endif
static HRESULT InnerDXCCompileWrapper (
TRefCountPtr < IDxcCompiler3 > & Compiler ,
TRefCountPtr < IDxcBlobEncoding > & TextBlob ,
LPCWSTR * Arguments ,
uint32 NumArguments ,
bool & bOutExceptionError ,
TRefCountPtr < IDxcResult > & OutCompileResult )
{
bOutExceptionError = false ;
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED && PLATFORM_WINDOWS
__try
# endif
{
DxcBuffer SourceBuffer = { 0 } ;
SourceBuffer . Ptr = TextBlob - > GetBufferPointer ( ) ;
SourceBuffer . Size = TextBlob - > GetBufferSize ( ) ;
BOOL bKnown = 0 ;
uint32 Encoding = 0 ;
if ( SUCCEEDED ( TextBlob - > GetEncoding ( & bKnown , ( uint32 * ) & Encoding ) ) )
{
if ( bKnown )
{
SourceBuffer . Encoding = Encoding ;
}
}
return Compiler - > Compile (
& SourceBuffer , // source text to compile
Arguments , // array of pointers to arguments
NumArguments , // number of arguments
nullptr , // user-provided interface to handle #include directives (optional)
IID_PPV_ARGS ( OutCompileResult . GetInitReference ( ) ) // compiler output status, buffer, and errors
) ;
}
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED && PLATFORM_WINDOWS
__except ( HandleException ( GetExceptionInformation ( ) ) )
{
bOutExceptionError = true ;
return E_FAIL ;
}
# endif
}
static HRESULT DXCCompileWrapper (
TRefCountPtr < IDxcCompiler3 > & Compiler ,
TRefCountPtr < IDxcBlobEncoding > & TextBlob ,
FDxcArguments & Arguments ,
TRefCountPtr < IDxcResult > & OutCompileResult )
{
bool bExceptionError = false ;
TArray < const WCHAR * > CompilerArgs ;
Arguments . GetCompilerArgs ( CompilerArgs ) ;
HRESULT Result = InnerDXCCompileWrapper ( Compiler , TextBlob ,
CompilerArgs . GetData ( ) , CompilerArgs . Num ( ) , bExceptionError , OutCompileResult ) ;
if ( bExceptionError )
{
GSCWErrorCode = ESCWErrorCode : : CrashInsidePlatformCompiler ;
FString ErrorMsg = TEXT ( " Internal error or exception inside dxcompiler.dll \n " ) ;
ErrorMsg + = GDxcStackTrace ;
FCString : : Strcpy ( GErrorExceptionDescription , * ErrorMsg ) ;
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED && PLATFORM_WINDOWS
// Throw an exception so SCW can send it back in the output file
FPlatformMisc : : RaiseException ( EXCEPTION_EXECUTE_HANDLER ) ;
# endif
}
return Result ;
}
static void SaveDxcBlobToFile ( IDxcBlob * Blob , const FString & Filename )
{
const uint8 * DxilData = ( const uint8 * ) Blob - > GetBufferPointer ( ) ;
uint32 DxilSize = Blob - > GetBufferSize ( ) ;
TArrayView < const uint8 > Contents ( DxilData , DxilSize ) ;
FFileHelper : : SaveArrayToFile ( Contents , * Filename ) ;
}
static void DisassembleAndSave ( TRefCountPtr < IDxcCompiler3 > & Compiler , IDxcBlob * Dxil , const FString & DisasmFilename )
{
TRefCountPtr < IDxcResult > DisasmResult ;
DxcBuffer DisasmBuffer = { 0 } ;
DisasmBuffer . Size = Dxil - > GetBufferSize ( ) ;
DisasmBuffer . Ptr = Dxil - > GetBufferPointer ( ) ;
if ( SUCCEEDED ( Compiler - > Disassemble ( & DisasmBuffer , IID_PPV_ARGS ( DisasmResult . GetInitReference ( ) ) ) ) )
{
HRESULT DisasmCodeResult ;
DisasmResult - > GetStatus ( & DisasmCodeResult ) ;
if ( SUCCEEDED ( DisasmCodeResult ) )
{
checkf ( DisasmResult - > HasOutput ( DXC_OUT_DISASSEMBLY ) , TEXT ( " Disasm part missing but container said it has one! " ) ) ;
TRefCountPtr < IDxcBlobEncoding > DisasmBlob ;
TRefCountPtr < IDxcBlobUtf16 > Dummy ;
VERIFYHRESULT ( DisasmResult - > GetOutput ( DXC_OUT_DISASSEMBLY , IID_PPV_ARGS ( DisasmBlob . GetInitReference ( ) ) , Dummy . GetInitReference ( ) ) ) ;
FString String = DxcBlobEncodingToFString ( DisasmBlob ) ;
FFileHelper : : SaveStringToFile ( String , * DisasmFilename ) ;
}
}
}
static void DumpFourCCParts ( dxc : : DxcDllSupport & DxcDllHelper , TRefCountPtr < IDxcBlob > & Blob )
{
# if UE_BUILD_DEBUG && IS_PROGRAM
TRefCountPtr < IDxcContainerReflection > Refl ;
VERIFYHRESULT ( DxcDllHelper . CreateInstance ( CLSID_DxcContainerReflection , Refl . GetInitReference ( ) ) ) ;
VERIFYHRESULT ( Refl - > Load ( Blob ) ) ;
uint32 Count = 0 ;
VERIFYHRESULT ( Refl - > GetPartCount ( & Count ) ) ;
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " *** Blob Size: %d, %d Parts \n " ) , Blob - > GetBufferSize ( ) , Count ) ;
for ( uint32 Index = 0 ; Index < Count ; + + Index )
{
char FourCC [ 5 ] = " \0 \0 \0 \0 " ;
VERIFYHRESULT ( Refl - > GetPartKind ( Index , ( uint32 * ) FourCC ) ) ;
TRefCountPtr < IDxcBlob > Part ;
Refl - > GetPartContent ( Index , Part . GetInitReference ( ) ) ;
FPlatformMisc : : LowLevelOutputDebugStringf ( TEXT ( " * %d %s, Size %d \n " ) , Index , ANSI_TO_TCHAR ( FourCC ) , ( uint32 ) Part - > GetBufferSize ( ) ) ;
}
# endif
}
2021-09-29 15:13:20 -04:00
static bool RemoveContainerReflection ( dxc : : DxcDllSupport & DxcDllHelper , TRefCountPtr < IDxcBlob > & Dxil , bool bRemovePDB )
2020-06-23 18:40:00 -04:00
{
TRefCountPtr < IDxcOperationResult > Result ;
TRefCountPtr < IDxcContainerBuilder > Builder ;
TRefCountPtr < IDxcBlob > StrippedDxil ;
VERIFYHRESULT ( DxcDllHelper . CreateInstance ( CLSID_DxcContainerBuilder , Builder . GetInitReference ( ) ) ) ;
VERIFYHRESULT ( Builder - > Load ( Dxil ) ) ;
2020-09-01 14:07:48 -04:00
// Try and remove both the PDB & Reflection Data
2021-09-29 15:13:20 -04:00
bool bPDBRemoved = bRemovePDB & & SUCCEEDED ( Builder - > RemovePart ( DXC_PART_PDB ) ) ;
2022-05-27 17:56:55 -04:00
bool bReflectionDataRemoved = bRemovePDB & & SUCCEEDED ( Builder - > RemovePart ( DXC_PART_REFLECTION_DATA ) ) ;
2020-09-01 14:07:48 -04:00
if ( bPDBRemoved | | bReflectionDataRemoved )
2020-06-23 18:40:00 -04:00
{
VERIFYHRESULT ( Builder - > SerializeContainer ( Result . GetInitReference ( ) ) ) ;
if ( SUCCEEDED ( Result - > GetResult ( StrippedDxil . GetInitReference ( ) ) ) )
{
Dxil . SafeRelease ( ) ;
Dxil = StrippedDxil ;
return true ;
}
}
return false ;
} ;
static HRESULT D3DCompileToDxil ( const char * SourceText , FDxcArguments & Arguments ,
TRefCountPtr < IDxcBlob > & OutDxilBlob , TRefCountPtr < IDxcBlob > & OutReflectionBlob , TRefCountPtr < IDxcBlobEncoding > & OutErrorBlob )
{
dxc : : DxcDllSupport & DxcDllHelper = GetDxcDllHelper ( ) ;
TRefCountPtr < IDxcCompiler3 > Compiler ;
VERIFYHRESULT ( DxcDllHelper . CreateInstance ( CLSID_DxcCompiler , Compiler . GetInitReference ( ) ) ) ;
TRefCountPtr < IDxcLibrary > Library ;
VERIFYHRESULT ( DxcDllHelper . CreateInstance ( CLSID_DxcLibrary , Library . GetInitReference ( ) ) ) ;
TRefCountPtr < IDxcBlobEncoding > TextBlob ;
VERIFYHRESULT ( Library - > CreateBlobWithEncodingFromPinned ( ( LPBYTE ) SourceText , FCStringAnsi : : Strlen ( SourceText ) , CP_UTF8 , TextBlob . GetInitReference ( ) ) ) ;
TRefCountPtr < IDxcResult > CompileResult ;
VERIFYHRESULT ( DXCCompileWrapper ( Compiler , TextBlob , Arguments , CompileResult ) ) ;
2022-01-21 11:40:12 -05:00
if ( ! CompileResult . IsValid ( ) )
{
2022-01-24 06:12:09 -05:00
return E_FAIL ;
2022-01-21 11:40:12 -05:00
}
2020-06-23 18:40:00 -04:00
HRESULT CompileResultCode ;
CompileResult - > GetStatus ( & CompileResultCode ) ;
if ( SUCCEEDED ( CompileResultCode ) )
{
2022-01-11 16:01:07 -05:00
TRefCountPtr < IDxcBlobUtf16 > ObjectCodeNameBlob ; // Dummy name blob to silence static analysis warning
2020-06-23 18:40:00 -04:00
checkf ( CompileResult - > HasOutput ( DXC_OUT_OBJECT ) , TEXT ( " No object code found! " ) ) ;
2022-01-11 16:01:07 -05:00
VERIFYHRESULT ( CompileResult - > GetOutput ( DXC_OUT_OBJECT , IID_PPV_ARGS ( OutDxilBlob . GetInitReference ( ) ) , ObjectCodeNameBlob . GetInitReference ( ) ) ) ;
2020-06-23 18:40:00 -04:00
2022-01-11 16:01:07 -05:00
TRefCountPtr < IDxcBlobUtf16 > ReflectionNameBlob ; // Dummy name blob to silence static analysis warning
2020-06-23 18:40:00 -04:00
checkf ( CompileResult - > HasOutput ( DXC_OUT_REFLECTION ) , TEXT ( " No reflection found! " ) ) ;
2022-01-11 16:01:07 -05:00
VERIFYHRESULT ( CompileResult - > GetOutput ( DXC_OUT_REFLECTION , IID_PPV_ARGS ( OutReflectionBlob . GetInitReference ( ) ) , ReflectionNameBlob . GetInitReference ( ) ) ) ;
2020-06-23 18:40:00 -04:00
if ( Arguments . ShouldDump ( ) )
{
2021-04-05 04:40:52 -04:00
// Dump disassembly before we strip reflection out
2020-06-23 18:40:00 -04:00
const FString & DisasmFilename = Arguments . GetDumpDisassemblyFilename ( ) ;
check ( DisasmFilename . Len ( ) > 0 ) ;
DisassembleAndSave ( Compiler , OutDxilBlob , DisasmFilename ) ;
// Dump dxil (.d3dasm -> .dxil)
FString DxilFile = Arguments . GetDumpDisassemblyFilename ( ) . LeftChop ( 7 ) + TEXT ( " _refl.dxil " ) ;
SaveDxcBlobToFile ( OutDxilBlob , DxilFile ) ;
2021-12-14 12:22:58 -05:00
if ( CompileResult - > HasOutput ( DXC_OUT_PDB ) )
2020-06-23 18:40:00 -04:00
{
TRefCountPtr < IDxcBlob > PdbBlob ;
2021-12-14 12:22:58 -05:00
TRefCountPtr < IDxcBlobUtf16 > PdbNameBlob ;
VERIFYHRESULT ( CompileResult - > GetOutput ( DXC_OUT_PDB , IID_PPV_ARGS ( PdbBlob . GetInitReference ( ) ) , PdbNameBlob . GetInitReference ( ) ) ) ;
2020-06-23 18:40:00 -04:00
2021-12-14 12:22:58 -05:00
const FString PdbName = PdbNameBlob - > GetStringPointer ( ) ;
2020-06-23 18:40:00 -04:00
// Dump pdb (.d3dasm -> .pdb)
2021-12-14 12:22:58 -05:00
const FString PdbFile = Arguments . GetDumpDebugInfoPath ( ) / PdbName ;
2020-06-23 18:40:00 -04:00
SaveDxcBlobToFile ( PdbBlob , PdbFile ) ;
}
}
DumpFourCCParts ( DxcDllHelper , OutDxilBlob ) ;
2021-09-29 15:13:20 -04:00
if ( RemoveContainerReflection ( DxcDllHelper , OutDxilBlob , ! Arguments . ShouldKeepEmbeddedPDB ( ) ) )
2020-06-23 18:40:00 -04:00
{
DumpFourCCParts ( DxcDllHelper , OutDxilBlob ) ;
}
if ( Arguments . ShouldDump ( ) )
{
// Dump dxil (.d3dasm -> .dxil)
FString DxilFile = Arguments . GetDumpDisassemblyFilename ( ) . LeftChop ( 7 ) + TEXT ( " _norefl.dxil " ) ;
SaveDxcBlobToFile ( OutDxilBlob , DxilFile ) ;
}
GBreakpointDXC + + ;
}
else
{
GBreakpointDXC + + ;
}
CompileResult - > GetErrorBuffer ( OutErrorBlob . GetInitReference ( ) ) ;
return CompileResultCode ;
}
static FString D3DCreateDXCCompileBatchFile ( const FDxcArguments & Args , const FString & ShaderPath )
{
2021-02-02 17:12:57 -04:00
FString DxcPath = FPaths : : ConvertRelativePathToFull ( FPaths : : EngineDir ( ) ) ;
2020-06-23 18:40:00 -04:00
2021-02-02 17:12:57 -04:00
DxcPath = FPaths : : Combine ( DxcPath , TEXT ( " Binaries/ThirdParty/ShaderConductor/Win64 " ) ) ;
FPaths : : MakePlatformFilename ( DxcPath ) ;
2020-06-23 18:40:00 -04:00
2021-02-02 17:12:57 -04:00
FString DxcFilename = FPaths : : Combine ( DxcPath , TEXT ( " dxc.exe " ) ) ;
FPaths : : MakePlatformFilename ( DxcFilename ) ;
2020-06-23 18:40:00 -04:00
2021-02-02 17:12:57 -04:00
const FString BatchCmdLineArgs = Args . GetBatchCommandLineString ( ShaderPath ) ;
2020-06-23 18:40:00 -04:00
2021-02-02 17:12:57 -04:00
return FString : : Printf (
TEXT (
" @ECHO OFF \n "
" SET DXC= \" %s \" \n "
" IF NOT EXIST %%DXC%% ( \n "
" \t ECHO Couldn't find dxc.exe under \" %s \" \n "
" \t GOTO :END \n "
" ) \n "
" %%DXC%%%s %s \n "
" :END \n "
" PAUSE \n "
) ,
* DxcFilename ,
* DxcPath ,
* BatchCmdLineArgs ,
* ShaderPath
) ;
2020-06-23 18:40:00 -04:00
}
inline bool IsCompatibleBinding ( const D3D12_SHADER_INPUT_BIND_DESC & BindDesc , uint32 BindingSpace )
{
2020-07-06 18:58:26 -04:00
bool bIsCompatibleBinding = ( BindDesc . Space = = BindingSpace ) ;
if ( ! bIsCompatibleBinding )
{
const bool bIsAMDExtensionDX12 = ( FCStringAnsi : : Strcmp ( BindDesc . Name , " AmdExtD3DShaderIntrinsicsUAV " ) = = 0 ) ;
bIsCompatibleBinding = bIsAMDExtensionDX12 & & ( BindDesc . Space = = AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ) ;
}
2021-04-30 08:37:35 -04:00
if ( ! bIsCompatibleBinding )
{
// #todo: there is currently no common header where a binding space number or buffer name could be defined. See D3DCommon.ush and D3D12RootSignature.cpp.
const bool bIsUEDebugBuffer = ( FCStringAnsi : : Strcmp ( BindDesc . Name , " UEDiagnosticBuffer " ) = = 0 ) ;
bIsCompatibleBinding = bIsUEDebugBuffer & & ( BindDesc . Space = = 999 ) ;
}
2020-07-06 18:58:26 -04:00
return bIsCompatibleBinding ;
2020-06-23 18:40:00 -04:00
}
// Parses ray tracing shader entry point specification string in one of the following formats:
// 1) Verbatim single entry point name, e.g. "MainRGS"
// 2) Complex entry point for ray tracing hit group shaders:
// a) "closesthit=MainCHS"
// b) "closesthit=MainCHS anyhit=MainAHS"
// c) "closesthit=MainCHS anyhit=MainAHS intersection=MainIS"
// d) "closesthit=MainCHS intersection=MainIS"
// NOTE: closesthit attribute must always be provided for complex hit group entry points
static void ParseRayTracingEntryPoint ( const FString & Input , FString & OutMain , FString & OutAnyHit , FString & OutIntersection )
{
auto ParseEntry = [ & Input ] ( const TCHAR * Marker )
{
FString Result ;
int32 BeginIndex = Input . Find ( Marker , ESearchCase : : IgnoreCase , ESearchDir : : FromStart ) ;
if ( BeginIndex ! = INDEX_NONE )
{
int32 EndIndex = Input . Find ( TEXT ( " " ) , ESearchCase : : IgnoreCase , ESearchDir : : FromStart , BeginIndex ) ;
if ( EndIndex = = INDEX_NONE ) EndIndex = Input . Len ( ) + 1 ;
int32 MarkerLen = FCString : : Strlen ( Marker ) ;
int32 Count = EndIndex - BeginIndex ;
Result = Input . Mid ( BeginIndex + MarkerLen , Count - MarkerLen ) ;
}
return Result ;
} ;
OutMain = ParseEntry ( TEXT ( " closesthit= " ) ) ;
OutAnyHit = ParseEntry ( TEXT ( " anyhit= " ) ) ;
OutIntersection = ParseEntry ( TEXT ( " intersection= " ) ) ;
// If complex hit group entry is not specified, assume a single verbatim entry point
if ( OutMain . IsEmpty ( ) & & OutAnyHit . IsEmpty ( ) & & OutIntersection . IsEmpty ( ) )
{
OutMain = Input ;
}
}
static ShaderConductor : : Compiler : : ShaderModel ToDXCShaderModel ( ELanguage Language )
{
switch ( Language )
{
case ELanguage : : ES3_1 :
case ELanguage : : SM5 :
return { 5 , 0 } ;
default :
UE_LOG ( LogD3D12ShaderCompiler , Error , TEXT ( " Invalid input shader target for enum ELanguage (%d). " ) , ( int32 ) Language ) ;
}
return { 6 , 0 } ;
}
static ShaderConductor : : ShaderStage ToDXCShaderStage ( EShaderFrequency Frequency )
{
check ( Frequency > = SF_Vertex & & Frequency < = SF_Compute ) ;
switch ( Frequency )
{
case SF_Vertex : return ShaderConductor : : ShaderStage : : VertexShader ;
case SF_Pixel : return ShaderConductor : : ShaderStage : : PixelShader ;
case SF_Geometry : return ShaderConductor : : ShaderStage : : GeometryShader ;
case SF_Compute : return ShaderConductor : : ShaderStage : : ComputeShader ;
default : return ShaderConductor : : ShaderStage : : NumShaderStages ;
}
}
2020-12-01 19:33:51 -04:00
// Inner wrapper function is required here because '__try'-statement cannot be used with function that requires object unwinding
static void InnerScRewriteWrapper (
const ShaderConductor : : Compiler : : SourceDesc & InDesc ,
const ShaderConductor : : Compiler : : Options & InOptions ,
ShaderConductor : : Compiler : : ResultDesc & OutResultDesc )
2020-06-23 18:40:00 -04:00
{
2020-12-01 19:33:51 -04:00
OutResultDesc = ShaderConductor : : Compiler : : Rewrite ( InDesc , InOptions ) ;
2020-06-23 18:40:00 -04:00
}
2020-12-01 19:33:51 -04:00
static bool DXCRewriteWrapper (
const ShaderConductor : : Compiler : : SourceDesc & InDesc ,
2020-06-23 18:40:00 -04:00
const ShaderConductor : : Compiler : : Options & InOptions ,
2020-12-01 19:33:51 -04:00
ShaderConductor : : Compiler : : ResultDesc & OutResultDesc ,
2020-06-23 18:40:00 -04:00
bool & bOutException )
{
bOutException = false ;
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED
__try
# endif
{
2020-12-01 19:33:51 -04:00
InnerScRewriteWrapper ( InDesc , InOptions , OutResultDesc ) ;
return true ;
2020-06-23 18:40:00 -04:00
}
# if !PLATFORM_SEH_EXCEPTIONS_DISABLED
__except ( EXCEPTION_EXECUTE_HANDLER )
{
GSCWErrorCode = ESCWErrorCode : : CrashInsidePlatformCompiler ;
2020-12-01 19:33:51 -04:00
FMemory : : Memzero ( OutResultDesc ) ;
2020-06-23 18:40:00 -04:00
bOutException = true ;
2020-12-01 19:33:51 -04:00
return false ;
2020-06-23 18:40:00 -04:00
}
# endif
}
static const TCHAR * GRewrittenBaseFilename = TEXT ( " Output.dxc.hlsl " ) ;
static bool RewriteUsingSC ( FString & PreprocessedShaderSource , const FShaderCompilerInput & Input , bool bIsRayTracingShader ,
bool bDumpDebugInfo , ELanguage Language , FShaderCompilerOutput & Output )
{
bool bResult = true ;
2021-04-20 17:00:25 -04:00
if ( bIsRayTracingShader )
2020-06-23 18:40:00 -04:00
{
bResult = false ;
}
else
{
// Set up compile options for ShaderConductor (shader model, optimization settings etc.)
ShaderConductor : : Compiler : : Options Options ;
Options . removeUnusedGlobals = false ;
Options . packMatricesInRowMajor = false ;
Options . enableDebugInfo = false ;
Options . enable16bitTypes = false ;
Options . disableOptimizations = false ;
Options . shaderModel = ToDXCShaderModel ( Language ) ;
// Convert input source code from TCHAR to ANSI
std : : string CStrSourceData ( TCHAR_TO_ANSI ( * PreprocessedShaderSource ) ) ;
std : : string CStrFileName ( TCHAR_TO_ANSI ( * Input . VirtualSourceFilePath ) ) ;
std : : string CStrEntryPointName ( TCHAR_TO_ANSI ( * Input . EntryPointName ) ) ;
const ShaderConductor : : MacroDefine BuiltinDefines [ ] =
{
// { "COMPILER_HLSL", "1" },
{ " TextureExternal " , " Texture2D " } ,
} ;
// Set up source description for ShaderConductor
ShaderConductor : : Compiler : : SourceDesc SourceDesc ;
FMemory : : Memzero ( SourceDesc ) ;
SourceDesc . source = CStrSourceData . c_str ( ) ;
SourceDesc . fileName = CStrFileName . c_str ( ) ;
SourceDesc . entryPoint = CStrEntryPointName . c_str ( ) ;
SourceDesc . numDefines = sizeof ( BuiltinDefines ) / sizeof ( BuiltinDefines [ 0 ] ) ;
SourceDesc . defines = BuiltinDefines ;
SourceDesc . stage = ToDXCShaderStage ( Input . Target . GetFrequency ( ) ) ;
ShaderConductor : : Compiler : : TargetDesc TargetDesc ;
FMemory : : Memzero ( TargetDesc ) ;
TargetDesc . language = ShaderConductor : : ShadingLanguage : : Dxil ;
// Rewrite HLSL source to remove unused global variables (DXC retains them when compiling)
Options . removeUnusedGlobals = true ;
bool bException = false ;
2020-12-01 19:33:51 -04:00
ShaderConductor : : Compiler : : ResultDesc RewriteResultDesc ;
DXCRewriteWrapper ( SourceDesc , Options , RewriteResultDesc , bException ) ;
2020-06-23 18:40:00 -04:00
Options . removeUnusedGlobals = false ;
if ( RewriteResultDesc . hasError | | bException )
{
if ( bException )
{
Output . Errors . Add ( TEXT ( " ShaderConductor exception during rewrite " ) ) ;
}
// Append compile error to output reports
2020-12-01 19:33:51 -04:00
if ( RewriteResultDesc . errorWarningMsg . Size ( ) > 0 )
2020-06-23 18:40:00 -04:00
{
2020-12-01 19:33:51 -04:00
FUTF8ToTCHAR UTF8Converter ( reinterpret_cast < const ANSICHAR * > ( RewriteResultDesc . errorWarningMsg . Data ( ) ) , RewriteResultDesc . errorWarningMsg . Size ( ) ) ;
const FString ErrorString ( RewriteResultDesc . errorWarningMsg . Size ( ) , UTF8Converter . Get ( ) ) ;
2020-06-23 18:40:00 -04:00
Output . Errors . Add ( * ErrorString ) ;
2020-12-01 19:33:51 -04:00
RewriteResultDesc . errorWarningMsg . Reset ( ) ;
2020-06-23 18:40:00 -04:00
bResult = false ;
}
}
else
{
// Copy rewritten HLSL code into new source data string
CStrSourceData . clear ( ) ;
2020-12-01 19:33:51 -04:00
CStrSourceData . resize ( RewriteResultDesc . target . Size ( ) ) ;
FCStringAnsi : : Strncpy ( & CStrSourceData [ 0 ] , static_cast < const char * > ( RewriteResultDesc . target . Data ( ) ) , RewriteResultDesc . target . Size ( ) ) ;
2020-06-23 18:40:00 -04:00
PreprocessedShaderSource = CStrSourceData . c_str ( ) ;
if ( bDumpDebugInfo )
{
2020-09-24 00:43:27 -04:00
DumpDebugUSF ( Input , CStrSourceData . c_str ( ) , 0 , GRewrittenBaseFilename ) ;
2020-06-23 18:40:00 -04:00
}
}
}
return bResult ;
}
// Generate the dumped usf file; call the D3D compiler, gather reflection information and generate the output data
bool CompileAndProcessD3DShaderDXC ( FString & PreprocessedShaderSource ,
2021-09-06 11:28:30 -04:00
const uint32 CompileFlags ,
const FShaderCompilerInput & Input ,
const FShaderParameterParser & ShaderParameterParser ,
FString & EntryPointName ,
2020-06-23 18:40:00 -04:00
const TCHAR * ShaderProfile , ELanguage Language , bool bProcessingSecondTime ,
TArray < FString > & FilteredErrors , FShaderCompilerOutput & Output )
{
2022-03-21 12:17:22 -04:00
TRACE_CPUPROFILER_EVENT_SCOPE ( CompileAndProcessD3DShaderDXC ) ;
2020-06-23 18:40:00 -04:00
auto AnsiSourceFile = StringCast < ANSICHAR > ( * PreprocessedShaderSource ) ;
2020-12-11 14:21:20 -04:00
const bool bIsRayTracingShader = Input . IsRayTracingShader ( ) ;
2020-06-23 18:40:00 -04:00
const uint32 AutoBindingSpace = GetAutoBindingSpace ( Input . Target ) ;
FString RayEntryPoint ; // Primary entry point for all ray tracing shaders
FString RayAnyHitEntryPoint ; // Optional for hit group shaders
FString RayIntersectionEntryPoint ; // Optional for hit group shaders
FString RayTracingExports ;
2020-09-01 14:07:48 -04:00
bool bEnable16BitTypes = false ;
2021-08-16 15:12:30 -04:00
if ( Language = = ELanguage : : SM6 )
{
// 16bit types are SM6.2 whereas Language == ELanguage::SM6 is SM6.6, so their support at runtime is guarented.
bEnable16BitTypes = Input . Environment . CompilerFlags . Contains ( CFLAG_AllowRealTypes ) ;
}
2020-09-01 14:07:48 -04:00
2020-06-23 18:40:00 -04:00
if ( bIsRayTracingShader )
{
ParseRayTracingEntryPoint ( Input . EntryPointName , RayEntryPoint , RayAnyHitEntryPoint , RayIntersectionEntryPoint ) ;
RayTracingExports = RayEntryPoint ;
if ( ! RayAnyHitEntryPoint . IsEmpty ( ) )
{
RayTracingExports + = TEXT ( " ; " ) ;
RayTracingExports + = RayAnyHitEntryPoint ;
}
if ( ! RayIntersectionEntryPoint . IsEmpty ( ) )
{
RayTracingExports + = TEXT ( " ; " ) ;
RayTracingExports + = RayIntersectionEntryPoint ;
}
2020-09-01 14:07:48 -04:00
// Enable 16bit_types to reduce DXIL size (compiler bug - will be fixed)
bEnable16BitTypes = true ;
2020-06-23 18:40:00 -04:00
}
// Write out the preprocessed file and a batch file to compile it if requested (DumpDebugInfoPath is valid)
bool bDumpDebugInfo = DumpDebugShaderUSF ( PreprocessedShaderSource , Input ) ;
FString Filename = Input . GetSourceFilename ( ) ;
if ( Input . Environment . CompilerFlags . Contains ( CFLAG_D3D12ForceShaderConductorRewrite ) )
{
if ( RewriteUsingSC ( PreprocessedShaderSource , Input , bIsRayTracingShader , bDumpDebugInfo , Language , Output ) )
{
Filename = GRewrittenBaseFilename ;
}
}
FString DisasmFilename ;
if ( bDumpDebugInfo )
{
DisasmFilename = Input . DumpDebugInfoPath / Filename ;
}
// Ignore backwards compatibility flag (/Gec) as it is deprecated.
// #dxr_todo: this flag should not be even passed into this function from the higher level.
2020-09-25 12:21:25 -04:00
uint32 DXCFlags = CompileFlags & ( ~ D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY ) ;
2020-06-23 18:40:00 -04:00
if ( Input . Environment . CompilerFlags . Contains ( CFLAG_SkipOptimizationsDXC ) )
{
2020-09-25 12:21:25 -04:00
DXCFlags | = D3DCOMPILE_SKIP_OPTIMIZATION ;
2020-06-23 18:40:00 -04:00
}
2021-04-05 04:40:52 -04:00
const TCHAR * ValidatorVersion = nullptr ; // Whatever default validator chosen by DXC
2021-08-16 23:18:23 -04:00
const bool bGenerateSymbols = Input . Environment . CompilerFlags . Contains ( CFLAG_GenerateSymbols ) ;
const bool bSymbolsBasedOnSource = Input . Environment . CompilerFlags . Contains ( CFLAG_AllowUniqueSymbols ) ;
2022-03-09 09:47:28 -05:00
const bool bHlslVersion2021 = Input . Environment . CompilerFlags . Contains ( CFLAG_HLSL2021 ) ;
const uint32 HlslVersion = ( bHlslVersion2021 ? 2021 : 2018 ) ;
2020-06-23 18:40:00 -04:00
2021-04-05 04:40:52 -04:00
FDxcArguments Args
(
EntryPointName ,
ShaderProfile ,
RayTracingExports ,
Input . DumpDebugInfoPath ,
Filename ,
bEnable16BitTypes ,
2021-08-16 23:18:23 -04:00
bGenerateSymbols ,
bSymbolsBasedOnSource ,
2021-04-05 04:40:52 -04:00
DXCFlags ,
AutoBindingSpace ,
2022-03-09 09:47:28 -05:00
ValidatorVersion ,
HlslVersion
2021-04-05 04:40:52 -04:00
) ;
2020-06-23 18:40:00 -04:00
if ( bDumpDebugInfo )
{
FString BatchFileContents = D3DCreateDXCCompileBatchFile ( Args , Filename ) ;
FFileHelper : : SaveStringToFile ( BatchFileContents , * ( Input . DumpDebugInfoPath / TEXT ( " CompileDXC.bat " ) ) ) ;
if ( Input . bGenerateDirectCompileFile )
{
FFileHelper : : SaveStringToFile ( CreateShaderCompilerWorkerDirectCommandLine ( Input ) , * ( Input . DumpDebugInfoPath / TEXT ( " DirectCompile.txt " ) ) ) ;
FFileHelper : : SaveStringToFile ( Input . DebugDescription , * ( Input . DumpDebugInfoPath / TEXT ( " permutation_info.txt " ) ) ) ;
}
}
TRefCountPtr < IDxcBlob > ShaderBlob ;
TRefCountPtr < IDxcBlob > ReflectionBlob ;
TRefCountPtr < IDxcBlobEncoding > DxcErrorBlob ;
2021-03-17 20:12:52 -04:00
const HRESULT D3DCompileToDxilResult = D3DCompileToDxil ( AnsiSourceFile . Get ( ) , Args , ShaderBlob , ReflectionBlob , DxcErrorBlob ) ;
2020-06-23 18:40:00 -04:00
if ( DxcErrorBlob & & DxcErrorBlob - > GetBufferSize ( ) )
{
FString ErrorString = DxcBlobEncodingToFString ( DxcErrorBlob ) ;
DXCFilterShaderCompileWarnings ( ErrorString , FilteredErrors ) ;
}
2021-03-17 20:12:52 -04:00
if ( SUCCEEDED ( D3DCompileToDxilResult ) )
2020-06-23 18:40:00 -04:00
{
// Gather reflection information
TArray < FString > ShaderInputs ;
TArray < FShaderCodeVendorExtension > VendorExtensions ;
bool bGlobalUniformBufferUsed = false ;
2021-04-30 08:37:35 -04:00
bool bDiagnosticBufferUsed = false ;
2020-06-23 18:40:00 -04:00
uint32 NumInstructions = 0 ;
uint32 NumSamplers = 0 ;
uint32 NumSRVs = 0 ;
uint32 NumCBs = 0 ;
uint32 NumUAVs = 0 ;
TArray < FString > UniformBufferNames ;
TArray < FString > ShaderOutputs ;
TBitArray < > UsedUniformBufferSlots ;
UsedUniformBufferSlots . Init ( false , 32 ) ;
2021-09-14 16:28:37 -04:00
uint64 ShaderRequiresFlags { } ;
2020-06-23 18:40:00 -04:00
dxc : : DxcDllSupport & DxcDllHelper = GetDxcDllHelper ( ) ;
TRefCountPtr < IDxcUtils > Utils ;
VERIFYHRESULT ( DxcDllHelper . CreateInstance ( CLSID_DxcUtils , Utils . GetInitReference ( ) ) ) ;
DxcBuffer ReflBuffer = { 0 } ;
ReflBuffer . Ptr = ReflectionBlob - > GetBufferPointer ( ) ;
ReflBuffer . Size = ReflectionBlob - > GetBufferSize ( ) ;
if ( bIsRayTracingShader )
{
TRefCountPtr < ID3D12LibraryReflection > LibraryReflection ;
2021-03-17 20:12:52 -04:00
const HRESULT CreateReflectionResult = Utils - > CreateReflection ( & ReflBuffer , IID_PPV_ARGS ( LibraryReflection . GetInitReference ( ) ) ) ;
2020-06-23 18:40:00 -04:00
2021-03-17 20:12:52 -04:00
if ( FAILED ( CreateReflectionResult ) )
2020-06-23 18:40:00 -04:00
{
2021-03-17 20:12:52 -04:00
UE_LOG ( LogD3D12ShaderCompiler , Fatal , TEXT ( " CreateReflection failed: Result=%08x " ) , CreateReflectionResult ) ;
2020-06-23 18:40:00 -04:00
}
D3D12_LIBRARY_DESC LibraryDesc = { } ;
LibraryReflection - > GetDesc ( & LibraryDesc ) ;
ID3D12FunctionReflection * FunctionReflection = nullptr ;
D3D12_FUNCTION_DESC FunctionDesc = { } ;
// MangledEntryPoints contains partial mangled entry point signatures in a the following form:
// ?QualifiedName@ (as described here: https://en.wikipedia.org/wiki/Name_mangling)
// Entry point parameters are currently not included in the partial mangling.
TArray < FString , TInlineAllocator < 3 > > MangledEntryPoints ;
if ( ! RayEntryPoint . IsEmpty ( ) )
{
MangledEntryPoints . Add ( FString : : Printf ( TEXT ( " ?%s@ " ) , * RayEntryPoint ) ) ;
}
if ( ! RayAnyHitEntryPoint . IsEmpty ( ) )
{
MangledEntryPoints . Add ( FString : : Printf ( TEXT ( " ?%s@ " ) , * RayAnyHitEntryPoint ) ) ;
}
if ( ! RayIntersectionEntryPoint . IsEmpty ( ) )
{
MangledEntryPoints . Add ( FString : : Printf ( TEXT ( " ?%s@ " ) , * RayIntersectionEntryPoint ) ) ;
}
uint32 NumFoundEntryPoints = 0 ;
for ( uint32 FunctionIndex = 0 ; FunctionIndex < LibraryDesc . FunctionCount ; + + FunctionIndex )
{
FunctionReflection = LibraryReflection - > GetFunctionByIndex ( FunctionIndex ) ;
FunctionReflection - > GetDesc ( & FunctionDesc ) ;
2021-09-14 16:28:37 -04:00
ShaderRequiresFlags | = FunctionDesc . RequiredFeatureFlags ;
2020-06-23 18:40:00 -04:00
for ( const FString & MangledEntryPoint : MangledEntryPoints )
{
// Entry point parameters are currently not included in the partial mangling, therefore partial substring match is used here.
if ( FCStringAnsi : : Strstr ( FunctionDesc . Name , TCHAR_TO_ANSI ( * MangledEntryPoint ) ) )
{
// Note: calling ExtractParameterMapFromD3DShader multiple times merges the reflection data for multiple functions
ExtractParameterMapFromD3DShader < ID3D12FunctionReflection , D3D12_FUNCTION_DESC , D3D12_SHADER_INPUT_BIND_DESC ,
ID3D12ShaderReflectionConstantBuffer , D3D12_SHADER_BUFFER_DESC ,
ID3D12ShaderReflectionVariable , D3D12_SHADER_VARIABLE_DESC > (
2021-09-06 11:28:30 -04:00
Input , ShaderParameterParser ,
AutoBindingSpace , FunctionReflection , FunctionDesc ,
2021-04-30 08:37:35 -04:00
bGlobalUniformBufferUsed , bDiagnosticBufferUsed ,
NumSamplers , NumSRVs , NumCBs , NumUAVs ,
2020-06-23 18:40:00 -04:00
Output , UniformBufferNames , UsedUniformBufferSlots , VendorExtensions ) ;
NumFoundEntryPoints + + ;
}
}
}
if ( NumFoundEntryPoints = = MangledEntryPoints . Num ( ) )
{
Output . bSucceeded = true ;
bool bGlobalUniformBufferAllowed = false ;
if ( bGlobalUniformBufferUsed & & ! IsGlobalConstantBufferSupported ( Input . Target ) )
{
const TCHAR * ShaderFrequencyString = GetShaderFrequencyString ( Input . Target . GetFrequency ( ) , false ) ;
FString ErrorString = FString : : Printf ( TEXT ( " Global uniform buffer cannot be used in a %s shader. " ) , ShaderFrequencyString ) ;
uint32 NumLooseParameters = 0 ;
for ( const auto & It : Output . ParameterMap . ParameterMap )
{
if ( It . Value . Type = = EShaderParameterType : : LooseData )
{
NumLooseParameters + + ;
}
}
if ( NumLooseParameters )
{
ErrorString + = TEXT ( " Global parameters: " ) ;
uint32 ParameterIndex = 0 ;
for ( const auto & It : Output . ParameterMap . ParameterMap )
{
if ( It . Value . Type = = EShaderParameterType : : LooseData )
{
- - NumLooseParameters ;
ErrorString + = FString : : Printf ( TEXT ( " %s%s " ) , * It . Key , NumLooseParameters ? TEXT ( " , " ) : TEXT ( " . " ) ) ;
}
}
}
FilteredErrors . Add ( ErrorString ) ;
Output . bSucceeded = false ;
}
}
else
{
UE_LOG ( LogD3D12ShaderCompiler , Fatal , TEXT ( " Failed to find required points in the shader library. " ) ) ;
Output . bSucceeded = false ;
}
}
else
{
TRefCountPtr < ID3D12ShaderReflection > ShaderReflection ;
2021-03-17 20:12:52 -04:00
const HRESULT CreateReflectionResult = Utils - > CreateReflection ( & ReflBuffer , IID_PPV_ARGS ( ShaderReflection . GetInitReference ( ) ) ) ;
if ( FAILED ( CreateReflectionResult ) )
2020-06-23 18:40:00 -04:00
{
2021-03-17 20:12:52 -04:00
UE_LOG ( LogD3D12ShaderCompiler , Fatal , TEXT ( " CreateReflection failed: Result=%08x " ) , CreateReflectionResult ) ;
2020-06-23 18:40:00 -04:00
}
D3D12_SHADER_DESC ShaderDesc = { } ;
ShaderReflection - > GetDesc ( & ShaderDesc ) ;
2021-09-14 16:28:37 -04:00
ShaderRequiresFlags = ShaderReflection - > GetRequiresFlags ( ) ;
2020-06-23 18:40:00 -04:00
ExtractParameterMapFromD3DShader < ID3D12ShaderReflection , D3D12_SHADER_DESC , D3D12_SHADER_INPUT_BIND_DESC ,
ID3D12ShaderReflectionConstantBuffer , D3D12_SHADER_BUFFER_DESC ,
ID3D12ShaderReflectionVariable , D3D12_SHADER_VARIABLE_DESC > (
2021-09-06 11:28:30 -04:00
Input , ShaderParameterParser ,
AutoBindingSpace , ShaderReflection , ShaderDesc ,
2021-09-14 16:28:37 -04:00
bGlobalUniformBufferUsed , bDiagnosticBufferUsed ,
2021-09-06 11:28:30 -04:00
NumSamplers , NumSRVs , NumCBs , NumUAVs ,
2020-06-23 18:40:00 -04:00
Output , UniformBufferNames , UsedUniformBufferSlots , VendorExtensions ) ;
2022-04-13 13:37:00 -04:00
NumInstructions = ShaderDesc . InstructionCount ;
2020-06-23 18:40:00 -04:00
Output . bSucceeded = true ;
}
if ( ! ValidateResourceCounts ( NumSRVs , NumSamplers , NumUAVs , NumCBs , FilteredErrors ) )
{
Output . bSucceeded = false ;
}
2022-05-17 16:30:48 -04:00
const bool bBindlessResourcesUsed = ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_RESOURCE_DESCRIPTOR_HEAP_INDEXING ) ! = 0 ) ;
const bool bBindlessSamplersUsed = ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_SAMPLER_DESCRIPTOR_HEAP_INDEXING ) ! = 0 ) ;
if ( Output . bSucceeded )
{
auto GetAllResourcesOfType = [ & ] ( EShaderParameterType InType )
{
const TArray < FString > AllNames = Output . ParameterMap . GetAllParameterNamesOfType ( InType ) ;
if ( AllNames . IsEmpty ( ) )
{
return FString ( ) ;
}
return FString : : Join ( AllNames , TEXT ( " , " ) ) ;
} ;
if ( bBindlessResourcesUsed & & NumSRVs > 0 )
{
const FString Names = GetAllResourcesOfType ( EShaderParameterType : : SRV ) ;
FilteredErrors . Add ( FString : : Printf ( TEXT ( " Shader is mixing bindless resources with non-bindless resources. %d SRV slots were detected: %s " ) , NumSRVs , * Names ) ) ;
Output . bSucceeded = false ;
}
if ( bBindlessResourcesUsed & & NumUAVs > 0 )
{
const FString Names = GetAllResourcesOfType ( EShaderParameterType : : UAV ) ;
FilteredErrors . Add ( FString : : Printf ( TEXT ( " Shader is mixing bindless resources with non-bindless resources. %d UAV slots were detected: %s " ) , NumUAVs , * Names ) ) ;
Output . bSucceeded = false ;
}
if ( bBindlessSamplersUsed & & NumSamplers > 0 )
{
const FString Names = GetAllResourcesOfType ( EShaderParameterType : : Sampler ) ;
FilteredErrors . Add ( FString : : Printf ( TEXT ( " Shader is mixing bindless samplers with non-bindless samplers. %d sampler slots were detected: %s " ) , NumSamplers , * Names ) ) ;
Output . bSucceeded = false ;
}
}
2020-06-23 18:40:00 -04:00
// Save results if compilation and reflection succeeded
if ( Output . bSucceeded )
{
auto PostSRTWriterCallback = [ & ] ( FMemoryWriter & Ar )
{
if ( bIsRayTracingShader )
{
Ar < < RayEntryPoint ;
Ar < < RayAnyHitEntryPoint ;
Ar < < RayIntersectionEntryPoint ;
}
} ;
auto AddOptionalDataCallback = [ & ] ( FShaderCode & ShaderCode )
{
FShaderCodeFeatures CodeFeatures ;
2021-09-14 16:28:37 -04:00
if ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_WAVE_OPS ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : WaveOps ) ;
}
if ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_NATIVE_16BIT_OPS ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : SixteenBitTypes ) ;
}
if ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_TYPED_UAV_LOAD_ADDITIONAL_FORMATS ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : TypedUAVLoadsExtended ) ;
}
if ( ( ShaderRequiresFlags & ( D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_TYPED_RESOURCE | D3D_SHADER_REQUIRES_ATOMIC_INT64_ON_GROUP_SHARED ) ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : Atomic64 ) ;
}
if ( bDiagnosticBufferUsed )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : DiagnosticBuffer ) ;
}
if ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_RESOURCE_DESCRIPTOR_HEAP_INDEXING ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : BindlessResources ) ;
}
if ( ( ShaderRequiresFlags & D3D_SHADER_REQUIRES_SAMPLER_DESCRIPTOR_HEAP_INDEXING ) ! = 0 )
{
EnumAddFlags ( CodeFeatures . CodeFeatures , EShaderCodeFeatures : : BindlessSamplers ) ;
}
2020-06-23 18:40:00 -04:00
// We only need this to appear when using a DXC shader
ShaderCode . AddOptionalData < FShaderCodeFeatures > ( CodeFeatures ) ;
2021-09-14 16:28:37 -04:00
if ( Language ! = ELanguage : : SM6 )
{
uint8 IsSM6 = 1 ;
ShaderCode . AddOptionalData ( ' 6 ' , & IsSM6 , 1 ) ;
}
2020-06-23 18:40:00 -04:00
} ;
//#todo-rco: Should compress ShaderCode?
2022-05-17 16:30:48 -04:00
FShaderCodePackedResourceCounts PackedResourceCounts { } ;
if ( bGlobalUniformBufferUsed )
{
PackedResourceCounts . UsageFlags | = EShaderResourceUsageFlags : : GlobalUniformBuffer ;
}
if ( bBindlessResourcesUsed )
{
PackedResourceCounts . UsageFlags | = EShaderResourceUsageFlags : : BindlessResources ;
}
if ( bBindlessSamplersUsed )
{
PackedResourceCounts . UsageFlags | = EShaderResourceUsageFlags : : BindlessSamplers ;
}
PackedResourceCounts . NumSamplers = static_cast < uint8 > ( NumSamplers ) ;
PackedResourceCounts . NumSRVs = static_cast < uint8 > ( NumSRVs ) ;
PackedResourceCounts . NumCBs = static_cast < uint8 > ( NumCBs ) ;
PackedResourceCounts . NumUAVs = static_cast < uint8 > ( NumUAVs ) ;
2020-06-23 18:40:00 -04:00
GenerateFinalOutput ( ShaderBlob ,
Input , VendorExtensions ,
UsedUniformBufferSlots , UniformBufferNames ,
bProcessingSecondTime , ShaderInputs ,
PackedResourceCounts , NumInstructions ,
Output ,
PostSRTWriterCallback ,
AddOptionalDataCallback ) ;
}
}
2021-03-17 20:12:52 -04:00
else
2020-06-23 18:40:00 -04:00
{
2021-02-06 07:48:09 -04:00
TCHAR ErrorMsg [ 1024 ] ;
2021-03-17 20:12:52 -04:00
FPlatformMisc : : GetSystemErrorMessage ( ErrorMsg , UE_ARRAY_COUNT ( ErrorMsg ) , ( int ) D3DCompileToDxilResult ) ;
2021-02-06 07:48:09 -04:00
const bool bKnownError = ErrorMsg [ 0 ] ! = TEXT ( ' \0 ' ) ;
2021-03-17 20:12:52 -04:00
FString ErrorString = FString : : Printf ( TEXT ( " D3DCompileToDxil failed. Error code: %s (0x%08X). " ) , bKnownError ? ErrorMsg : TEXT ( " Unknown error " ) , ( int ) D3DCompileToDxilResult ) ;
2021-02-06 07:48:09 -04:00
FilteredErrors . Add ( ErrorString ) ;
2020-06-23 18:40:00 -04:00
}
2021-03-17 20:12:52 -04:00
return Output . bSucceeded ;
2020-06-23 18:40:00 -04:00
}
# undef VERIFYHRESULT