You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Refactor SPIR-V patching and strip debug instructions for Vulkan mobile except OpName instructions in --strip-reflect pass as UE always needs this reflection information.
Rebuild ShaderConductor for Win64, Mac, Linux. #rb Carl.Lloyd, Rolando.Caloca, Ryan.Vance #fyi Mihnea.Balta, Will.Damon, Dmitriy.Dyomin, Michael.Sartain, Brandon.Schaefer #jira none #rnx [CL 16186169 by Lukas Hermanns in ue5-main branch]
This commit is contained in:
@@ -24,7 +24,6 @@ THIRD_PARTY_INCLUDES_START
|
||||
#include "SPIRV/GLSL.std.450.h"
|
||||
#include "SPIRV/doc.h"
|
||||
#include "SPIRV/disassemble.h"
|
||||
#include "SPIRV/spirv.hpp"
|
||||
THIRD_PARTY_INCLUDES_END
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
@@ -166,33 +165,8 @@ static EShLanguage GetStage(EHlslShaderFrequency Frequency)
|
||||
return EShLangCount;
|
||||
}
|
||||
|
||||
static void ComputeMovableWordIndices(FVulkanSpirv& Spirv)
|
||||
void PatchSpirvReflectionEntries(FVulkanSpirv& Spirv)
|
||||
{
|
||||
// SPIRV Header
|
||||
const uint32* PtrStart = Spirv.Data.GetData();
|
||||
const uint32* Ptr = PtrStart;
|
||||
const uint32* PtrEnd = Spirv.Data.GetData() + Spirv.Data.Num();
|
||||
const uint32_t MagicNumberValue = *Ptr++;
|
||||
check(MagicNumberValue == spv::MagicNumber);
|
||||
uint32_t Version = *Ptr++;
|
||||
uint32_t Generator = *Ptr++;
|
||||
uint32_t Bound = *Ptr++;
|
||||
const uint32_t ZeroCheckValue = *Ptr++;
|
||||
check(ZeroCheckValue == 0);
|
||||
|
||||
auto ReadLiteralString = [](const uint32_t* Ptr)
|
||||
{
|
||||
FString S;
|
||||
const char* Str = (const char*)Ptr;
|
||||
// Empty string is allowed...
|
||||
while (*Str)
|
||||
{
|
||||
S += *Str;
|
||||
++Str;
|
||||
}
|
||||
return S;
|
||||
};
|
||||
|
||||
TMap<uint32, FString> Names;
|
||||
struct FDecorations
|
||||
{
|
||||
@@ -204,57 +178,38 @@ static void ComputeMovableWordIndices(FVulkanSpirv& Spirv)
|
||||
TMap<uint32, FDecorations> Decorations;
|
||||
TMap<uint32, uint32> TypePointerUniforms;
|
||||
TMap<uint32, uint32> VariableUniformTypes;
|
||||
bool bFoundEntry = false;
|
||||
while (Ptr < PtrEnd)
|
||||
|
||||
bool bDone = false;
|
||||
for (FSpirvConstIterator Iter = Spirv.cbegin(); Iter != Spirv.cend() && !bDone; ++Iter)
|
||||
{
|
||||
uint32_t WordCount = (*Ptr >> spv::WordCountShift) & spv::OpCodeMask;
|
||||
spv::Op OpCode = (spv::Op)(*Ptr & spv::OpCodeMask);
|
||||
switch (OpCode)
|
||||
switch (Iter.Opcode())
|
||||
{
|
||||
case spv::OpEntryPoint:
|
||||
{
|
||||
uint32 ExecModel = Ptr[1];
|
||||
uint32 EntryPoint = Ptr[2];
|
||||
FString Name = ReadLiteralString(Ptr + 3);
|
||||
if (Name == TEXT("main_00000000_00000000"))
|
||||
{
|
||||
check(Spirv.OffsetToEntryPoint == 0);
|
||||
Spirv.OffsetToEntryPoint = (uint32)(&Ptr[3] - PtrStart);
|
||||
bFoundEntry = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case spv::OpName:
|
||||
{
|
||||
uint32 TargetId = Ptr[1];
|
||||
FString Name = ReadLiteralString(Ptr + 2);
|
||||
if (Name == TEXT("main_00000000_00000000"))
|
||||
{
|
||||
check(Spirv.OffsetToMainName == 0);
|
||||
Spirv.OffsetToMainName = (uint32)(&Ptr[2] - PtrStart);
|
||||
}
|
||||
Names.Add(TargetId, Name);
|
||||
}
|
||||
break;
|
||||
case spv::OpDecorate:
|
||||
case SpvOpName:
|
||||
{
|
||||
uint32 TargetId = Ptr[1];
|
||||
spv::Decoration Decoration = (spv::Decoration)Ptr[2];
|
||||
uint32 TargetId = Iter.Operand(1);
|
||||
FString Name = ANSI_TO_TCHAR(Iter.OperandAsString(2));
|
||||
Names.Add(TargetId, MoveTemp(Name));
|
||||
}
|
||||
break;
|
||||
case SpvOpDecorate:
|
||||
{
|
||||
uint32 TargetId = Iter.Operand(1);
|
||||
SpvDecoration Decoration = Iter.OperandAs<SpvDecoration>(2);
|
||||
switch (Decoration)
|
||||
{
|
||||
case spv::DecorationDescriptorSet:
|
||||
case SpvDecorationDescriptorSet:
|
||||
{
|
||||
uint32 Value = Ptr[3];
|
||||
uint32 WordValueIndex = (uint32)(&Ptr[3] - PtrStart);
|
||||
uint32 Value = Iter.Operand(3);
|
||||
uint32 WordValueIndex = Spirv.GetWordOffset(Iter, 3);
|
||||
FDecorations& UBDecoration = Decorations.FindOrAdd(TargetId);
|
||||
UBDecoration.DescriptorSet = Value;
|
||||
UBDecoration.WordDescriptorSet = WordValueIndex;
|
||||
break;
|
||||
}
|
||||
case spv::DecorationBinding:
|
||||
case SpvDecorationBinding:
|
||||
{
|
||||
uint32 Value = Ptr[3];
|
||||
uint32 WordValueIndex = (uint32)(&Ptr[3] - PtrStart);
|
||||
uint32 Value = Iter.Operand(3);
|
||||
uint32 WordValueIndex = Spirv.GetWordOffset(Iter, 3);
|
||||
FDecorations& UBDecoration = Decorations.FindOrAdd(TargetId);
|
||||
UBDecoration.BindingIndex = Value;
|
||||
UBDecoration.WordBindingIndex = WordValueIndex;
|
||||
@@ -265,37 +220,36 @@ static void ComputeMovableWordIndices(FVulkanSpirv& Spirv)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case spv::OpTypePointer:
|
||||
case SpvOpTypePointer:
|
||||
{
|
||||
uint32 Result = Ptr[1];
|
||||
spv::StorageClass Storage = (spv::StorageClass)Ptr[2];
|
||||
if (Storage == spv::StorageClassUniform || Storage == spv::StorageClassUniformConstant)
|
||||
uint32 Result = Iter.Operand(1);
|
||||
SpvStorageClass Storage = Iter.OperandAs<SpvStorageClass>(2);
|
||||
if (Storage == SpvStorageClassUniform || Storage == SpvStorageClassUniformConstant)
|
||||
{
|
||||
uint32 Type = Ptr[3];
|
||||
uint32 Type = Iter.Operand(3);
|
||||
TypePointerUniforms.Add(Result, Type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case spv::OpVariable:
|
||||
case SpvOpVariable:
|
||||
{
|
||||
uint32 Type = Ptr[1];
|
||||
uint32 Id = Ptr[2];
|
||||
spv::StorageClass Storage = (spv::StorageClass)Ptr[3];
|
||||
if (Storage == spv::StorageClassUniform || Storage == spv::StorageClassUniformConstant)
|
||||
uint32 Type = Iter.Operand(1);
|
||||
uint32 Id = Iter.Operand(2);
|
||||
SpvStorageClass Storage = Iter.OperandAs<SpvStorageClass>(3);
|
||||
if (Storage == SpvStorageClassUniform || Storage == SpvStorageClassUniformConstant)
|
||||
{
|
||||
VariableUniformTypes.Add(Id, Type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SpvOpFunction:
|
||||
bDone = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Ptr += WordCount;
|
||||
}
|
||||
|
||||
check(bFoundEntry);
|
||||
|
||||
// Go through all found uniform variables and make sure we found the right info
|
||||
for (const auto& Pair : VariableUniformTypes)
|
||||
{
|
||||
@@ -335,25 +289,6 @@ static void ComputeMovableWordIndices(FVulkanSpirv& Spirv)
|
||||
}
|
||||
}
|
||||
|
||||
static void PatchSpirvEntryPoint(FVulkanSpirv& OutSpirv, uint32 OffsetToName)
|
||||
{
|
||||
char* EntryPointName = (char*)(OutSpirv.Data.GetData() + OffsetToName);
|
||||
check(!FCStringAnsi::Strcmp(EntryPointName, "main_00000000_00000000"));
|
||||
FCStringAnsi::Sprintf(EntryPointName, "main_%0.8x_%0.8x", OutSpirv.Data.Num() * sizeof(uint32), OutSpirv.CRC);
|
||||
};
|
||||
|
||||
bool PatchSpirvReflectionEntriesAndEntryPoint(FVulkanSpirv& OutSpirv)
|
||||
{
|
||||
// Re-compute movable word indices and update CRC code
|
||||
ComputeMovableWordIndices(OutSpirv);
|
||||
OutSpirv.CRC = FCrc::MemCrc32(OutSpirv.Data.GetData(), OutSpirv.Data.Num() * sizeof(uint32));
|
||||
|
||||
// Patch the entry point name
|
||||
PatchSpirvEntryPoint(OutSpirv, OutSpirv.OffsetToMainName);
|
||||
PatchSpirvEntryPoint(OutSpirv, OutSpirv.OffsetToEntryPoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GenerateSpirv(const ANSICHAR* Source, FCompilerInfo& CompilerInfo, FString& OutErrors, const FString& DumpDebugInfoPath, FVulkanSpirv& OutSpirv)
|
||||
{
|
||||
glslang::TProgram* Program = new glslang::TProgram;
|
||||
@@ -444,7 +379,8 @@ bool GenerateSpirv(const ANSICHAR* Source, FCompilerInfo& CompilerInfo, FString&
|
||||
OutSpirv.ReflectionInfo.Add(Entry);
|
||||
}
|
||||
|
||||
PatchSpirvReflectionEntriesAndEntryPoint(OutSpirv);
|
||||
PatchSpirvReflectionEntries(OutSpirv);
|
||||
OutSpirv.EntryPointName = PatchSpirvEntryPointWithCRC(OutSpirv, OutSpirv.CRC);
|
||||
|
||||
// Copy back to original spirv data as it is used for dumping information
|
||||
FMemory::Memcpy(&Spirv[0], OutSpirv.Data.GetData(), SizeInWords * sizeof(uint32));
|
||||
|
||||
@@ -9,21 +9,6 @@
|
||||
#include "hlslcc.h"
|
||||
#include "SpirvReflectCommon.h"
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
|
||||
THIRD_PARTY_INCLUDES_START
|
||||
#include "SPIRV/GlslangToSpv.h"
|
||||
#include "SPIRV/doc.h"
|
||||
#include "SPIRV/disassemble.h"
|
||||
THIRD_PARTY_INCLUDES_END
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
// For excpt.h
|
||||
#include <D3Dcompiler.h>
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
#endif
|
||||
#endif // PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
|
||||
|
||||
#if PLATFORM_MAC
|
||||
// Horrible hack as we need the enum available but the Vulkan headers do not compile on Mac
|
||||
enum VkDescriptorType {
|
||||
@@ -1563,7 +1548,7 @@ static void BuildShaderOutput(
|
||||
{
|
||||
if (IsVulkanMobilePlatform((EShaderPlatform)ShaderInput.Target.Platform))
|
||||
{
|
||||
CompileOfflineMali(ShaderInput, ShaderOutput, (const ANSICHAR*)Spirv.GetByteData(), Spirv.GetByteSize(), true, (const ANSICHAR*)(Spirv.GetByteData() + Spirv.OffsetToMainName));
|
||||
CompileOfflineMali(ShaderInput, ShaderOutput, (const ANSICHAR*)Spirv.GetByteData(), Spirv.GetByteSize(), true, Spirv.EntryPointName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1919,15 +1904,17 @@ static void GatherSpirvReflectionBindings(
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildShaderOutputFromSpirv(
|
||||
FVulkanSpirv& Spirv,
|
||||
const FShaderCompilerInput& Input,
|
||||
FShaderCompilerOutput& Output,
|
||||
FVulkanBindingTable& BindingTable,
|
||||
const FString& EntryPointName,
|
||||
bool bHasRealUBs,
|
||||
bool bDebugDump,
|
||||
bool bIsRayTracingShader)
|
||||
static bool BuildShaderOutputFromSpirv(
|
||||
CrossCompiler::FShaderConductorContext& CompilerContext,
|
||||
FVulkanSpirv& Spirv,
|
||||
const FShaderCompilerInput& Input,
|
||||
FShaderCompilerOutput& Output,
|
||||
FVulkanBindingTable& BindingTable,
|
||||
const FString& EntryPointName,
|
||||
bool bHasRealUBs,
|
||||
bool bStripReflect,
|
||||
bool bIsRayTracingShader,
|
||||
bool bDebugDump)
|
||||
{
|
||||
FShaderParameterMap& ParameterMap = Output.ParameterMap;
|
||||
|
||||
@@ -2299,7 +2286,20 @@ static void BuildShaderOutputFromSpirv(
|
||||
|
||||
// Overwrite updated SPIRV code
|
||||
Spirv.Data = TArray<uint32>(Reflection.GetCode(), Reflection.GetCodeSize() / 4);
|
||||
PatchSpirvReflectionEntriesAndEntryPoint(Spirv);
|
||||
|
||||
// We have to strip out most debug instructions (except OpName) for Vulkan mobile
|
||||
if (bStripReflect)
|
||||
{
|
||||
const char* OptArgs[] = { "--strip-reflect" };
|
||||
if (!CompilerContext.OptimizeSpirv(Spirv.Data, OptArgs, UE_ARRAY_COUNT(OptArgs)))
|
||||
{
|
||||
UE_LOG(LogVulkanShaderCompiler, Error, TEXT("Failed to strip debug instructions from SPIR-V module"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PatchSpirvReflectionEntries(Spirv);
|
||||
Spirv.EntryPointName = PatchSpirvEntryPointWithCRC(Spirv, Spirv.CRC);
|
||||
|
||||
BuildShaderOutput(
|
||||
Output,
|
||||
@@ -2321,6 +2321,8 @@ static void BuildShaderOutputFromSpirv(
|
||||
DumpDebugShaderBinary(Input, Spirv.GetByteData(), Spirv.GetByteSize(), TEXT("spv"));
|
||||
DumpDebugShaderDisassembledSpirv(Input, Spirv.GetByteData(), Spirv.GetByteSize(), TEXT("spvasm"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CompileWithShaderConductor(
|
||||
@@ -2330,7 +2332,8 @@ static bool CompileWithShaderConductor(
|
||||
EHlslCompileTarget HlslCompilerTarget,
|
||||
FShaderCompilerOutput& Output,
|
||||
FVulkanBindingTable& BindingTable,
|
||||
bool bHasRealUBs)
|
||||
bool bHasRealUBs,
|
||||
bool bStripReflect)
|
||||
{
|
||||
const FShaderCompilerInput& Input = CompilerInfo.Input;
|
||||
|
||||
@@ -2384,15 +2387,13 @@ static bool CompileWithShaderConductor(
|
||||
}
|
||||
|
||||
// Build shader output and binding table
|
||||
BuildShaderOutputFromSpirv(Spirv, Input, Output, BindingTable, EntryPointName, bHasRealUBs, bDebugDump, bIsRayTracingShader);
|
||||
Output.bSucceeded = BuildShaderOutputFromSpirv(CompilerContext, Spirv, Input, Output, BindingTable, EntryPointName, bHasRealUBs, bStripReflect, bIsRayTracingShader, bDebugDump);
|
||||
|
||||
if (Input.Environment.CompilerFlags.Contains(CFLAG_KeepDebugInfo))
|
||||
{
|
||||
Output.ShaderCode.AddOptionalData(FShaderCodeName::Key, TCHAR_TO_UTF8(*Input.GenerateShaderName()));
|
||||
}
|
||||
|
||||
Output.bSucceeded = true;
|
||||
|
||||
if (bDebugDump)
|
||||
{
|
||||
DumpDebugShaderBinary(Input, Spirv.GetByteData(), Spirv.GetByteSize(), TEXT("spv"));
|
||||
@@ -2414,6 +2415,7 @@ void DoCompileVulkanShader(const FShaderCompilerInput& Input, FShaderCompilerOut
|
||||
const bool bHasRealUBs = !Input.Environment.CompilerFlags.Contains(CFLAG_UseEmulatedUB);
|
||||
const bool bIsSM5 = (Version == EVulkanShaderVersion::SM5);
|
||||
const bool bIsMobile = (Version == EVulkanShaderVersion::ES3_1 || Version == EVulkanShaderVersion::ES3_1_ANDROID);
|
||||
const bool bStripReflect = (IsVulkanMobilePlatform(ShaderPlatform) || IsVulkanMobileSM5Platform(ShaderPlatform));
|
||||
const bool bForceDXC = Input.Environment.CompilerFlags.Contains(CFLAG_ForceDXC);
|
||||
|
||||
const EHlslShaderFrequency FrequencyTable[] =
|
||||
@@ -2564,7 +2566,7 @@ void DoCompileVulkanShader(const FShaderCompilerInput& Input, FShaderCompilerOut
|
||||
if (bForceDXC)
|
||||
{
|
||||
// Cross-compile shader via ShaderConductor (DXC, SPIRV-Tools, SPIRV-Cross)
|
||||
bSuccess = CompileWithShaderConductor(PreprocessedShaderSource, EntryPointName, CompilerInfo, HlslCompilerTarget, Output, BindingTable, bHasRealUBs);
|
||||
bSuccess = CompileWithShaderConductor(PreprocessedShaderSource, EntryPointName, CompilerInfo, HlslCompilerTarget, Output, BindingTable, bHasRealUBs, bStripReflect);
|
||||
}
|
||||
else
|
||||
#endif // PLATFORM_MAC || PLATFORM_WINDOWS || PLATFORM_LINUX
|
||||
|
||||
@@ -52,10 +52,10 @@ struct FVulkanSpirv : FSpirv
|
||||
// Index into the Spirv Word containing the binding index decoration
|
||||
uint32 WordBindingIndex = UINT32_MAX;
|
||||
};
|
||||
|
||||
TArray<FEntry> ReflectionInfo;
|
||||
uint32 OffsetToMainName = 0;
|
||||
uint32 OffsetToEntryPoint = 0;
|
||||
uint32 CRC = 0;
|
||||
const ANSICHAR* EntryPointName = nullptr;
|
||||
|
||||
int32 FindBinding(const FString& Name, bool bOuter = false) const
|
||||
{
|
||||
@@ -135,7 +135,7 @@ struct FVulkanSpirv : FSpirv
|
||||
};
|
||||
|
||||
// Updates all reflection entries in the specified SPIR-V module.
|
||||
extern bool PatchSpirvReflectionEntriesAndEntryPoint(FVulkanSpirv& OutSpirv);
|
||||
extern void PatchSpirvReflectionEntries(FVulkanSpirv& OutSpirv);
|
||||
|
||||
// Generates SPIR-V out of the specified GLSL source code.
|
||||
extern bool GenerateSpirv(const ANSICHAR* Source, FCompilerInfo& CompilerInfo, FString& OutErrors, const FString& DumpDebugInfoPath, FVulkanSpirv& OutSpirv);
|
||||
|
||||
Reference in New Issue
Block a user