uint32_t Flags; // dxbc::HashFlags
uint8_t Digest[16];
+ bool isPopulated();
+
void swapBytes() { sys::swapByteOrder(Flags); }
};
#ifdef CONTAINER_PART
CONTAINER_PART(DXIL)
CONTAINER_PART(SFI0)
+CONTAINER_PART(HASH)
#undef CONTAINER_PART
#endif
SmallVector<uint32_t, 4> PartOffsets;
Optional<DXILData> DXIL;
Optional<uint64_t> ShaderFlags;
+ Optional<dxbc::ShaderHash> Hash;
Error parseHeader();
Error parsePartOffsets();
Error parseDXILHeader(uint32_t Offset);
Error parseShaderFlags(uint32_t Offset);
+ Error parseHash(uint32_t Offset);
friend class PartIterator;
public:
Optional<DXILData> getDXIL() const { return DXIL; }
Optional<uint64_t> getShaderFlags() const { return ShaderFlags; }
+
+ Optional<dxbc::ShaderHash> getShaderHash() const { return Hash; }
};
} // namespace object
#define LLVM_OBJECTYAML_DXCONTAINERYAML_H
#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/ObjectYAML/YAML.h"
#include "llvm/Support/YAMLTraits.h"
#include <cstdint>
#include "llvm/BinaryFormat/DXContainerConstants.def"
};
+struct ShaderHash {
+ ShaderHash() = default;
+ ShaderHash(const dxbc::ShaderHash &Data);
+
+ bool IncludesSource;
+ std::vector<llvm::yaml::Hex8> Digest;
+};
+
struct Part {
Part() = default;
Part(std::string N, uint32_t S) : Name(N), Size(S) {}
uint32_t Size;
Optional<DXILProgram> Program;
Optional<ShaderFlags> Flags;
+ Optional<ShaderHash> Hash;
};
struct Object {
static void mapping(IO &IO, DXContainerYAML::ShaderFlags &Flags);
};
+template <> struct MappingTraits<DXContainerYAML::ShaderHash> {
+ static void mapping(IO &IO, DXContainerYAML::ShaderHash &Hash);
+};
+
template <> struct MappingTraits<DXContainerYAML::Part> {
static void mapping(IO &IO, DXContainerYAML::Part &Version);
};
#include "llvm/ADT/StringSwitch.h"
using namespace llvm;
-using namespace llvm;
+using namespace llvm::dxbc;
dxbc::PartType dxbc::parsePartType(StringRef S) {
#define CONTAINER_PART(PartName) .Case(#PartName, PartType::PartName)
#include "llvm/BinaryFormat/DXContainerConstants.def"
.Default(dxbc::PartType::Unknown);
}
+
+bool ShaderHash::isPopulated() {
+ static uint8_t Zeros[16] = {0};
+ return Flags > 0 || 0 != memcmp(&Digest, &Zeros, 16);
+}
return Error::success();
}
+Error DXContainer::parseHash(uint32_t Offset) {
+ if (Hash)
+ return parseFailed("More than one HASH part is present in the file");
+ const char *Current = Data.getBuffer().data() + Offset;
+ dxbc::ShaderHash ReadHash;
+ if (Error Err = readStruct(Data.getBuffer(), Current, ReadHash))
+ return Err;
+ Hash = ReadHash;
+ return Error::success();
+}
+
Error DXContainer::parsePartOffsets() {
const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header);
for (uint32_t Part = 0; Part < Header.PartCount; ++Part) {
if (Error Err = parseShaderFlags(PartOffset + sizeof(dxbc::PartHeader)))
return Err;
break;
+ case dxbc::PartType::HASH:
+ if (Error Err = parseHash(PartOffset + sizeof(dxbc::PartHeader)))
+ return Err;
+ break;
case dxbc::PartType::Unknown:
break;
}
dxbc::PartType PT = dxbc::parsePartType(P.Name);
uint64_t DataStart = OS.tell();
- if (PT == dxbc::PartType::DXIL) {
+ switch (PT) {
+ case dxbc::PartType::DXIL: {
if (!P.Program)
continue;
dxbc::ProgramHeader Header;
OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
P.Program->DXIL->size());
}
- } else if (PT == dxbc::PartType::SFI0) {
+ break;
+ }
+ case 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())
if (sys::IsBigEndianHost)
sys::swapByteOrder(Flags);
OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
+ break;
+ }
+ case dxbc::PartType::HASH: {
+ if (!P.Hash.has_value())
+ continue;
+ dxbc::ShaderHash Hash = {0, {0}};
+ if (P.Hash->IncludesSource)
+ Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
+ memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
+ if (sys::IsBigEndianHost)
+ Hash.swapBytes();
+ OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
+ break;
+ }
+ case dxbc::PartType::Unknown:
+ break; // Skip any handling for unrecognized parts.
}
uint64_t BytesWritten = OS.tell() - DataStart;
RollingOffset += BytesWritten;
return Flag;
}
+DXContainerYAML::ShaderHash::ShaderHash(const dxbc::ShaderHash &Data)
+ : IncludesSource((Data.Flags & static_cast<uint32_t>(
+ dxbc::HashFlags::IncludesSource)) != 0),
+ Digest(16, 0) {
+ memcpy(Digest.data(), &Data.Digest[0], 16);
+}
+
namespace yaml {
void MappingTraits<DXContainerYAML::VersionTuple>::mapping(
#include "llvm/BinaryFormat/DXContainerConstants.def"
}
+void MappingTraits<DXContainerYAML::ShaderHash>::mapping(
+ IO &IO, DXContainerYAML::ShaderHash &Hash) {
+ IO.mapRequired("IncludesSource", Hash.IncludesSource);
+ IO.mapRequired("Digest", Hash.Digest);
+}
+
void MappingTraits<DXContainerYAML::Part>::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);
+ IO.mapOptional("Hash", P.Hash);
}
void MappingTraits<DXContainerYAML::Object>::mapping(
Version:
Major: 1
Minor: 0
- FileSize: 172
+ FileSize: 184
PartCount: 7
- PartOffsets: [ 60, 76, 92, 108, 124, 140, 156 ]
+ PartOffsets: [ 60, 76, 92, 108, 124, 140, 168 ]
Parts:
- Name: SFI0
Size: 8
- Name: STAT
Size: 8
- Name: HASH
- Size: 8
+ Size: 20
- Name: CXIL
Size: 8
...
# CHECK-NEXT: Version:
# CHECK-NEXT: Major: 1
# CHECK-NEXT: Minor: 0
-# CHECK-NEXT: FileSize: 172
+# CHECK-NEXT: FileSize: 184
# CHECK-NEXT: PartCount: 7
-# CHECK-NEXT: PartOffsets: [ 60, 76, 92, 108, 124, 140, 156 ]
+# CHECK-NEXT: PartOffsets: [ 60, 76, 92, 108, 124, 140, 168 ]
# CHECK-NEXT: Parts:
# CHECK-NEXT: - Name: SFI0
# CHECK-NEXT: Size: 8
# CHECK-NEXT: - Name: STAT
# CHECK-NEXT: Size: 8
# CHECK-NEXT: - Name: HASH
-# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Size: 20
# CHECK-NEXT: - Name: CXIL
# CHECK-NEXT: Size: 8
# CHECK-NEXT: ...
- Name: STAT
Size: 8
- Name: HASH
- Size: 8
+ Size: 20
- Name: CXIL
Size: 8
...
# CHECK-NEXT: Version:
# CHECK-NEXT: Major: 1
# CHECK-NEXT: Minor: 0
-# CHECK-NEXT: FileSize: 172
+# CHECK-NEXT: FileSize: 184
# CHECK-NEXT: PartCount: 7
-# CHECK-NEXT: PartOffsets: [ 60, 76, 92, 108, 124, 140, 156 ]
+# CHECK-NEXT: PartOffsets: [ 60, 76, 92, 108, 124, 140, 168 ]
# CHECK-NEXT: Parts:
# CHECK-NEXT: - Name: SFI0
# CHECK-NEXT: Size: 8
# CHECK-NEXT: - Name: STAT
# CHECK-NEXT: Size: 8
# CHECK-NEXT: - Name: HASH
-# CHECK-NEXT: Size: 8
+# CHECK-NEXT: Size: 20
# CHECK-NEXT: - Name: CXIL
# CHECK-NEXT: Size: 8
# CHECK-NEXT: ...
- Name: STAT
Size: 8
- Name: HASH
- Size: 8
+ Size: 20
- Name: CXIL
Size: 8
...
- Name: STAT
Size: 8
- Name: HASH
- Size: 8
+ Size: 20
- Name: CXIL
Size: 8
...
--- /dev/null
+# 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: 1
+Parts:
+ - Name: HASH
+ Size: 20
+ Hash:
+ IncludesSource: true
+ Digest: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 ]
+...
+
+# CHECK: --- !dxcontainer
+# CHECK-NEXT: Header:
+# CHECK-NEXT: Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+# CHECK-NEXT: 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+# CHECK: FileSize: 64
+# CHECK-NEXT: PartCount: 1
+# CHECK-NEXT: PartOffsets: [ 36 ]
+# CHECK: - Name: HASH
+# CHECK-NEXT: Size: 20
+# CHECK-NEXT: Hash:
+# CHECK-NEXT: IncludesSource: true
+# CHECK-NEXT: Digest: [ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x10,
+# CHECK-NEXT: 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 ]
+# CHECK-NEXT: ...
NewPart.Flags = DXContainerYAML::ShaderFlags(*Flags);
break;
}
+ case dxbc::PartType::HASH: {
+ Optional<dxbc::ShaderHash> Hash = Container.getShaderHash();
+ if (Hash && Hash->isPopulated())
+ NewPart.Hash = DXContainerYAML::ShaderHash(*Hash);
+ break;
+ }
case dxbc::PartType::Unknown:
break;
}