1 //===- DXContainerYAML.cpp - DXContainer YAMLIO implementation ------------===// 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 // This file defines classes for handling the YAML representation of 10 // DXContainerYAML. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ObjectYAML/DXContainerYAML.h" 15 #include "llvm/ADT/ScopeExit.h" 16 #include "llvm/BinaryFormat/DXContainer.h" 17 #include "llvm/Support/ScopedPrinter.h" 18 19 namespace llvm { 20 21 // This assert is duplicated here to leave a breadcrumb of the places that need 22 // to be updated if flags grow past 64-bits. 23 static_assert((uint64_t)dxbc::FeatureFlags::NextUnusedBit <= 1ull << 63, 24 "Shader flag bits exceed enum size."); 25 26 DXContainerYAML::ShaderFeatureFlags::ShaderFeatureFlags(uint64_t FlagData) { 27 #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \ 28 Val = (FlagData & (uint64_t)dxbc::FeatureFlags::Val) > 0; 29 #include "llvm/BinaryFormat/DXContainerConstants.def" 30 } 31 32 uint64_t DXContainerYAML::ShaderFeatureFlags::getEncodedFlags() { 33 uint64_t Flag = 0; 34 #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \ 35 if (Val) \ 36 Flag |= (uint64_t)dxbc::FeatureFlags::Val; 37 #include "llvm/BinaryFormat/DXContainerConstants.def" 38 return Flag; 39 } 40 41 DXContainerYAML::ShaderHash::ShaderHash(const dxbc::ShaderHash &Data) 42 : IncludesSource((Data.Flags & static_cast<uint32_t>( 43 dxbc::HashFlags::IncludesSource)) != 0), 44 Digest(16, 0) { 45 memcpy(Digest.data(), &Data.Digest[0], 16); 46 } 47 48 DXContainerYAML::PSVInfo::PSVInfo() : Version(0) { 49 memset(&Info, 0, sizeof(Info)); 50 } 51 52 DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v0::RuntimeInfo *P, 53 uint16_t Stage) 54 : Version(0) { 55 memset(&Info, 0, sizeof(Info)); 56 memcpy(&Info, P, sizeof(dxbc::PSV::v0::RuntimeInfo)); 57 58 assert(Stage < std::numeric_limits<uint8_t>::max() && 59 "Stage should be a very small number"); 60 // We need to bring the stage in separately since it isn't part of the v1 data 61 // structure. 62 Info.ShaderStage = static_cast<uint8_t>(Stage); 63 } 64 65 DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v1::RuntimeInfo *P) 66 : Version(1) { 67 memset(&Info, 0, sizeof(Info)); 68 memcpy(&Info, P, sizeof(dxbc::PSV::v1::RuntimeInfo)); 69 } 70 71 DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v2::RuntimeInfo *P) 72 : Version(2) { 73 memset(&Info, 0, sizeof(Info)); 74 memcpy(&Info, P, sizeof(dxbc::PSV::v2::RuntimeInfo)); 75 } 76 77 DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v3::RuntimeInfo *P, 78 StringRef StringTable) 79 : Version(3), 80 EntryName(StringTable.substr(P->EntryNameOffset, 81 StringTable.find('\0', P->EntryNameOffset) - 82 P->EntryNameOffset)) { 83 memset(&Info, 0, sizeof(Info)); 84 memcpy(&Info, P, sizeof(dxbc::PSV::v3::RuntimeInfo)); 85 } 86 87 namespace yaml { 88 89 void MappingTraits<DXContainerYAML::VersionTuple>::mapping( 90 IO &IO, DXContainerYAML::VersionTuple &Version) { 91 IO.mapRequired("Major", Version.Major); 92 IO.mapRequired("Minor", Version.Minor); 93 } 94 95 void MappingTraits<DXContainerYAML::FileHeader>::mapping( 96 IO &IO, DXContainerYAML::FileHeader &Header) { 97 IO.mapRequired("Hash", Header.Hash); 98 IO.mapRequired("Version", Header.Version); 99 IO.mapOptional("FileSize", Header.FileSize); 100 IO.mapRequired("PartCount", Header.PartCount); 101 IO.mapOptional("PartOffsets", Header.PartOffsets); 102 } 103 104 void MappingTraits<DXContainerYAML::DXILProgram>::mapping( 105 IO &IO, DXContainerYAML::DXILProgram &Program) { 106 IO.mapRequired("MajorVersion", Program.MajorVersion); 107 IO.mapRequired("MinorVersion", Program.MinorVersion); 108 IO.mapRequired("ShaderKind", Program.ShaderKind); 109 IO.mapOptional("Size", Program.Size); 110 IO.mapRequired("DXILMajorVersion", Program.DXILMajorVersion); 111 IO.mapRequired("DXILMinorVersion", Program.DXILMinorVersion); 112 IO.mapOptional("DXILSize", Program.DXILSize); 113 IO.mapOptional("DXIL", Program.DXIL); 114 } 115 116 void MappingTraits<DXContainerYAML::ShaderFeatureFlags>::mapping( 117 IO &IO, DXContainerYAML::ShaderFeatureFlags &Flags) { 118 #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \ 119 IO.mapRequired(#Val, Flags.Val); 120 #include "llvm/BinaryFormat/DXContainerConstants.def" 121 } 122 123 void MappingTraits<DXContainerYAML::ShaderHash>::mapping( 124 IO &IO, DXContainerYAML::ShaderHash &Hash) { 125 IO.mapRequired("IncludesSource", Hash.IncludesSource); 126 IO.mapRequired("Digest", Hash.Digest); 127 } 128 129 void MappingTraits<DXContainerYAML::PSVInfo>::mapping( 130 IO &IO, DXContainerYAML::PSVInfo &PSV) { 131 IO.mapRequired("Version", PSV.Version); 132 133 // Store the PSV version in the YAML context. 134 void *OldContext = IO.getContext(); 135 uint32_t Version = PSV.Version; 136 IO.setContext(&Version); 137 138 // Restore the YAML context on function exit. 139 auto RestoreContext = make_scope_exit([&]() { IO.setContext(OldContext); }); 140 141 // Shader stage is only included in binaries for v1 and later, but we always 142 // include it since it simplifies parsing and file construction. 143 IO.mapRequired("ShaderStage", PSV.Info.ShaderStage); 144 PSV.mapInfoForVersion(IO); 145 146 IO.mapRequired("ResourceStride", PSV.ResourceStride); 147 IO.mapRequired("Resources", PSV.Resources); 148 if (PSV.Version == 0) 149 return; 150 IO.mapRequired("SigInputElements", PSV.SigInputElements); 151 IO.mapRequired("SigOutputElements", PSV.SigOutputElements); 152 IO.mapRequired("SigPatchOrPrimElements", PSV.SigPatchOrPrimElements); 153 154 Triple::EnvironmentType Stage = dxbc::getShaderStage(PSV.Info.ShaderStage); 155 if (PSV.Info.UsesViewID) { 156 MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableOutMasks( 157 PSV.OutputVectorMasks); 158 IO.mapRequired("OutputVectorMasks", MutableOutMasks); 159 if (Stage == Triple::EnvironmentType::Hull) 160 IO.mapRequired("PatchOrPrimMasks", PSV.PatchOrPrimMasks); 161 } 162 MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableIOMap( 163 PSV.InputOutputMap); 164 IO.mapRequired("InputOutputMap", MutableIOMap); 165 166 if (Stage == Triple::EnvironmentType::Hull) 167 IO.mapRequired("InputPatchMap", PSV.InputPatchMap); 168 169 if (Stage == Triple::EnvironmentType::Domain) 170 IO.mapRequired("PatchOutputMap", PSV.PatchOutputMap); 171 } 172 173 void MappingTraits<DXContainerYAML::SignatureParameter>::mapping( 174 IO &IO, DXContainerYAML::SignatureParameter &S) { 175 IO.mapRequired("Stream", S.Stream); 176 IO.mapRequired("Name", S.Name); 177 IO.mapRequired("Index", S.Index); 178 IO.mapRequired("SystemValue", S.SystemValue); 179 IO.mapRequired("CompType", S.CompType); 180 IO.mapRequired("Register", S.Register); 181 IO.mapRequired("Mask", S.Mask); 182 IO.mapRequired("ExclusiveMask", S.ExclusiveMask); 183 IO.mapRequired("MinPrecision", S.MinPrecision); 184 } 185 186 void MappingTraits<DXContainerYAML::Signature>::mapping( 187 IO &IO, DXContainerYAML::Signature &S) { 188 IO.mapRequired("Parameters", S.Parameters); 189 } 190 191 void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO, 192 DXContainerYAML::Part &P) { 193 IO.mapRequired("Name", P.Name); 194 IO.mapRequired("Size", P.Size); 195 IO.mapOptional("Program", P.Program); 196 IO.mapOptional("Flags", P.Flags); 197 IO.mapOptional("Hash", P.Hash); 198 IO.mapOptional("PSVInfo", P.Info); 199 IO.mapOptional("Signature", P.Signature); 200 } 201 202 void MappingTraits<DXContainerYAML::Object>::mapping( 203 IO &IO, DXContainerYAML::Object &Obj) { 204 IO.mapTag("!dxcontainer", true); 205 IO.mapRequired("Header", Obj.Header); 206 IO.mapRequired("Parts", Obj.Parts); 207 } 208 209 void MappingTraits<DXContainerYAML::ResourceFlags>::mapping( 210 IO &IO, DXContainerYAML::ResourceFlags &Flags) { 211 #define RESOURCE_FLAG(FlagIndex, Enum) IO.mapRequired(#Enum, Flags.Bits.Enum); 212 #include "llvm/BinaryFormat/DXContainerConstants.def" 213 } 214 215 void MappingTraits<DXContainerYAML::ResourceBindInfo>::mapping( 216 IO &IO, DXContainerYAML::ResourceBindInfo &Res) { 217 IO.mapRequired("Type", Res.Type); 218 IO.mapRequired("Space", Res.Space); 219 IO.mapRequired("LowerBound", Res.LowerBound); 220 IO.mapRequired("UpperBound", Res.UpperBound); 221 222 const uint32_t *PSVVersion = static_cast<uint32_t *>(IO.getContext()); 223 if (*PSVVersion < 2) 224 return; 225 226 IO.mapRequired("Kind", Res.Kind); 227 IO.mapRequired("Flags", Res.Flags); 228 } 229 230 void MappingTraits<DXContainerYAML::SignatureElement>::mapping( 231 IO &IO, DXContainerYAML::SignatureElement &El) { 232 IO.mapRequired("Name", El.Name); 233 IO.mapRequired("Indices", El.Indices); 234 IO.mapRequired("StartRow", El.StartRow); 235 IO.mapRequired("Cols", El.Cols); 236 IO.mapRequired("StartCol", El.StartCol); 237 IO.mapRequired("Allocated", El.Allocated); 238 IO.mapRequired("Kind", El.Kind); 239 IO.mapRequired("ComponentType", El.Type); 240 IO.mapRequired("Interpolation", El.Mode); 241 IO.mapRequired("DynamicMask", El.DynamicMask); 242 IO.mapRequired("Stream", El.Stream); 243 } 244 245 void ScalarEnumerationTraits<dxbc::PSV::SemanticKind>::enumeration( 246 IO &IO, dxbc::PSV::SemanticKind &Value) { 247 for (const auto &E : dxbc::PSV::getSemanticKinds()) 248 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 249 } 250 251 void ScalarEnumerationTraits<dxbc::PSV::ComponentType>::enumeration( 252 IO &IO, dxbc::PSV::ComponentType &Value) { 253 for (const auto &E : dxbc::PSV::getComponentTypes()) 254 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 255 } 256 257 void ScalarEnumerationTraits<dxbc::PSV::InterpolationMode>::enumeration( 258 IO &IO, dxbc::PSV::InterpolationMode &Value) { 259 for (const auto &E : dxbc::PSV::getInterpolationModes()) 260 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 261 } 262 263 void ScalarEnumerationTraits<dxbc::PSV::ResourceType>::enumeration( 264 IO &IO, dxbc::PSV::ResourceType &Value) { 265 for (const auto &E : dxbc::PSV::getResourceTypes()) 266 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 267 } 268 269 void ScalarEnumerationTraits<dxbc::PSV::ResourceKind>::enumeration( 270 IO &IO, dxbc::PSV::ResourceKind &Value) { 271 for (const auto &E : dxbc::PSV::getResourceKinds()) 272 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 273 } 274 275 void ScalarEnumerationTraits<dxbc::D3DSystemValue>::enumeration( 276 IO &IO, dxbc::D3DSystemValue &Value) { 277 for (const auto &E : dxbc::getD3DSystemValues()) 278 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 279 } 280 281 void ScalarEnumerationTraits<dxbc::SigMinPrecision>::enumeration( 282 IO &IO, dxbc::SigMinPrecision &Value) { 283 for (const auto &E : dxbc::getSigMinPrecisions()) 284 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 285 } 286 287 void ScalarEnumerationTraits<dxbc::SigComponentType>::enumeration( 288 IO &IO, dxbc::SigComponentType &Value) { 289 for (const auto &E : dxbc::getSigComponentTypes()) 290 IO.enumCase(Value, E.Name.str().c_str(), E.Value); 291 } 292 293 } // namespace yaml 294 295 void DXContainerYAML::PSVInfo::mapInfoForVersion(yaml::IO &IO) { 296 dxbc::PipelinePSVInfo &StageInfo = Info.StageInfo; 297 Triple::EnvironmentType Stage = dxbc::getShaderStage(Info.ShaderStage); 298 299 switch (Stage) { 300 case Triple::EnvironmentType::Pixel: 301 IO.mapRequired("DepthOutput", StageInfo.PS.DepthOutput); 302 IO.mapRequired("SampleFrequency", StageInfo.PS.SampleFrequency); 303 break; 304 case Triple::EnvironmentType::Vertex: 305 IO.mapRequired("OutputPositionPresent", StageInfo.VS.OutputPositionPresent); 306 break; 307 case Triple::EnvironmentType::Geometry: 308 IO.mapRequired("InputPrimitive", StageInfo.GS.InputPrimitive); 309 IO.mapRequired("OutputTopology", StageInfo.GS.OutputTopology); 310 IO.mapRequired("OutputStreamMask", StageInfo.GS.OutputStreamMask); 311 IO.mapRequired("OutputPositionPresent", StageInfo.GS.OutputPositionPresent); 312 break; 313 case Triple::EnvironmentType::Hull: 314 IO.mapRequired("InputControlPointCount", 315 StageInfo.HS.InputControlPointCount); 316 IO.mapRequired("OutputControlPointCount", 317 StageInfo.HS.OutputControlPointCount); 318 IO.mapRequired("TessellatorDomain", StageInfo.HS.TessellatorDomain); 319 IO.mapRequired("TessellatorOutputPrimitive", 320 StageInfo.HS.TessellatorOutputPrimitive); 321 break; 322 case Triple::EnvironmentType::Domain: 323 IO.mapRequired("InputControlPointCount", 324 StageInfo.DS.InputControlPointCount); 325 IO.mapRequired("OutputPositionPresent", StageInfo.DS.OutputPositionPresent); 326 IO.mapRequired("TessellatorDomain", StageInfo.DS.TessellatorDomain); 327 break; 328 case Triple::EnvironmentType::Mesh: 329 IO.mapRequired("GroupSharedBytesUsed", StageInfo.MS.GroupSharedBytesUsed); 330 IO.mapRequired("GroupSharedBytesDependentOnViewID", 331 StageInfo.MS.GroupSharedBytesDependentOnViewID); 332 IO.mapRequired("PayloadSizeInBytes", StageInfo.MS.PayloadSizeInBytes); 333 IO.mapRequired("MaxOutputVertices", StageInfo.MS.MaxOutputVertices); 334 IO.mapRequired("MaxOutputPrimitives", StageInfo.MS.MaxOutputPrimitives); 335 break; 336 case Triple::EnvironmentType::Amplification: 337 IO.mapRequired("PayloadSizeInBytes", StageInfo.AS.PayloadSizeInBytes); 338 break; 339 default: 340 break; 341 } 342 343 IO.mapRequired("MinimumWaveLaneCount", Info.MinimumWaveLaneCount); 344 IO.mapRequired("MaximumWaveLaneCount", Info.MaximumWaveLaneCount); 345 346 if (Version == 0) 347 return; 348 349 IO.mapRequired("UsesViewID", Info.UsesViewID); 350 351 switch (Stage) { 352 case Triple::EnvironmentType::Geometry: 353 IO.mapRequired("MaxVertexCount", Info.GeomData.MaxVertexCount); 354 break; 355 case Triple::EnvironmentType::Hull: 356 case Triple::EnvironmentType::Domain: 357 IO.mapRequired("SigPatchConstOrPrimVectors", 358 Info.GeomData.SigPatchConstOrPrimVectors); 359 break; 360 case Triple::EnvironmentType::Mesh: 361 IO.mapRequired("SigPrimVectors", Info.GeomData.MeshInfo.SigPrimVectors); 362 IO.mapRequired("MeshOutputTopology", 363 Info.GeomData.MeshInfo.MeshOutputTopology); 364 break; 365 default: 366 break; 367 } 368 369 IO.mapRequired("SigInputVectors", Info.SigInputVectors); 370 MutableArrayRef<uint8_t> Vec(Info.SigOutputVectors); 371 IO.mapRequired("SigOutputVectors", Vec); 372 373 if (Version == 1) 374 return; 375 376 IO.mapRequired("NumThreadsX", Info.NumThreadsX); 377 IO.mapRequired("NumThreadsY", Info.NumThreadsY); 378 IO.mapRequired("NumThreadsZ", Info.NumThreadsZ); 379 380 if (Version == 2) 381 return; 382 383 IO.mapRequired("EntryName", EntryName); 384 } 385 386 } // namespace llvm 387