Files
UnrealEngineUWP/Engine/Source/Developer/Windows/ShaderFormatD3D/Private/ShaderFormatD3D.cpp
Yuriy ODonnell bddca76c94 ShaderMinifier - Add support for dead code removal to all shader formats
* Add code to all shader format back-ends to take dead code removal into account when computing the version ID
* Not enabled in Metal and OpenGL back-ends (require further testing)

#rb dan.elksnitis
#preflight 6390f1f15c5308d18c7364fb

[CL 23433448 by Yuriy ODonnell in ue5-main branch]
2022-12-07 15:13:42 -05:00

230 lines
6.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ShaderFormatD3D.h"
#include "ShaderCompilerCommon.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IShaderFormat.h"
#include "Interfaces/IShaderFormatModule.h"
#include "DXCWrapper.h"
static FName NAME_PCD3D_SM6(TEXT("PCD3D_SM6"));
static FName NAME_PCD3D_SM5(TEXT("PCD3D_SM5"));
static FName NAME_PCD3D_ES3_1(TEXT("PCD3D_ES31"));
static FName NAME_D3D_ES3_1_HOLOLENS(TEXT("D3D_ES3_1_HOLOLENS"));
class FShaderFormatD3D : public IShaderFormat
{
enum EVersion
{
UE_SHADER_PCD3D_SHARED_VER = 5,
/** Version for shader format, this becomes part of the DDC key. */
UE_SHADER_PCD3D_SM6_VER = 7,
UE_SHADER_PCD3D_SM5_VER = 12,
UE_SHADER_PCD3D_ES3_1_VER = 8,
UE_SHADER_D3D_ES3_1_HOLOLENS_VER = UE_SHADER_PCD3D_ES3_1_VER,
};
void CheckFormat(FName Format) const
{
check(Format == NAME_PCD3D_SM6 || Format == NAME_PCD3D_SM5 || Format == NAME_PCD3D_ES3_1 || Format == NAME_D3D_ES3_1_HOLOLENS);
}
uint32 DxcVersionHash = 0;
public:
FShaderFormatD3D(uint32 InDxcVersionHash)
: DxcVersionHash(InDxcVersionHash)
{
}
inline uint32 GetVersionHash(EVersion InVersion) const
{
const uint32 BaseHash = GetTypeHash(UE_SHADER_PCD3D_SHARED_VER);
uint32 VersionHash = GetTypeHash(InVersion);
#if UE_D3D_SHADER_COMPILER_ALLOW_DEAD_CODE_REMOVAL
{
static const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Shader.RemoveDeadCode"));
if (CVar && CVar->GetInt() != 0)
{
VersionHash = HashCombine(VersionHash, 0x75E2FE85);
}
}
#endif // UE_D3D_SHADER_COMPILER_ALLOW_DEAD_CODE_REMOVAL
return HashCombine(BaseHash, VersionHash);
}
virtual uint32 GetVersion(FName Format) const override
{
CheckFormat(Format);
if (Format == NAME_PCD3D_SM6)
{
uint32 ShaderModelHash = GetVersionHash(UE_SHADER_PCD3D_SM6_VER);
#if USE_SHADER_MODEL_6_6
ShaderModelHash ^= 0x96ED7F56;
#endif
// Make sure we recompile if EShaderCodeFeatures gets bigger
ShaderModelHash = HashCombine(ShaderModelHash, GetTypeHash(sizeof(EShaderCodeFeatures)));
return HashCombine(DxcVersionHash, ShaderModelHash);
}
else if (Format == NAME_PCD3D_SM5)
{
uint32 ShaderModelHash = GetVersionHash(UE_SHADER_PCD3D_SM6_VER);
// Make sure we recompile if EShaderCodeFeatures gets bigger
ShaderModelHash = HashCombine(ShaderModelHash, GetTypeHash(sizeof(EShaderCodeFeatures)));
// Technically not needed for regular SM5 compiled with legacy compiler,
// but PCD3D_SM5 currently includes ray tracing shaders that are compiled with new compiler stack.
return HashCombine(DxcVersionHash, ShaderModelHash);
}
else if (Format == NAME_PCD3D_ES3_1)
{
// Shader DXC signature is intentionally not included, as ES3_1 target always uses legacy compiler.
return GetVersionHash(UE_SHADER_PCD3D_ES3_1_VER);
}
else if (Format == NAME_D3D_ES3_1_HOLOLENS)
{
// Shader DXC signature is intentionally not included, as ES3_1 target always uses legacy compiler.
return GetVersionHash(UE_SHADER_D3D_ES3_1_HOLOLENS_VER);
}
checkf(0, TEXT("Unknown Format %s"), *Format.ToString());
return 0;
}
virtual void GetSupportedFormats(TArray<FName>& OutFormats) const
{
OutFormats.Add(NAME_PCD3D_SM6);
OutFormats.Add(NAME_PCD3D_SM5);
OutFormats.Add(NAME_PCD3D_ES3_1);
OutFormats.Add(NAME_D3D_ES3_1_HOLOLENS);
}
virtual void CompileShader(FName Format, const struct FShaderCompilerInput& Input, struct FShaderCompilerOutput& Output,const FString& WorkingDirectory) const
{
CheckFormat(Format);
if (Format == NAME_PCD3D_SM6)
{
CompileShader_Windows(Input, Output, WorkingDirectory, ELanguage::SM6);
}
else if(Format == NAME_PCD3D_SM5)
{
CompileShader_Windows(Input, Output, WorkingDirectory, ELanguage::SM5);
}
else if (Format == NAME_PCD3D_ES3_1)
{
CompileShader_Windows(Input, Output, WorkingDirectory, ELanguage::ES3_1);
}
else if (Format == NAME_D3D_ES3_1_HOLOLENS)
{
CompileShader_Windows(Input, Output, WorkingDirectory, ELanguage::ES3_1);
}
else
{
checkf(0, TEXT("Unknown format %s"), *Format.ToString());
}
}
void AddShaderTargetDefines(FShaderCompilerInput& Input, uint32 ShaderTargetMajor, uint32 ShaderTargetMinor) const
{
// Inserting our own versions of these defines since we preprocess our shader source before we actually use something that defines them.
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MAJOR"), ShaderTargetMajor);
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MINOR"), ShaderTargetMinor);
}
void ModifyShaderCompilerInput(FShaderCompilerInput& Input) const final
{
CheckFormat(Input.ShaderFormat);
if (Input.ShaderFormat == NAME_PCD3D_SM6 || Input.IsRayTracingShader())
{
Input.Environment.SetDefine(TEXT("SM6_PROFILE"), 1);
Input.Environment.SetDefine(TEXT("COMPILER_DXC"), 1);
Input.Environment.SetDefine(TEXT("PLATFORM_SUPPORTS_UB_STRUCT"), 1);
if (USE_SHADER_MODEL_6_6)
{
AddShaderTargetDefines(Input, 6, 6);
}
else
{
AddShaderTargetDefines(Input, 6, 5);
}
}
else if (Input.ShaderFormat == NAME_PCD3D_SM5)
{
Input.Environment.SetDefine(TEXT("SM5_PROFILE"), 1);
const bool bUseDXC =
Input.Environment.CompilerFlags.Contains(CFLAG_WaveOperations)
|| Input.Environment.CompilerFlags.Contains(CFLAG_ForceDXC);
Input.Environment.SetDefine(TEXT("COMPILER_DXC"), bUseDXC);
if (bUseDXC)
{
AddShaderTargetDefines(Input, 6, 0);
}
else
{
AddShaderTargetDefines(Input, 5, 0);
}
}
else if (Input.ShaderFormat == NAME_PCD3D_ES3_1)
{
Input.Environment.SetDefine(TEXT("ES3_1_PROFILE"), 1);
Input.Environment.SetDefine(TEXT("COMPILER_DXC"), 0);
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MAJOR"), 5);
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MINOR"), 0);
}
else if (Input.ShaderFormat == NAME_D3D_ES3_1_HOLOLENS)
{
Input.Environment.SetDefine(TEXT("ES3_1_PROFILE"), 1);
Input.Environment.SetDefine(TEXT("COMPILER_DXC"), 0);
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MAJOR"), 5);
Input.Environment.SetDefine(TEXT("__SHADER_TARGET_MINOR"), 0);
}
else
{
checkf(0, TEXT("Unknown format %s"), *Input.ShaderFormat.ToString());
}
}
virtual const TCHAR* GetPlatformIncludeDirectory() const
{
return TEXT("D3D");
}
};
/**
* Module for D3D shaders
*/
static IShaderFormat* Singleton = nullptr;
class FShaderFormatD3DModule : public IShaderFormatModule, public FDxcModuleWrapper
{
public:
virtual ~FShaderFormatD3DModule()
{
delete Singleton;
Singleton = nullptr;
}
virtual IShaderFormat* GetShaderFormat()
{
if (!Singleton)
{
Singleton = new FShaderFormatD3D(FDxcModuleWrapper::GetModuleVersionHash());
}
return Singleton;
}
};
IMPLEMENT_MODULE( FShaderFormatD3DModule, ShaderFormatD3D);