blob: f92071e32222e1c457cc1f1e418ed1c3a02a7d52 [file] [log] [blame]
//===-- llvm/BinaryFormat/DXContainer.h - The DXBC file format --*- C++/-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines manifest constants for the DXContainer object file format.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_BINARYFORMAT_DXCONTAINER_H
#define LLVM_BINARYFORMAT_DXCONTAINER_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/TargetParser/Triple.h"
#include <stdint.h>
namespace llvm {
template <typename T> struct EnumEntry;
// The DXContainer file format is arranged as a header and "parts". Semantically
// parts are similar to sections in other object file formats. The File format
// structure is roughly:
// ┌────────────────────────────────┐
// │ Header │
// ├────────────────────────────────┤
// │ Part │
// ├────────────────────────────────┤
// │ Part │
// ├────────────────────────────────┤
// │ ... │
// └────────────────────────────────┘
namespace dxbc {
inline Triple::EnvironmentType getShaderStage(uint32_t Kind) {
assert(Kind <= Triple::Amplification - Triple::Pixel &&
"Shader kind out of expected range.");
return static_cast<Triple::EnvironmentType>(Triple::Pixel + Kind);
}
struct Hash {
uint8_t Digest[16];
};
enum class HashFlags : uint32_t {
None = 0, // No flags defined.
IncludesSource = 1, // This flag indicates that the shader hash was computed
// taking into account source information (-Zss)
};
struct ShaderHash {
uint32_t Flags; // dxbc::HashFlags
uint8_t Digest[16];
bool isPopulated();
void swapBytes() { sys::swapByteOrder(Flags); }
};
struct ContainerVersion {
uint16_t Major;
uint16_t Minor;
void swapBytes() {
sys::swapByteOrder(Major);
sys::swapByteOrder(Minor);
}
};
struct Header {
uint8_t Magic[4]; // "DXBC"
Hash FileHash;
ContainerVersion Version;
uint32_t FileSize;
uint32_t PartCount;
void swapBytes() {
Version.swapBytes();
sys::swapByteOrder(FileSize);
sys::swapByteOrder(PartCount);
}
// Structure is followed by part offsets: uint32_t PartOffset[PartCount];
// The offset is to a PartHeader, which is followed by the Part Data.
};
/// Use this type to describe the size and type of a DXIL container part.
struct PartHeader {
uint8_t Name[4];
uint32_t Size;
void swapBytes() { sys::swapByteOrder(Size); }
StringRef getName() const {
return StringRef(reinterpret_cast<const char *>(&Name[0]), 4);
}
// Structure is followed directly by part data: uint8_t PartData[PartSize].
};
struct BitcodeHeader {
uint8_t Magic[4]; // ACSII "DXIL".
uint8_t MajorVersion; // DXIL version.
uint8_t MinorVersion; // DXIL version.
uint16_t Unused;
uint32_t Offset; // Offset to LLVM bitcode (from start of header).
uint32_t Size; // Size of LLVM bitcode (in bytes).
// Followed by uint8_t[BitcodeHeader.Size] at &BitcodeHeader + Header.Offset
void swapBytes() {
sys::swapByteOrder(MinorVersion);
sys::swapByteOrder(MajorVersion);
sys::swapByteOrder(Offset);
sys::swapByteOrder(Size);
}
};
struct ProgramHeader {
uint8_t MinorVersion : 4;
uint8_t MajorVersion : 4;
uint8_t Unused;
uint16_t ShaderKind;
uint32_t Size; // Size in uint32_t words including this header.
BitcodeHeader Bitcode;
void swapBytes() {
sys::swapByteOrder(ShaderKind);
sys::swapByteOrder(Size);
Bitcode.swapBytes();
}
};
static_assert(sizeof(ProgramHeader) == 24, "ProgramHeader Size incorrect!");
#define CONTAINER_PART(Part) Part,
enum class PartType {
Unknown = 0,
#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);
struct VertexPSVInfo {
uint8_t OutputPositionPresent;
uint8_t Unused[3];
void swapBytes() {
// nothing to swap
}
};
struct HullPSVInfo {
uint32_t InputControlPointCount;
uint32_t OutputControlPointCount;
uint32_t TessellatorDomain;
uint32_t TessellatorOutputPrimitive;
void swapBytes() {
sys::swapByteOrder(InputControlPointCount);
sys::swapByteOrder(OutputControlPointCount);
sys::swapByteOrder(TessellatorDomain);
sys::swapByteOrder(TessellatorOutputPrimitive);
}
};
struct DomainPSVInfo {
uint32_t InputControlPointCount;
uint8_t OutputPositionPresent;
uint8_t Unused[3];
uint32_t TessellatorDomain;
void swapBytes() {
sys::swapByteOrder(InputControlPointCount);
sys::swapByteOrder(TessellatorDomain);
}
};
struct GeometryPSVInfo {
uint32_t InputPrimitive;
uint32_t OutputTopology;
uint32_t OutputStreamMask;
uint8_t OutputPositionPresent;
uint8_t Unused[3];
void swapBytes() {
sys::swapByteOrder(InputPrimitive);
sys::swapByteOrder(OutputTopology);
sys::swapByteOrder(OutputStreamMask);
}
};
struct PixelPSVInfo {
uint8_t DepthOutput;
uint8_t SampleFrequency;
uint8_t Unused[2];
void swapBytes() {
// nothing to swap
}
};
struct MeshPSVInfo {
uint32_t GroupSharedBytesUsed;
uint32_t GroupSharedBytesDependentOnViewID;
uint32_t PayloadSizeInBytes;
uint16_t MaxOutputVertices;
uint16_t MaxOutputPrimitives;
void swapBytes() {
sys::swapByteOrder(GroupSharedBytesUsed);
sys::swapByteOrder(GroupSharedBytesDependentOnViewID);
sys::swapByteOrder(PayloadSizeInBytes);
sys::swapByteOrder(MaxOutputVertices);
sys::swapByteOrder(MaxOutputPrimitives);
}
};
struct AmplificationPSVInfo {
uint32_t PayloadSizeInBytes;
void swapBytes() { sys::swapByteOrder(PayloadSizeInBytes); }
};
union PipelinePSVInfo {
VertexPSVInfo VS;
HullPSVInfo HS;
DomainPSVInfo DS;
GeometryPSVInfo GS;
PixelPSVInfo PS;
MeshPSVInfo MS;
AmplificationPSVInfo AS;
void swapBytes(Triple::EnvironmentType Stage) {
switch (Stage) {
case Triple::EnvironmentType::Pixel:
PS.swapBytes();
break;
case Triple::EnvironmentType::Vertex:
VS.swapBytes();
break;
case Triple::EnvironmentType::Geometry:
GS.swapBytes();
break;
case Triple::EnvironmentType::Hull:
HS.swapBytes();
break;
case Triple::EnvironmentType::Domain:
DS.swapBytes();
break;
case Triple::EnvironmentType::Mesh:
MS.swapBytes();
break;
case Triple::EnvironmentType::Amplification:
AS.swapBytes();
break;
default:
break;
}
}
};
static_assert(sizeof(PipelinePSVInfo) == 4 * sizeof(uint32_t),
"Pipeline-specific PSV info must fit in 16 bytes.");
namespace PSV {
#define SEMANTIC_KIND(Val, Enum) Enum = Val,
enum class SemanticKind : uint8_t {
#include "DXContainerConstants.def"
};
ArrayRef<EnumEntry<SemanticKind>> getSemanticKinds();
#define COMPONENT_TYPE(Val, Enum) Enum = Val,
enum class ComponentType : uint8_t {
#include "DXContainerConstants.def"
};
ArrayRef<EnumEntry<ComponentType>> getComponentTypes();
#define INTERPOLATION_MODE(Val, Enum) Enum = Val,
enum class InterpolationMode : uint8_t {
#include "DXContainerConstants.def"
};
ArrayRef<EnumEntry<InterpolationMode>> getInterpolationModes();
namespace v0 {
struct RuntimeInfo {
PipelinePSVInfo StageInfo;
uint32_t MinimumWaveLaneCount; // minimum lane count required, 0 if unused
uint32_t MaximumWaveLaneCount; // maximum lane count required,
// 0xffffffff if unused
void swapBytes() {
// Skip the union because we don't know which field it has
sys::swapByteOrder(MinimumWaveLaneCount);
sys::swapByteOrder(MaximumWaveLaneCount);
}
void swapBytes(Triple::EnvironmentType Stage) { StageInfo.swapBytes(Stage); }
};
struct ResourceBindInfo {
uint32_t Type;
uint32_t Space;
uint32_t LowerBound;
uint32_t UpperBound;
void swapBytes() {
sys::swapByteOrder(Type);
sys::swapByteOrder(Space);
sys::swapByteOrder(LowerBound);
sys::swapByteOrder(UpperBound);
}
};
struct SignatureElement {
uint32_t NameOffset;
uint32_t IndicesOffset;
uint8_t Rows;
uint8_t StartRow;
uint8_t Cols : 4;
uint8_t StartCol : 2;
uint8_t Allocated : 1;
uint8_t Unused : 1;
SemanticKind Kind;
ComponentType Type;
InterpolationMode Mode;
uint8_t DynamicMask : 4;
uint8_t Stream : 2;
uint8_t Unused2 : 2;
uint8_t Reserved;
void swapBytes() {
sys::swapByteOrder(NameOffset);
sys::swapByteOrder(IndicesOffset);
}
};
static_assert(sizeof(SignatureElement) == 4 * sizeof(uint32_t),
"PSV Signature elements must fit in 16 bytes.");
} // namespace v0
namespace v1 {
struct MeshRuntimeInfo {
uint8_t SigPrimVectors; // Primitive output for MS
uint8_t MeshOutputTopology;
};
union GeometryExtraInfo {
uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024)
uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS;
// Primitive output for MS (overlaps
// MeshInfo::SigPrimVectors)
MeshRuntimeInfo MeshInfo;
};
struct RuntimeInfo : public v0::RuntimeInfo {
uint8_t ShaderStage; // PSVShaderKind
uint8_t UsesViewID;
GeometryExtraInfo GeomData;
// PSVSignatureElement counts
uint8_t SigInputElements;
uint8_t SigOutputElements;
uint8_t SigPatchOrPrimElements;
// Number of packed vectors per signature
uint8_t SigInputVectors;
uint8_t SigOutputVectors[4];
void swapBytes() {
// nothing to swap since everything is single-byte or a union field
}
void swapBytes(Triple::EnvironmentType Stage) {
v0::RuntimeInfo::swapBytes(Stage);
if (Stage == Triple::EnvironmentType::Geometry)
sys::swapByteOrder(GeomData.MaxVertexCount);
}
};
} // namespace v1
namespace v2 {
struct RuntimeInfo : public v1::RuntimeInfo {
uint32_t NumThreadsX;
uint32_t NumThreadsY;
uint32_t NumThreadsZ;
void swapBytes() {
sys::swapByteOrder(NumThreadsX);
sys::swapByteOrder(NumThreadsY);
sys::swapByteOrder(NumThreadsZ);
}
void swapBytes(Triple::EnvironmentType Stage) {
v1::RuntimeInfo::swapBytes(Stage);
}
};
struct ResourceBindInfo : public v0::ResourceBindInfo {
uint32_t Kind;
uint32_t Flags;
void swapBytes() {
v0::ResourceBindInfo::swapBytes();
sys::swapByteOrder(Kind);
sys::swapByteOrder(Flags);
}
};
} // namespace v2
} // namespace PSV
} // namespace dxbc
} // namespace llvm
#endif // LLVM_BINARYFORMAT_DXCONTAINER_H