blob: ce0b905f5363bb49b34d2f5d4ec1e1401a9fdb41 [file] [edit]
///////////////////////////////////////////////////////////////////////////////
// //
// DxilContainer.h //
// Copyright (C) Microsoft Corporation. All rights reserved. //
// This file is distributed under the University of Illinois Open Source //
// License. See LICENSE.TXT for details. //
// //
// Provides declarations for the DXIL container format. //
// //
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef __DXC_CONTAINER__
#define __DXC_CONTAINER__
#include <stdint.h>
#include <iterator>
#include <functional>
#include "dxc/HLSL/DxilConstants.h"
struct IDxcContainerReflection;
namespace llvm { class Module; }
namespace hlsl {
class AbstractMemoryStream;
class RootSignatureHandle;
class DxilModule;
#pragma pack(push, 1)
static const size_t DxilContainerHashSize = 16;
static const uint16_t DxilContainerVersionMajor = 1; // Current major version
static const uint16_t DxilContainerVersionMinor = 0; // Current minor version
static const uint32_t DxilContainerMaxSize = 0x80000000; // Max size for container.
/// Use this type to represent the hash for the full container.
struct DxilContainerHash {
uint8_t Digest[DxilContainerHashSize];
};
struct DxilContainerVersion {
uint16_t Major;
uint16_t Minor;
};
/// Use this type to describe a DXIL container of parts.
struct DxilContainerHeader {
uint32_t HeaderFourCC;
DxilContainerHash Hash;
DxilContainerVersion Version;
uint32_t ContainerSizeInBytes; // From start of this header
uint32_t PartCount;
// Structure is followed by uint32_t PartOffset[PartCount];
// The offset is to a DxilPartHeader.
};
/// Use this type to describe the size and type of a DXIL container part.
struct DxilPartHeader {
uint32_t PartFourCC; // Four char code for part type.
uint32_t PartSize; // Byte count for PartData.
// Structure is followed by uint8_t PartData[PartSize].
};
#define DXIL_FOURCC(ch0, ch1, ch2, ch3) ( \
(uint32_t)(uint8_t)(ch0) | (uint32_t)(uint8_t)(ch1) << 8 | \
(uint32_t)(uint8_t)(ch2) << 16 | (uint32_t)(uint8_t)(ch3) << 24 \
)
enum DxilFourCC {
DFCC_Container = DXIL_FOURCC('D', 'X', 'B', 'C'), // for back-compat with tools that look for DXBC containers
DFCC_ResourceDef = DXIL_FOURCC('R', 'D', 'E', 'F'),
DFCC_InputSignature = DXIL_FOURCC('I', 'S', 'G', '1'),
DFCC_OutputSignature = DXIL_FOURCC('O', 'S', 'G', '1'),
DFCC_PatchConstantSignature = DXIL_FOURCC('P', 'S', 'G', '1'),
DFCC_ShaderStatistics = DXIL_FOURCC('S', 'T', 'A', 'T'),
DFCC_ShaderDebugInfoDXIL = DXIL_FOURCC('I', 'L', 'D', 'B'),
DFCC_ShaderDebugName = DXIL_FOURCC('I', 'L', 'D', 'N'),
DFCC_FeatureInfo = DXIL_FOURCC('S', 'F', 'I', '0'),
DFCC_PrivateData = DXIL_FOURCC('P', 'R', 'I', 'V'),
DFCC_RootSignature = DXIL_FOURCC('R', 'T', 'S', '0'),
DFCC_DXIL = DXIL_FOURCC('D', 'X', 'I', 'L'),
DFCC_PipelineStateValidation = DXIL_FOURCC('P', 'S', 'V', '0'),
};
#undef DXIL_FOURCC
// DFCC_FeatureInfo is a uint64_t value with these flags.
static const uint64_t ShaderFeatureInfo_Doubles = 0x0001;
static const uint64_t ShaderFeatureInfo_ComputeShadersPlusRawAndStructuredBuffersViaShader4X = 0x0002;
static const uint64_t ShaderFeatureInfo_UAVsAtEveryStage = 0x0004;
static const uint64_t ShaderFeatureInfo_64UAVs = 0x0008;
static const uint64_t ShaderFeatureInfo_MinimumPrecision = 0x0010;
static const uint64_t ShaderFeatureInfo_11_1_DoubleExtensions = 0x0020;
static const uint64_t ShaderFeatureInfo_11_1_ShaderExtensions = 0x0040;
static const uint64_t ShaderFeatureInfo_LEVEL9ComparisonFiltering = 0x0080;
static const uint64_t ShaderFeatureInfo_TiledResources = 0x0100;
static const uint64_t ShaderFeatureInfo_StencilRef = 0x0200;
static const uint64_t ShaderFeatureInfo_InnerCoverage = 0x0400;
static const uint64_t ShaderFeatureInfo_TypedUAVLoadAdditionalFormats = 0x0800;
static const uint64_t ShaderFeatureInfo_ROVs = 0x1000;
static const uint64_t ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer = 0x2000;
static const uint64_t ShaderFeatureInfo_WaveOps = 0x4000;
static const uint64_t ShaderFeatureInfo_Int64Ops = 0x8000;
static const uint64_t ShaderFeatureInfo_ViewID = 0x10000;
static const uint64_t ShaderFeatureInfo_Barycentrics = 0x20000;
static const uint64_t ShaderFeatureInfo_NativeLowPrecision = 0x40000;
static const unsigned ShaderFeatureInfoCount = 19;
struct DxilShaderFeatureInfo {
uint64_t FeatureFlags;
};
// DXIL program information.
struct DxilBitcodeHeader {
uint32_t DxilMagic; // ACSII "DXIL".
uint32_t DxilVersion; // DXIL version.
uint32_t BitcodeOffset; // Offset to LLVM bitcode (from start of header).
uint32_t BitcodeSize; // Size of LLVM bitcode.
};
static const uint32_t DxilMagicValue = 0x4C495844; // 'DXIL'
struct DxilProgramHeader {
uint32_t ProgramVersion; /// Major and minor version, including type.
uint32_t SizeInUint32; /// Size in uint32_t units including this header.
DxilBitcodeHeader BitcodeHeader; /// Bitcode-specific header.
// Followed by uint8_t[BitcodeHeader.BitcodeOffset]
};
struct DxilProgramSignature {
uint32_t ParamCount;
uint32_t ParamOffset;
};
enum class DxilProgramSigMinPrecision : uint32_t {
Default = 0,
Float16 = 1,
Float2_8 = 2,
Reserved = 3,
SInt16 = 4,
UInt16 = 5,
Any16 = 0xf0,
Any10 = 0xf1
};
// Corresponds to D3D_NAME and D3D10_SB_NAME
enum class DxilProgramSigSemantic : uint32_t {
Undefined = 0,
Position = 1,
ClipDistance = 2,
CullDistance = 3,
RenderTargetArrayIndex = 4,
ViewPortArrayIndex = 5,
VertexID = 6,
PrimitiveID = 7,
InstanceID = 8,
IsFrontFace = 9,
SampleIndex = 10,
FinalQuadEdgeTessfactor = 11,
FinalQuadInsideTessfactor = 12,
FinalTriEdgeTessfactor = 13,
FinalTriInsideTessfactor = 14,
FinalLineDetailTessfactor = 15,
FinalLineDensityTessfactor = 16,
Barycentrics = 23,
Target = 64,
Depth = 65,
Coverage = 66,
DepthGE = 67,
DepthLE = 68,
StencilRef = 69,
InnerCoverage = 70,
};
enum class DxilProgramSigCompType : uint32_t {
Unknown = 0,
UInt32 = 1,
SInt32 = 2,
Float32 = 3,
UInt16 = 4,
SInt16 = 5,
Float16 = 6,
UInt64 = 7,
SInt64 = 8,
Float64 = 9,
};
static const uint8_t DxilProgramSigMaskX = 1;
static const uint8_t DxilProgramSigMaskY = 2;
static const uint8_t DxilProgramSigMaskZ = 4;
static const uint8_t DxilProgramSigMaskW = 8;
struct DxilProgramSignatureElement {
uint32_t Stream; // Stream index (parameters must appear in non-decreasing stream order)
uint32_t SemanticName; // Offset to LPCSTR from start of DxilProgramSignature.
uint32_t SemanticIndex; // Semantic Index
DxilProgramSigSemantic SystemValue; // Semantic type. Similar to DxilSemantic::Kind, but a serialized rather than processing rep.
DxilProgramSigCompType CompType; // Type of bits.
uint32_t Register; // Register Index (row index)
uint8_t Mask; // Mask (column allocation)
union // Unconditional cases useful for validation of shader linkage.
{
uint8_t NeverWrites_Mask; // For an output signature, the shader the signature belongs to never
// writes the masked components of the output register.
uint8_t AlwaysReads_Mask; // For an input signature, the shader the signature belongs to always
// reads the masked components of the input register.
};
uint16_t Pad;
DxilProgramSigMinPrecision MinPrecision; // Minimum precision of input/output data
};
// Easy to get this wrong. Earlier assertions can help determine
static_assert(sizeof(DxilProgramSignatureElement) == 0x20, "else DxilProgramSignatureElement is misaligned");
struct DxilShaderDebugName {
uint16_t Flags; // Reserved, must be set to zero.
uint16_t NameLength; // Length of the debug name, without null terminator.
// Followed by NameLength bytes of the UTF-8-encoded name.
// Followed by a null terminator.
// Followed by [0-3] zero bytes to align to a 4-byte boundary.
};
static const size_t MinDxilShaderDebugNameSize = sizeof(DxilShaderDebugName) + 4;
#pragma pack(pop)
/// Gets a part header by index.
inline const DxilPartHeader *
GetDxilContainerPart(const DxilContainerHeader *pHeader, uint32_t index) {
const uint8_t *pLinearContainer = reinterpret_cast<const uint8_t *>(pHeader);
const uint32_t *pPartOffsetTable =
reinterpret_cast<const uint32_t *>(pHeader + 1);
return reinterpret_cast<const DxilPartHeader *>(
pLinearContainer + pPartOffsetTable[index]);
}
/// Gets a part header by index.
inline DxilPartHeader *GetDxilContainerPart(DxilContainerHeader *pHeader,
uint32_t index) {
return const_cast<DxilPartHeader *>(GetDxilContainerPart(
reinterpret_cast<const DxilContainerHeader *>(pHeader), index));
}
/// Gets the part data from the header.
inline const char *GetDxilPartData(const DxilPartHeader *pPart) {
return reinterpret_cast<const char *>(pPart + 1);
}
/// Gets the part data from the header.
inline char *GetDxilPartData(DxilPartHeader *pPart) {
return reinterpret_cast<char *>(pPart + 1);
}
/// Gets a part header by fourCC
DxilPartHeader *GetDxilPartByType(DxilContainerHeader *pHeader,
DxilFourCC fourCC);
/// Gets a part header by fourCC
const DxilPartHeader *
GetDxilPartByType(const DxilContainerHeader *pHeader,
DxilFourCC fourCC);
/// Returns valid DxilProgramHeader. nullptr if does not exist.
DxilProgramHeader *GetDxilProgramHeader(DxilContainerHeader *pHeader, DxilFourCC fourCC);
/// Returns valid DxilProgramHeader. nullptr if does not exist.
const DxilProgramHeader *
GetDxilProgramHeader(const DxilContainerHeader *pHeader, DxilFourCC fourCC);
/// Initializes container with the specified values.
void InitDxilContainer(_Out_ DxilContainerHeader *pHeader, uint32_t partCount,
uint32_t containerSizeInBytes);
/// Checks whether pHeader claims by signature to be a DXIL container.
const DxilContainerHeader *IsDxilContainerLike(const void *ptr, size_t length);
/// Checks whether the DXIL container is valid and in-bounds.
bool IsValidDxilContainer(const DxilContainerHeader *pHeader, size_t length);
/// Use this type as a unary predicate functor.
struct DxilPartIsType {
uint32_t IsFourCC;
DxilPartIsType(uint32_t FourCC) : IsFourCC(FourCC) { }
bool operator()(const DxilPartHeader *pPart) const {
return pPart->PartFourCC == IsFourCC;
}
};
/// Use this type as an iterator over the part headers.
struct DxilPartIterator : public std::iterator<std::input_iterator_tag,
const DxilContainerHeader *> {
const DxilContainerHeader *pHeader;
uint32_t index;
DxilPartIterator(const DxilContainerHeader *h, uint32_t i)
: pHeader(h), index(i) {}
// increment
DxilPartIterator &operator++() {
++index;
return *this;
}
DxilPartIterator operator++(int) {
DxilPartIterator result(pHeader, index);
++index;
return result;
}
// input iterator - compare and deref
bool operator==(const DxilPartIterator &other) const {
return index == other.index && pHeader == other.pHeader;
}
bool operator!=(const DxilPartIterator &other) const {
return index != other.index || pHeader != other.pHeader;
}
const DxilPartHeader *operator*() const {
return GetDxilContainerPart(pHeader, index);
}
};
DxilPartIterator begin(const DxilContainerHeader *pHeader);
DxilPartIterator end(const DxilContainerHeader *pHeader);
inline bool IsValidDxilBitcodeHeader(const DxilBitcodeHeader *pHeader,
uint32_t length) {
return length > sizeof(DxilBitcodeHeader) &&
pHeader->BitcodeOffset + pHeader->BitcodeSize >
pHeader->BitcodeOffset &&
length >= pHeader->BitcodeOffset + pHeader->BitcodeSize &&
pHeader->DxilMagic == DxilMagicValue;
}
inline void InitBitcodeHeader(DxilBitcodeHeader &header,
uint32_t dxilVersion,
uint32_t bitcodeSize) {
header.DxilMagic = DxilMagicValue;
header.DxilVersion = dxilVersion;
header.BitcodeOffset = sizeof(DxilBitcodeHeader);
header.BitcodeSize = bitcodeSize;
}
inline void GetDxilProgramBitcode(const DxilProgramHeader *pHeader,
const char **pBitcode,
uint32_t *pBitcodeLength) {
*pBitcode = reinterpret_cast<const char *>(&pHeader->BitcodeHeader) +
pHeader->BitcodeHeader.BitcodeOffset;
*pBitcodeLength = pHeader->BitcodeHeader.BitcodeSize;
}
inline bool IsValidDxilProgramHeader(const DxilProgramHeader *pHeader,
uint32_t length) {
return length >= sizeof(DxilProgramHeader) &&
length >= (pHeader->SizeInUint32 * sizeof(uint32_t)) &&
IsValidDxilBitcodeHeader(
&pHeader->BitcodeHeader,
length - offsetof(DxilProgramHeader, BitcodeHeader));
}
inline void InitProgramHeader(DxilProgramHeader &header, uint32_t shaderVersion,
uint32_t dxilVersion,
uint32_t bitcodeSize) {
header.ProgramVersion = shaderVersion;
header.SizeInUint32 =
sizeof(DxilProgramHeader) / sizeof(uint32_t) +
bitcodeSize / sizeof(uint32_t) + ((bitcodeSize % 4) ? 1 : 0);
InitBitcodeHeader(header.BitcodeHeader, dxilVersion, bitcodeSize);
}
inline const char *GetDxilBitcodeData(const DxilProgramHeader *pHeader) {
const DxilBitcodeHeader *pBCHdr = &(pHeader->BitcodeHeader);
return (const char *)pBCHdr + pBCHdr->BitcodeOffset;
}
inline uint32_t GetDxilBitcodeSize(const DxilProgramHeader *pHeader) {
return pHeader->BitcodeHeader.BitcodeSize;
}
/// Extract the shader type from the program version value.
inline DXIL::ShaderKind GetVersionShaderType(uint32_t programVersion) {
return (DXIL::ShaderKind)((programVersion & 0xffff0000) >> 16);
}
inline uint32_t GetVersionMajor(uint32_t programVersion) {
return (programVersion & 0xf0) >> 4;
}
inline uint32_t GetVersionMinor(uint32_t programVersion) {
return (programVersion & 0xf);
}
inline uint32_t EncodeVersion(DXIL::ShaderKind shaderType, uint32_t major,
uint32_t minor) {
return ((unsigned)shaderType << 16) | (major << 4) | minor;
}
inline bool IsDxilShaderDebugNameValid(const DxilPartHeader *pPart) {
if (pPart->PartFourCC != DFCC_ShaderDebugName) return false;
if (pPart->PartSize < MinDxilShaderDebugNameSize) return false;
const DxilShaderDebugName *pDebugNameContent = reinterpret_cast<const DxilShaderDebugName *>(GetDxilPartData(pPart));
uint16_t ExpectedSize = sizeof(DxilShaderDebugName) + pDebugNameContent->NameLength + 1;
if (ExpectedSize & 0x3) {
ExpectedSize += 0x4;
ExpectedSize &= ~(0x3);
}
if (pPart->PartSize != ExpectedSize) return false;
return true;
}
inline bool GetDxilShaderDebugName(const DxilPartHeader *pDebugNamePart,
const char **ppUtf8Name, _Out_opt_ uint16_t *pUtf8NameLen) {
*ppUtf8Name = nullptr;
if (!IsDxilShaderDebugNameValid(pDebugNamePart)) {
return false;
}
const DxilShaderDebugName *pDebugNameContent = reinterpret_cast<const DxilShaderDebugName *>(GetDxilPartData(pDebugNamePart));
if (pUtf8NameLen) {
*pUtf8NameLen = pDebugNameContent->NameLength;
}
*ppUtf8Name = (const char *)(pDebugNameContent + 1);
return true;
}
class DxilPartWriter {
public:
virtual ~DxilPartWriter() {}
virtual uint32_t size() const = 0;
virtual void write(AbstractMemoryStream *pStream) = 0;
};
DxilPartWriter *NewProgramSignatureWriter(const DxilModule &M, DXIL::SignatureKind Kind);
DxilPartWriter *NewRootSignatureWriter(const RootSignatureHandle &S);
DxilPartWriter *NewFeatureInfoWriter(const DxilModule &M);
DxilPartWriter *NewPSVWriter(const DxilModule &M, uint32_t PSVVersion = 0);
class DxilContainerWriter : public DxilPartWriter {
public:
typedef std::function<void(AbstractMemoryStream*)> WriteFn;
virtual ~DxilContainerWriter() {}
virtual void AddPart(uint32_t FourCC, uint32_t Size, WriteFn Write) = 0;
};
DxilContainerWriter *NewDxilContainerWriter();
enum class SerializeDxilFlags : uint32_t {
None = 0, // No flags defined.
IncludeDebugInfoPart = 1, // Include the debug info part in the container.
IncludeDebugNamePart = 2, // Include the debug name part in the container.
DebugNameDependOnSource = 4 // Make the debug name depend on source (and not just final module).
};
inline SerializeDxilFlags& operator |=(SerializeDxilFlags& l, const SerializeDxilFlags& r) {
l = static_cast<SerializeDxilFlags>(static_cast<int>(l) | static_cast<int>(r));
return l;
}
inline SerializeDxilFlags& operator &=(SerializeDxilFlags& l, const SerializeDxilFlags& r) {
l = static_cast<SerializeDxilFlags>(static_cast<int>(l) & static_cast<int>(r));
return l;
}
inline int operator&(SerializeDxilFlags l, SerializeDxilFlags r) {
return static_cast<int>(l) & static_cast<int>(r);
}
inline SerializeDxilFlags operator~(SerializeDxilFlags l) {
return static_cast<SerializeDxilFlags>(~static_cast<uint32_t>(l));
}
void SerializeDxilContainerForModule(hlsl::DxilModule *pModule,
AbstractMemoryStream *pModuleBitcode,
AbstractMemoryStream *pStream,
SerializeDxilFlags Flags);
void SerializeDxilContainerForRootSignature(hlsl::RootSignatureHandle *pRootSigHandle,
AbstractMemoryStream *pStream);
void CreateDxcContainerReflection(IDxcContainerReflection **ppResult);
// Converts uint32_t partKind to char array object.
inline char * PartKindToCharArray(uint32_t partKind, _Out_writes_(5) char* pText) {
pText[0] = (char)((partKind & 0x000000FF) >> 0);
pText[1] = (char)((partKind & 0x0000FF00) >> 8);
pText[2] = (char)((partKind & 0x00FF0000) >> 16);
pText[3] = (char)((partKind & 0xFF000000) >> 24);
pText[4] = '\0';
return pText;
}
inline size_t GetOffsetTableSize(uint32_t partCount) {
return sizeof(uint32_t) * partCount;
}
// Compute total size of the dxil container from parts information
inline size_t GetDxilContainerSizeFromParts(uint32_t partCount, uint32_t partsSize) {
return partsSize + (uint32_t)sizeof(DxilContainerHeader) +
GetOffsetTableSize(partCount) +
(uint32_t)sizeof(DxilPartHeader) * partCount;
}
} // namespace hlsl
#endif // __DXC_CONTAINER__