1 | //===------ dxcontainer2yaml.cpp - obj2yaml conversion tool -----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "obj2yaml.h" |
10 | #include "llvm/Object/DXContainer.h" |
11 | #include "llvm/ObjectYAML/DXContainerYAML.h" |
12 | #include "llvm/Support/Error.h" |
13 | |
14 | #include <algorithm> |
15 | |
16 | using namespace llvm; |
17 | using namespace llvm::object; |
18 | |
19 | static DXContainerYAML::Signature dumpSignature(const DirectX::Signature &Sig) { |
20 | DXContainerYAML::Signature YAML; |
21 | for (auto Param : Sig) |
22 | YAML.Parameters.push_back(Elt: DXContainerYAML::SignatureParameter{ |
23 | .Stream: Param.Stream, .Name: Sig.getName(Offset: Param.NameOffset).str(), .Index: Param.Index, |
24 | .SystemValue: Param.SystemValue, .CompType: Param.CompType, .Register: Param.Register, .Mask: Param.Mask, |
25 | .ExclusiveMask: Param.ExclusiveMask, .MinPrecision: Param.MinPrecision}); |
26 | return YAML; |
27 | } |
28 | |
29 | static Expected<DXContainerYAML::Object *> |
30 | dumpDXContainer(MemoryBufferRef Source) { |
31 | assert(file_magic::dxcontainer_object == identify_magic(Source.getBuffer())); |
32 | |
33 | Expected<DXContainer> ExDXC = DXContainer::create(Object: Source); |
34 | if (!ExDXC) |
35 | return ExDXC.takeError(); |
36 | DXContainer Container = *ExDXC; |
37 | |
38 | std::unique_ptr<DXContainerYAML::Object> Obj = |
39 | std::make_unique<DXContainerYAML::Object>(); |
40 | |
41 | for (uint8_t Byte : Container.getHeader().FileHash.Digest) |
42 | Obj->Header.Hash.push_back(x: Byte); |
43 | Obj->Header.Version.Major = Container.getHeader().Version.Major; |
44 | Obj->Header.Version.Minor = Container.getHeader().Version.Minor; |
45 | Obj->Header.FileSize = Container.getHeader().FileSize; |
46 | Obj->Header.PartCount = Container.getHeader().PartCount; |
47 | |
48 | Obj->Header.PartOffsets = std::vector<uint32_t>(); |
49 | for (const auto P : Container) { |
50 | Obj->Header.PartOffsets->push_back(x: P.Offset); |
51 | Obj->Parts.push_back( |
52 | x: DXContainerYAML::Part(P.Part.getName().str(), P.Part.Size)); |
53 | DXContainerYAML::Part &NewPart = Obj->Parts.back(); |
54 | dxbc::PartType PT = dxbc::parsePartType(S: P.Part.getName()); |
55 | switch (PT) { |
56 | case dxbc::PartType::DXIL: { |
57 | std::optional<DXContainer::DXILData> DXIL = Container.getDXIL(); |
58 | assert(DXIL && "Since we are iterating and found a DXIL part, " |
59 | "this should never not have a value" ); |
60 | NewPart.Program = DXContainerYAML::DXILProgram{ |
61 | .MajorVersion: DXIL->first.getMajorVersion(), |
62 | .MinorVersion: DXIL->first.getMinorVersion(), |
63 | .ShaderKind: DXIL->first.ShaderKind, |
64 | .Size: DXIL->first.Size, |
65 | .DXILMajorVersion: DXIL->first.Bitcode.MajorVersion, |
66 | .DXILMinorVersion: DXIL->first.Bitcode.MinorVersion, |
67 | .DXILOffset: DXIL->first.Bitcode.Offset, |
68 | .DXILSize: DXIL->first.Bitcode.Size, |
69 | .DXIL: std::vector<llvm::yaml::Hex8>( |
70 | DXIL->second, DXIL->second + DXIL->first.Bitcode.Size)}; |
71 | break; |
72 | } |
73 | case dxbc::PartType::SFI0: { |
74 | std::optional<uint64_t> Flags = Container.getShaderFeatureFlags(); |
75 | // Omit the flags in the YAML if they are missing or zero. |
76 | if (Flags && *Flags > 0) |
77 | NewPart.Flags = DXContainerYAML::ShaderFeatureFlags(*Flags); |
78 | break; |
79 | } |
80 | case dxbc::PartType::HASH: { |
81 | std::optional<dxbc::ShaderHash> Hash = Container.getShaderHash(); |
82 | if (Hash && Hash->isPopulated()) |
83 | NewPart.Hash = DXContainerYAML::ShaderHash(*Hash); |
84 | break; |
85 | } |
86 | case dxbc::PartType::PSV0: { |
87 | const auto &PSVInfo = Container.getPSVInfo(); |
88 | if (!PSVInfo) |
89 | break; |
90 | if (const auto *P = |
91 | std::get_if<dxbc::PSV::v0::RuntimeInfo>(ptr: &PSVInfo->getInfo())) { |
92 | if (!Container.getDXIL()) |
93 | break; |
94 | NewPart.Info = |
95 | DXContainerYAML::PSVInfo(P, Container.getDXIL()->first.ShaderKind); |
96 | } else if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>( |
97 | ptr: &PSVInfo->getInfo())) |
98 | NewPart.Info = DXContainerYAML::PSVInfo(P); |
99 | else if (const auto *P = |
100 | std::get_if<dxbc::PSV::v2::RuntimeInfo>(ptr: &PSVInfo->getInfo())) |
101 | NewPart.Info = DXContainerYAML::PSVInfo(P); |
102 | else if (const auto *P = |
103 | std::get_if<dxbc::PSV::v3::RuntimeInfo>(ptr: &PSVInfo->getInfo())) |
104 | NewPart.Info = DXContainerYAML::PSVInfo(P, PSVInfo->getStringTable()); |
105 | NewPart.Info->ResourceStride = PSVInfo->getResourceStride(); |
106 | for (auto Res : PSVInfo->getResources()) |
107 | NewPart.Info->Resources.push_back(Elt: Res); |
108 | |
109 | for (auto El : PSVInfo->getSigInputElements()) |
110 | NewPart.Info->SigInputElements.push_back( |
111 | Elt: DXContainerYAML::SignatureElement( |
112 | El, PSVInfo->getStringTable(), |
113 | PSVInfo->getSemanticIndexTable())); |
114 | for (auto El : PSVInfo->getSigOutputElements()) |
115 | NewPart.Info->SigOutputElements.push_back( |
116 | Elt: DXContainerYAML::SignatureElement( |
117 | El, PSVInfo->getStringTable(), |
118 | PSVInfo->getSemanticIndexTable())); |
119 | for (auto El : PSVInfo->getSigPatchOrPrimElements()) |
120 | NewPart.Info->SigPatchOrPrimElements.push_back( |
121 | Elt: DXContainerYAML::SignatureElement( |
122 | El, PSVInfo->getStringTable(), |
123 | PSVInfo->getSemanticIndexTable())); |
124 | |
125 | if (PSVInfo->usesViewID()) { |
126 | for (int I = 0; I < 4; ++I) |
127 | for (auto Mask : PSVInfo->getOutputVectorMasks(Idx: I)) |
128 | NewPart.Info->OutputVectorMasks[I].push_back(Elt: Mask); |
129 | for (auto Mask : PSVInfo->getPatchOrPrimMasks()) |
130 | NewPart.Info->PatchOrPrimMasks.push_back(Elt: Mask); |
131 | } |
132 | |
133 | for (int I = 0; I < 4; ++I) |
134 | for (auto Mask : PSVInfo->getInputOutputMap(Idx: I)) |
135 | NewPart.Info->InputOutputMap[I].push_back(Elt: Mask); |
136 | |
137 | for (auto Mask : PSVInfo->getInputPatchMap()) |
138 | NewPart.Info->InputPatchMap.push_back(Elt: Mask); |
139 | |
140 | for (auto Mask : PSVInfo->getPatchOutputMap()) |
141 | NewPart.Info->PatchOutputMap.push_back(Elt: Mask); |
142 | |
143 | break; |
144 | } |
145 | case dxbc::PartType::ISG1: |
146 | NewPart.Signature = dumpSignature(Sig: Container.getInputSignature()); |
147 | break; |
148 | case dxbc::PartType::OSG1: |
149 | NewPart.Signature = dumpSignature(Sig: Container.getOutputSignature()); |
150 | break; |
151 | case dxbc::PartType::PSG1: |
152 | NewPart.Signature = dumpSignature(Sig: Container.getPatchConstantSignature()); |
153 | break; |
154 | case dxbc::PartType::Unknown: |
155 | break; |
156 | } |
157 | } |
158 | |
159 | return Obj.release(); |
160 | } |
161 | |
162 | llvm::Error dxcontainer2yaml(llvm::raw_ostream &Out, |
163 | llvm::MemoryBufferRef Source) { |
164 | Expected<DXContainerYAML::Object *> YAMLOrErr = dumpDXContainer(Source); |
165 | if (!YAMLOrErr) |
166 | return YAMLOrErr.takeError(); |
167 | |
168 | std::unique_ptr<DXContainerYAML::Object> YAML(YAMLOrErr.get()); |
169 | yaml::Output Yout(Out); |
170 | Yout << *YAML; |
171 | |
172 | return Error::success(); |
173 | } |
174 | |