diff --git a/llvm/include/llvm/BinaryFormat/DXContainer.h b/llvm/include/llvm/BinaryFormat/DXContainer.h --- a/llvm/include/llvm/BinaryFormat/DXContainer.h +++ b/llvm/include/llvm/BinaryFormat/DXContainer.h @@ -131,6 +131,13 @@ #include "DXContainerConstants.def" }; +#define SHADER_FLAG(Num, Val, Str) Val = 1ull << Num, +enum class FeatureFlags : uint64_t { +#include "DXContainerConstants.def" +}; +static_assert((uint64_t)FeatureFlags::NextUnusedBit <= 1ull << 63, + "Shader flag bits exceed enum size."); + PartType parsePartType(StringRef S); } // namespace dxbc diff --git a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def --- a/llvm/include/llvm/BinaryFormat/DXContainerConstants.def +++ b/llvm/include/llvm/BinaryFormat/DXContainerConstants.def @@ -1,6 +1,46 @@ #ifdef CONTAINER_PART CONTAINER_PART(DXIL) +CONTAINER_PART(SFI0) #undef CONTAINER_PART #endif + +#ifdef SHADER_FLAG + +SHADER_FLAG(0, Doubles, "Double-precision floating point") +SHADER_FLAG(1, ComputeShadersPlusRawAndStructuredBuffers, "Raw and Structured buffers") +SHADER_FLAG(2, UAVsAtEveryStage, "UAVs at every shader stage") +SHADER_FLAG(3, Max64UAVs, "64 UAV slots") +SHADER_FLAG(4, MinimumPrecision, "Minimum-precision data types") +SHADER_FLAG(5, DX11_1_DoubleExtensions, "Double-precision extensions for 11.1") +SHADER_FLAG(6, DX11_1_ShaderExtensions, "Shader extensions for 11.1") +SHADER_FLAG(7, LEVEL9ComparisonFiltering, "Comparison filtering for feature level 9") +SHADER_FLAG(8, TiledResources, "Tiled resources") +SHADER_FLAG(9, StencilRef, "PS Output Stencil Ref") +SHADER_FLAG(10, InnerCoverage, "PS Inner Coverage") +SHADER_FLAG(11, TypedUAVLoadAdditionalFormats, "Typed UAV Load Additional Formats") +SHADER_FLAG(12, ROVs, "Raster Ordered UAVs") +SHADER_FLAG(13, ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer, "SV_RenderTargetArrayIndex or SV_ViewportArrayIndex from any shader feeding rasterizer") +SHADER_FLAG(14, WaveOps, "Wave level operations") +SHADER_FLAG(15, Int64Ops, "64-Bit integer") +SHADER_FLAG(16, ViewID, "View Instancing") +SHADER_FLAG(17, Barycentrics, "Barycentrics") +SHADER_FLAG(18, NativeLowPrecision, "Use native low precision") +SHADER_FLAG(19, ShadingRate, "Shading Rate") +SHADER_FLAG(20, Raytracing_Tier_1_1, "Raytracing tier 1.1 features") +SHADER_FLAG(21, SamplerFeedback, "Sampler feedback") +SHADER_FLAG(22, AtomicInt64OnTypedResource, "64-bit Atomics on Typed Resources") +SHADER_FLAG(23, AtomicInt64OnGroupShared, "64-bit Atomics on Group Shared") +SHADER_FLAG(24, DerivativesInMeshAndAmpShaders, "Derivatives in mesh and amplification shaders") +SHADER_FLAG(25, ResourceDescriptorHeapIndexing, "Resource descriptor heap indexing") +SHADER_FLAG(26, SamplerDescriptorHeapIndexing, "Sampler descriptor heap indexing") +SHADER_FLAG(27, RESERVED, "") +SHADER_FLAG(28, AtomicInt64OnHeapResource, "64-bit Atomics on Heap Resources") +SHADER_FLAG(29, AdvancedTextureOps, "Advanced Texture Ops") +SHADER_FLAG(30, WriteableMSAATextures, "Writeable MSAA Textures") + +SHADER_FLAG(31, NextUnusedBit, "Next reserved shader flag bit (not a flag)") + +#undef SHADER_FLAG +#endif diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h --- a/llvm/include/llvm/Object/DXContainer.h +++ b/llvm/include/llvm/Object/DXContainer.h @@ -35,10 +35,12 @@ dxbc::Header Header; SmallVector PartOffsets; Optional DXIL; + Optional ShaderFlags; Error parseHeader(); Error parsePartOffsets(); Error parseDXILHeader(uint32_t Offset); + Error parseShaderFlags(uint32_t Offset); friend class PartIterator; public: @@ -116,6 +118,8 @@ const dxbc::Header &getHeader() const { return Header; } Optional getDXIL() const { return DXIL; } + + Optional getShaderFlags() const { return ShaderFlags; } }; } // namespace object diff --git a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h --- a/llvm/include/llvm/ObjectYAML/DXContainerYAML.h +++ b/llvm/include/llvm/ObjectYAML/DXContainerYAML.h @@ -53,12 +53,21 @@ Optional> DXIL; }; +#define SHADER_FLAG(Num, Val, Str) bool Val = false; +struct ShaderFlags { + ShaderFlags() = default; + ShaderFlags(uint64_t FlagData); + uint64_t getEncodedFlags(); +#include "llvm/BinaryFormat/DXContainerConstants.def" +}; + struct Part { Part() = default; Part(std::string N, uint32_t S) : Name(N), Size(S) {} std::string Name; uint32_t Size; Optional Program; + Optional Flags; }; struct Object { @@ -88,6 +97,10 @@ static void mapping(IO &IO, DXContainerYAML::DXILProgram &Program); }; +template <> struct MappingTraits { + static void mapping(IO &IO, DXContainerYAML::ShaderFlags &Flags); +}; + template <> struct MappingTraits { static void mapping(IO &IO, DXContainerYAML::Part &Version); }; diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp --- a/llvm/lib/Object/DXContainer.cpp +++ b/llvm/lib/Object/DXContainer.cpp @@ -34,13 +34,17 @@ static Error readInteger(StringRef Buffer, const char *Src, T &Val) { static_assert(std::is_integral::value, "Cannot call readInteger on non-integral type."); - assert(reinterpret_cast(Src) % alignof(T) == 0 && - "Unaligned read of value from buffer!"); // Don't read before the beginning or past the end of the file if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end()) return parseFailed("Reading structure out of file bounds"); - Val = *reinterpret_cast(Src); + // The DXContainer offset table is comprised of uint32_t values but not padded + // to a 64-bit boundary. So Parts may start unaligned if there is an odd + // number of parts and part data itself is not required to be padded. + if (reinterpret_cast(Src) % alignof(T) != 0) + memcpy(reinterpret_cast(&Val), Src, sizeof(T)); + else + Val = *reinterpret_cast(Src); // DXContainer is always little endian if (sys::IsBigEndianHost) sys::swapByteOrder(Val); @@ -65,6 +69,17 @@ return Error::success(); } +Error DXContainer::parseShaderFlags(uint32_t Offset) { + if (ShaderFlags) + return parseFailed("More than one SFI0 part is present in the file"); + const char *Current = Data.getBuffer().data() + Offset; + uint64_t FlagValue = 0; + if (Error Err = readInteger(Data.getBuffer(), Current, FlagValue)) + return Err; + ShaderFlags = FlagValue; + return Error::success(); +} + Error DXContainer::parsePartOffsets() { const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header); for (uint32_t Part = 0; Part < Header.PartCount; ++Part) { @@ -88,6 +103,10 @@ if (Error Err = parseDXILHeader(PartOffset + sizeof(dxbc::PartHeader))) return Err; break; + case dxbc::PartType::SFI0: + if (Error Err = parseShaderFlags(PartOffset + sizeof(dxbc::PartHeader))) + return Err; + break; case dxbc::PartType::Unknown: break; } diff --git a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp --- a/llvm/lib/ObjectYAML/DXContainerEmitter.cpp +++ b/llvm/lib/ObjectYAML/DXContainerEmitter.cpp @@ -114,13 +114,20 @@ OS.write_zeros(PadBytes); } DXContainerYAML::Part P = std::get<0>(I); + RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader); + uint32_t PartSize = P.Size; + OS.write(P.Name.c_str(), 4); if (sys::IsBigEndianHost) sys::swapByteOrder(P.Size); OS.write(reinterpret_cast(&P.Size), sizeof(uint32_t)); - RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader); - if (P.Name == "DXIL" && P.Program) { + dxbc::PartType PT = dxbc::parsePartType(P.Name); + + uint64_t DataStart = OS.tell(); + if (PT == dxbc::PartType::DXIL) { + if (!P.Program) + continue; dxbc::ProgramHeader Header; Header.MajorVersion = P.Program->MajorVersion; Header.MinorVersion = P.Program->MinorVersion; @@ -160,7 +167,21 @@ OS.write(reinterpret_cast(P.Program->DXIL->data()), P.Program->DXIL->size()); } + } else if (PT == dxbc::PartType::SFI0) { + // If we don't have any flags we can continue here and the data will be + // zeroed out. + if (!P.Flags.has_value()) + continue; + uint64_t Flags = P.Flags->getEncodedFlags(); + if (sys::IsBigEndianHost) + sys::swapByteOrder(Flags); + OS.write(reinterpret_cast(&Flags), sizeof(uint64_t)); } + uint64_t BytesWritten = OS.tell() - DataStart; + RollingOffset += BytesWritten; + if (BytesWritten < PartSize) + OS.write_zeros(PartSize - BytesWritten); + RollingOffset += PartSize; } } diff --git a/llvm/lib/ObjectYAML/DXContainerYAML.cpp b/llvm/lib/ObjectYAML/DXContainerYAML.cpp --- a/llvm/lib/ObjectYAML/DXContainerYAML.cpp +++ b/llvm/lib/ObjectYAML/DXContainerYAML.cpp @@ -12,8 +12,30 @@ //===----------------------------------------------------------------------===// #include "llvm/ObjectYAML/DXContainerYAML.h" +#include "llvm/BinaryFormat/DXContainer.h" namespace llvm { + +// This assert is duplicated here to leave a breadcrumb of the places that need +// to be updated if flags grow past 64-bits. +static_assert((uint64_t)dxbc::FeatureFlags::NextUnusedBit <= 1ull << 63, + "Shader flag bits exceed enum size."); + +DXContainerYAML::ShaderFlags::ShaderFlags(uint64_t FlagData) { +#define SHADER_FLAG(Num, Val, Str) \ + Val = (FlagData & (uint64_t)dxbc::FeatureFlags::Val) > 0; +#include "llvm/BinaryFormat/DXContainerConstants.def" +} + +uint64_t DXContainerYAML::ShaderFlags::getEncodedFlags() { + uint64_t Flag = 0; +#define SHADER_FLAG(Num, Val, Str) \ + if (Val) \ + Flag |= (uint64_t)dxbc::FeatureFlags::Val; +#include "llvm/BinaryFormat/DXContainerConstants.def" + return Flag; +} + namespace yaml { void MappingTraits::mapping( @@ -43,11 +65,18 @@ IO.mapOptional("DXIL", Program.DXIL); } +void MappingTraits::mapping( + IO &IO, DXContainerYAML::ShaderFlags &Flags) { +#define SHADER_FLAG(Num, Val, Str) IO.mapRequired(#Val, Flags.Val); +#include "llvm/BinaryFormat/DXContainerConstants.def" +} + void MappingTraits::mapping(IO &IO, DXContainerYAML::Part &P) { IO.mapRequired("Name", P.Name); IO.mapRequired("Size", P.Size); IO.mapOptional("Program", P.Program); + IO.mapOptional("Flags", P.Flags); } void MappingTraits::mapping( diff --git a/llvm/test/tools/obj2yaml/DXContainer/ShaderFlags.yaml b/llvm/test/tools/obj2yaml/DXContainer/ShaderFlags.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/DXContainer/ShaderFlags.yaml @@ -0,0 +1,97 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s + +# This test verifies that shader flags are omitted if they are all off. +--- !dxcontainer +Header: + Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ] + Version: + Major: 1 + Minor: 0 + PartCount: 7 +Parts: + - Name: SFI0 + Size: 8 + Flags: + Doubles: true + ComputeShadersPlusRawAndStructuredBuffers: false + UAVsAtEveryStage: true + Max64UAVs: false + MinimumPrecision: true + DX11_1_DoubleExtensions: false + DX11_1_ShaderExtensions: true + LEVEL9ComparisonFiltering: true + TiledResources: false + StencilRef: true + InnerCoverage: true + TypedUAVLoadAdditionalFormats: false + ROVs: false + ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer: true + WaveOps: false + Int64Ops: false + ViewID: true + Barycentrics: false + NativeLowPrecision: false + ShadingRate: false + Raytracing_Tier_1_1: true + SamplerFeedback: false + AtomicInt64OnTypedResource: false + AtomicInt64OnGroupShared: false + DerivativesInMeshAndAmpShaders: true + ResourceDescriptorHeapIndexing: false + SamplerDescriptorHeapIndexing: false + RESERVED: true + AtomicInt64OnHeapResource: false + AdvancedTextureOps: true + WriteableMSAATextures: false + NextUnusedBit: true + - Name: ISG1 + Size: 8 + - Name: OSG1 + Size: 8 + - Name: PSV0 + Size: 8 + - Name: STAT + Size: 8 + - Name: HASH + Size: 8 + - Name: CXIL + Size: 8 +... + +# CHECK: Parts: +# CHECK-NEXT: - Name: SFI0 +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Flags: +# CHECK-NEXT: Doubles: true +# CHECK-NEXT: ComputeShadersPlusRawAndStructuredBuffers: false +# CHECK-NEXT: UAVsAtEveryStage: true +# CHECK-NEXT: Max64UAVs: false +# CHECK-NEXT: MinimumPrecision: true +# CHECK-NEXT: DX11_1_DoubleExtensions: false +# CHECK-NEXT: DX11_1_ShaderExtensions: true +# CHECK-NEXT: LEVEL9ComparisonFiltering: true +# CHECK-NEXT: TiledResources: false +# CHECK-NEXT: StencilRef: true +# CHECK-NEXT: InnerCoverage: true +# CHECK-NEXT: TypedUAVLoadAdditionalFormats: false +# CHECK-NEXT: ROVs: false +# CHECK-NEXT: ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer: true +# CHECK-NEXT: WaveOps: false +# CHECK-NEXT: Int64Ops: false +# CHECK-NEXT: ViewID: true +# CHECK-NEXT: Barycentrics: false +# CHECK-NEXT: NativeLowPrecision: false +# CHECK-NEXT: ShadingRate: false +# CHECK-NEXT: Raytracing_Tier_1_1: true +# CHECK-NEXT: SamplerFeedback: false +# CHECK-NEXT: AtomicInt64OnTypedResource: false +# CHECK-NEXT: AtomicInt64OnGroupShared: false +# CHECK-NEXT: DerivativesInMeshAndAmpShaders: true +# CHECK-NEXT: ResourceDescriptorHeapIndexing: false +# CHECK-NEXT: SamplerDescriptorHeapIndexing: false +# CHECK-NEXT: RESERVED: true +# CHECK-NEXT: AtomicInt64OnHeapResource: false +# CHECK-NEXT: AdvancedTextureOps: true +# CHECK-NEXT: WriteableMSAATextures: false +# CHECK-NEXT: NextUnusedBit: true diff --git a/llvm/test/tools/obj2yaml/DXContainer/ShaderFlagsEmpty.yaml b/llvm/test/tools/obj2yaml/DXContainer/ShaderFlagsEmpty.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/DXContainer/ShaderFlagsEmpty.yaml @@ -0,0 +1,65 @@ +# RUN: yaml2obj %s | obj2yaml | FileCheck %s + +--- !dxcontainer +Header: + Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ] + Version: + Major: 1 + Minor: 0 + PartCount: 7 +Parts: + - Name: SFI0 + Size: 8 + Flags: + Doubles: false + ComputeShadersPlusRawAndStructuredBuffers: false + UAVsAtEveryStage: false + Max64UAVs: false + MinimumPrecision: false + DX11_1_DoubleExtensions: false + DX11_1_ShaderExtensions: false + LEVEL9ComparisonFiltering: false + TiledResources: false + StencilRef: false + InnerCoverage: false + TypedUAVLoadAdditionalFormats: false + ROVs: false + ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer: false + WaveOps: false + Int64Ops: false + ViewID: false + Barycentrics: false + NativeLowPrecision: false + ShadingRate: false + Raytracing_Tier_1_1: false + SamplerFeedback: false + AtomicInt64OnTypedResource: false + AtomicInt64OnGroupShared: false + DerivativesInMeshAndAmpShaders: false + ResourceDescriptorHeapIndexing: false + SamplerDescriptorHeapIndexing: false + RESERVED: false + AtomicInt64OnHeapResource: false + AdvancedTextureOps: false + WriteableMSAATextures: false + NextUnusedBit: false + - Name: ISG1 + Size: 8 + - Name: OSG1 + Size: 8 + - Name: PSV0 + Size: 8 + - Name: STAT + Size: 8 + - Name: HASH + Size: 8 + - Name: CXIL + Size: 8 +... + +# CHECK: Parts: +# CHECK-NEXT: - Name: SFI0 +# CHECK-NEXT: Size: 8 +# CHECK-NOT: Flags: +# CHECK-NEXT: - Name: ISG1 diff --git a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp --- a/llvm/tools/obj2yaml/dxcontainer2yaml.cpp +++ b/llvm/tools/obj2yaml/dxcontainer2yaml.cpp @@ -60,6 +60,13 @@ DXIL->second, DXIL->second + DXIL->first.Bitcode.Size)}; break; } + case dxbc::PartType::SFI0: { + Optional Flags = Container.getShaderFlags(); + // Omit the flags in the YAML if they are missing or zero. + if (Flags && *Flags > 0) + NewPart.Flags = DXContainerYAML::ShaderFlags(*Flags); + break; + } case dxbc::PartType::Unknown: break; }