181ad6265SDimitry Andric //===- DXContainer.cpp - DXContainer object file implementation -----------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "llvm/Object/DXContainer.h" 1081ad6265SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h" 1181ad6265SDimitry Andric #include "llvm/Object/Error.h" 12*5f757f3fSDimitry Andric #include "llvm/Support/Alignment.h" 13bdd1243dSDimitry Andric #include "llvm/Support/FormatVariadic.h" 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric using namespace llvm; 1681ad6265SDimitry Andric using namespace llvm::object; 1781ad6265SDimitry Andric 1881ad6265SDimitry Andric static Error parseFailed(const Twine &Msg) { 1981ad6265SDimitry Andric return make_error<GenericBinaryError>(Msg.str(), object_error::parse_failed); 2081ad6265SDimitry Andric } 2181ad6265SDimitry Andric 2281ad6265SDimitry Andric template <typename T> 2381ad6265SDimitry Andric static Error readStruct(StringRef Buffer, const char *Src, T &Struct) { 2481ad6265SDimitry Andric // Don't read before the beginning or past the end of the file 2581ad6265SDimitry Andric if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end()) 2681ad6265SDimitry Andric return parseFailed("Reading structure out of file bounds"); 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric memcpy(&Struct, Src, sizeof(T)); 2981ad6265SDimitry Andric // DXContainer is always little endian 3081ad6265SDimitry Andric if (sys::IsBigEndianHost) 3181ad6265SDimitry Andric Struct.swapBytes(); 3281ad6265SDimitry Andric return Error::success(); 3381ad6265SDimitry Andric } 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric template <typename T> 36bdd1243dSDimitry Andric static Error readInteger(StringRef Buffer, const char *Src, T &Val, 37bdd1243dSDimitry Andric Twine Str = "structure") { 38bdd1243dSDimitry Andric static_assert(std::is_integral_v<T>, 3981ad6265SDimitry Andric "Cannot call readInteger on non-integral type."); 4081ad6265SDimitry Andric // Don't read before the beginning or past the end of the file 4181ad6265SDimitry Andric if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end()) 42bdd1243dSDimitry Andric return parseFailed(Twine("Reading ") + Str + " out of file bounds"); 4381ad6265SDimitry Andric 44bdd1243dSDimitry Andric // The DXContainer offset table is comprised of uint32_t values but not padded 45bdd1243dSDimitry Andric // to a 64-bit boundary. So Parts may start unaligned if there is an odd 46bdd1243dSDimitry Andric // number of parts and part data itself is not required to be padded. 47bdd1243dSDimitry Andric if (reinterpret_cast<uintptr_t>(Src) % alignof(T) != 0) 48bdd1243dSDimitry Andric memcpy(reinterpret_cast<char *>(&Val), Src, sizeof(T)); 49bdd1243dSDimitry Andric else 5081ad6265SDimitry Andric Val = *reinterpret_cast<const T *>(Src); 5181ad6265SDimitry Andric // DXContainer is always little endian 5281ad6265SDimitry Andric if (sys::IsBigEndianHost) 5381ad6265SDimitry Andric sys::swapByteOrder(Val); 5481ad6265SDimitry Andric return Error::success(); 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric 5781ad6265SDimitry Andric DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {} 5881ad6265SDimitry Andric 5981ad6265SDimitry Andric Error DXContainer::parseHeader() { 6081ad6265SDimitry Andric return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header); 6181ad6265SDimitry Andric } 6281ad6265SDimitry Andric 63bdd1243dSDimitry Andric Error DXContainer::parseDXILHeader(StringRef Part) { 6481ad6265SDimitry Andric if (DXIL) 6581ad6265SDimitry Andric return parseFailed("More than one DXIL part is present in the file"); 66bdd1243dSDimitry Andric const char *Current = Part.begin(); 6781ad6265SDimitry Andric dxbc::ProgramHeader Header; 68bdd1243dSDimitry Andric if (Error Err = readStruct(Part, Current, Header)) 6981ad6265SDimitry Andric return Err; 7081ad6265SDimitry Andric Current += offsetof(dxbc::ProgramHeader, Bitcode) + Header.Bitcode.Offset; 7181ad6265SDimitry Andric DXIL.emplace(std::make_pair(Header, Current)); 7281ad6265SDimitry Andric return Error::success(); 7381ad6265SDimitry Andric } 7481ad6265SDimitry Andric 75bdd1243dSDimitry Andric Error DXContainer::parseShaderFlags(StringRef Part) { 76bdd1243dSDimitry Andric if (ShaderFlags) 77bdd1243dSDimitry Andric return parseFailed("More than one SFI0 part is present in the file"); 78bdd1243dSDimitry Andric uint64_t FlagValue = 0; 79bdd1243dSDimitry Andric if (Error Err = readInteger(Part, Part.begin(), FlagValue)) 80bdd1243dSDimitry Andric return Err; 81bdd1243dSDimitry Andric ShaderFlags = FlagValue; 82bdd1243dSDimitry Andric return Error::success(); 83bdd1243dSDimitry Andric } 84bdd1243dSDimitry Andric 85bdd1243dSDimitry Andric Error DXContainer::parseHash(StringRef Part) { 86bdd1243dSDimitry Andric if (Hash) 87bdd1243dSDimitry Andric return parseFailed("More than one HASH part is present in the file"); 88bdd1243dSDimitry Andric dxbc::ShaderHash ReadHash; 89bdd1243dSDimitry Andric if (Error Err = readStruct(Part, Part.begin(), ReadHash)) 90bdd1243dSDimitry Andric return Err; 91bdd1243dSDimitry Andric Hash = ReadHash; 92bdd1243dSDimitry Andric return Error::success(); 93bdd1243dSDimitry Andric } 94bdd1243dSDimitry Andric 9506c3fb27SDimitry Andric Error DXContainer::parsePSVInfo(StringRef Part) { 9606c3fb27SDimitry Andric if (PSVInfo) 9706c3fb27SDimitry Andric return parseFailed("More than one PSV0 part is present in the file"); 9806c3fb27SDimitry Andric PSVInfo = DirectX::PSVRuntimeInfo(Part); 9906c3fb27SDimitry Andric // Parsing the PSVRuntime info occurs late because we need to read data from 10006c3fb27SDimitry Andric // other parts first. 10106c3fb27SDimitry Andric return Error::success(); 10206c3fb27SDimitry Andric } 10306c3fb27SDimitry Andric 104*5f757f3fSDimitry Andric Error DirectX::Signature::initialize(StringRef Part) { 105*5f757f3fSDimitry Andric dxbc::ProgramSignatureHeader SigHeader; 106*5f757f3fSDimitry Andric if (Error Err = readStruct(Part, Part.begin(), SigHeader)) 107*5f757f3fSDimitry Andric return Err; 108*5f757f3fSDimitry Andric size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount; 109*5f757f3fSDimitry Andric 110*5f757f3fSDimitry Andric if (Part.size() < Size + SigHeader.FirstParamOffset) 111*5f757f3fSDimitry Andric return parseFailed("Signature parameters extend beyond the part boundary"); 112*5f757f3fSDimitry Andric 113*5f757f3fSDimitry Andric Parameters.Data = Part.substr(SigHeader.FirstParamOffset, Size); 114*5f757f3fSDimitry Andric 115*5f757f3fSDimitry Andric StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size); 116*5f757f3fSDimitry Andric StringTable = Part.substr(SigHeader.FirstParamOffset + Size); 117*5f757f3fSDimitry Andric 118*5f757f3fSDimitry Andric for (const auto &Param : Parameters) { 119*5f757f3fSDimitry Andric if (Param.NameOffset < StringTableOffset) 120*5f757f3fSDimitry Andric return parseFailed("Invalid parameter name offset: name starts before " 121*5f757f3fSDimitry Andric "the first name offset"); 122*5f757f3fSDimitry Andric if (Param.NameOffset - StringTableOffset > StringTable.size()) 123*5f757f3fSDimitry Andric return parseFailed("Invalid parameter name offset: name starts after the " 124*5f757f3fSDimitry Andric "end of the part data"); 125*5f757f3fSDimitry Andric } 126*5f757f3fSDimitry Andric return Error::success(); 127*5f757f3fSDimitry Andric } 128*5f757f3fSDimitry Andric 12981ad6265SDimitry Andric Error DXContainer::parsePartOffsets() { 130bdd1243dSDimitry Andric uint32_t LastOffset = 131bdd1243dSDimitry Andric sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t)); 13281ad6265SDimitry Andric const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header); 13381ad6265SDimitry Andric for (uint32_t Part = 0; Part < Header.PartCount; ++Part) { 13481ad6265SDimitry Andric uint32_t PartOffset; 13581ad6265SDimitry Andric if (Error Err = readInteger(Data.getBuffer(), Current, PartOffset)) 13681ad6265SDimitry Andric return Err; 137bdd1243dSDimitry Andric if (PartOffset < LastOffset) 138bdd1243dSDimitry Andric return parseFailed( 139bdd1243dSDimitry Andric formatv( 140bdd1243dSDimitry Andric "Part offset for part {0} begins before the previous part ends", 141bdd1243dSDimitry Andric Part) 142bdd1243dSDimitry Andric .str()); 14381ad6265SDimitry Andric Current += sizeof(uint32_t); 144bdd1243dSDimitry Andric if (PartOffset >= Data.getBufferSize()) 14581ad6265SDimitry Andric return parseFailed("Part offset points beyond boundary of the file"); 146bdd1243dSDimitry Andric // To prevent overflow when reading the part name, we subtract the part name 147bdd1243dSDimitry Andric // size from the buffer size, rather than adding to the offset. Since the 148bdd1243dSDimitry Andric // file header is larger than the part header we can't reach this code 149bdd1243dSDimitry Andric // unless the buffer is at least as large as a part header, so this 150bdd1243dSDimitry Andric // subtraction can't underflow. 151bdd1243dSDimitry Andric if (PartOffset >= Data.getBufferSize() - sizeof(dxbc::PartHeader::Name)) 152bdd1243dSDimitry Andric return parseFailed("File not large enough to read part name"); 15381ad6265SDimitry Andric PartOffsets.push_back(PartOffset); 15481ad6265SDimitry Andric 155bdd1243dSDimitry Andric dxbc::PartType PT = 156bdd1243dSDimitry Andric dxbc::parsePartType(Data.getBuffer().substr(PartOffset, 4)); 157bdd1243dSDimitry Andric uint32_t PartDataStart = PartOffset + sizeof(dxbc::PartHeader); 158bdd1243dSDimitry Andric uint32_t PartSize; 159bdd1243dSDimitry Andric if (Error Err = readInteger(Data.getBuffer(), 160bdd1243dSDimitry Andric Data.getBufferStart() + PartOffset + 4, 161bdd1243dSDimitry Andric PartSize, "part size")) 16281ad6265SDimitry Andric return Err; 163bdd1243dSDimitry Andric StringRef PartData = Data.getBuffer().substr(PartDataStart, PartSize); 164bdd1243dSDimitry Andric LastOffset = PartOffset + PartSize; 165bdd1243dSDimitry Andric switch (PT) { 166bdd1243dSDimitry Andric case dxbc::PartType::DXIL: 167bdd1243dSDimitry Andric if (Error Err = parseDXILHeader(PartData)) 168bdd1243dSDimitry Andric return Err; 169bdd1243dSDimitry Andric break; 170bdd1243dSDimitry Andric case dxbc::PartType::SFI0: 171bdd1243dSDimitry Andric if (Error Err = parseShaderFlags(PartData)) 172bdd1243dSDimitry Andric return Err; 173bdd1243dSDimitry Andric break; 174bdd1243dSDimitry Andric case dxbc::PartType::HASH: 175bdd1243dSDimitry Andric if (Error Err = parseHash(PartData)) 176bdd1243dSDimitry Andric return Err; 177bdd1243dSDimitry Andric break; 17806c3fb27SDimitry Andric case dxbc::PartType::PSV0: 17906c3fb27SDimitry Andric if (Error Err = parsePSVInfo(PartData)) 18006c3fb27SDimitry Andric return Err; 18106c3fb27SDimitry Andric break; 182*5f757f3fSDimitry Andric case dxbc::PartType::ISG1: 183*5f757f3fSDimitry Andric if (Error Err = InputSignature.initialize(PartData)) 184*5f757f3fSDimitry Andric return Err; 185*5f757f3fSDimitry Andric break; 186*5f757f3fSDimitry Andric case dxbc::PartType::OSG1: 187*5f757f3fSDimitry Andric if (Error Err = OutputSignature.initialize(PartData)) 188*5f757f3fSDimitry Andric return Err; 189*5f757f3fSDimitry Andric break; 190*5f757f3fSDimitry Andric case dxbc::PartType::PSG1: 191*5f757f3fSDimitry Andric if (Error Err = PatchConstantSignature.initialize(PartData)) 192*5f757f3fSDimitry Andric return Err; 193*5f757f3fSDimitry Andric break; 194bdd1243dSDimitry Andric case dxbc::PartType::Unknown: 195bdd1243dSDimitry Andric break; 196bdd1243dSDimitry Andric } 19781ad6265SDimitry Andric } 19806c3fb27SDimitry Andric 19906c3fb27SDimitry Andric // Fully parsing the PSVInfo requires knowing the shader kind which we read 20006c3fb27SDimitry Andric // out of the program header in the DXIL part. 20106c3fb27SDimitry Andric if (PSVInfo) { 20206c3fb27SDimitry Andric if (!DXIL) 20306c3fb27SDimitry Andric return parseFailed("Cannot fully parse pipeline state validation " 20406c3fb27SDimitry Andric "information without DXIL part."); 20506c3fb27SDimitry Andric if (Error Err = PSVInfo->parse(DXIL->first.ShaderKind)) 20606c3fb27SDimitry Andric return Err; 20706c3fb27SDimitry Andric } 20881ad6265SDimitry Andric return Error::success(); 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) { 21281ad6265SDimitry Andric DXContainer Container(Object); 21381ad6265SDimitry Andric if (Error Err = Container.parseHeader()) 21481ad6265SDimitry Andric return std::move(Err); 21581ad6265SDimitry Andric if (Error Err = Container.parsePartOffsets()) 21681ad6265SDimitry Andric return std::move(Err); 21781ad6265SDimitry Andric return Container; 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) { 22181ad6265SDimitry Andric StringRef Buffer = Container.Data.getBuffer(); 22281ad6265SDimitry Andric const char *Current = Buffer.data() + Offset; 22381ad6265SDimitry Andric // Offsets are validated during parsing, so all offsets in the container are 22481ad6265SDimitry Andric // valid and contain enough readable data to read a header. 22581ad6265SDimitry Andric cantFail(readStruct(Buffer, Current, IteratorState.Part)); 22681ad6265SDimitry Andric IteratorState.Data = 22781ad6265SDimitry Andric StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size); 22881ad6265SDimitry Andric IteratorState.Offset = Offset; 22981ad6265SDimitry Andric } 23006c3fb27SDimitry Andric 23106c3fb27SDimitry Andric Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) { 23206c3fb27SDimitry Andric Triple::EnvironmentType ShaderStage = dxbc::getShaderStage(ShaderKind); 23306c3fb27SDimitry Andric 23406c3fb27SDimitry Andric const char *Current = Data.begin(); 23506c3fb27SDimitry Andric if (Error Err = readInteger(Data, Current, Size)) 23606c3fb27SDimitry Andric return Err; 23706c3fb27SDimitry Andric Current += sizeof(uint32_t); 23806c3fb27SDimitry Andric 23906c3fb27SDimitry Andric StringRef PSVInfoData = Data.substr(sizeof(uint32_t), Size); 24006c3fb27SDimitry Andric 24106c3fb27SDimitry Andric if (PSVInfoData.size() < Size) 24206c3fb27SDimitry Andric return parseFailed( 24306c3fb27SDimitry Andric "Pipeline state data extends beyond the bounds of the part"); 24406c3fb27SDimitry Andric 24506c3fb27SDimitry Andric using namespace dxbc::PSV; 24606c3fb27SDimitry Andric 24706c3fb27SDimitry Andric const uint32_t PSVVersion = getVersion(); 24806c3fb27SDimitry Andric 24906c3fb27SDimitry Andric // Detect the PSVVersion by looking at the size field. 25006c3fb27SDimitry Andric if (PSVVersion == 2) { 25106c3fb27SDimitry Andric v2::RuntimeInfo Info; 25206c3fb27SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info)) 25306c3fb27SDimitry Andric return Err; 25406c3fb27SDimitry Andric if (sys::IsBigEndianHost) 25506c3fb27SDimitry Andric Info.swapBytes(ShaderStage); 25606c3fb27SDimitry Andric BasicInfo = Info; 25706c3fb27SDimitry Andric } else if (PSVVersion == 1) { 25806c3fb27SDimitry Andric v1::RuntimeInfo Info; 25906c3fb27SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info)) 26006c3fb27SDimitry Andric return Err; 26106c3fb27SDimitry Andric if (sys::IsBigEndianHost) 26206c3fb27SDimitry Andric Info.swapBytes(ShaderStage); 26306c3fb27SDimitry Andric BasicInfo = Info; 264*5f757f3fSDimitry Andric } else if (PSVVersion == 0) { 26506c3fb27SDimitry Andric v0::RuntimeInfo Info; 26606c3fb27SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info)) 26706c3fb27SDimitry Andric return Err; 26806c3fb27SDimitry Andric if (sys::IsBigEndianHost) 26906c3fb27SDimitry Andric Info.swapBytes(ShaderStage); 27006c3fb27SDimitry Andric BasicInfo = Info; 271*5f757f3fSDimitry Andric } else 272*5f757f3fSDimitry Andric return parseFailed( 273*5f757f3fSDimitry Andric "Cannot read PSV Runtime Info, unsupported PSV version."); 274*5f757f3fSDimitry Andric 27506c3fb27SDimitry Andric Current += Size; 27606c3fb27SDimitry Andric 27706c3fb27SDimitry Andric uint32_t ResourceCount = 0; 27806c3fb27SDimitry Andric if (Error Err = readInteger(Data, Current, ResourceCount)) 27906c3fb27SDimitry Andric return Err; 28006c3fb27SDimitry Andric Current += sizeof(uint32_t); 28106c3fb27SDimitry Andric 28206c3fb27SDimitry Andric if (ResourceCount > 0) { 28306c3fb27SDimitry Andric if (Error Err = readInteger(Data, Current, Resources.Stride)) 28406c3fb27SDimitry Andric return Err; 28506c3fb27SDimitry Andric Current += sizeof(uint32_t); 28606c3fb27SDimitry Andric 28706c3fb27SDimitry Andric size_t BindingDataSize = Resources.Stride * ResourceCount; 28806c3fb27SDimitry Andric Resources.Data = Data.substr(Current - Data.begin(), BindingDataSize); 28906c3fb27SDimitry Andric 29006c3fb27SDimitry Andric if (Resources.Data.size() < BindingDataSize) 29106c3fb27SDimitry Andric return parseFailed( 29206c3fb27SDimitry Andric "Resource binding data extends beyond the bounds of the part"); 29306c3fb27SDimitry Andric 29406c3fb27SDimitry Andric Current += BindingDataSize; 295*5f757f3fSDimitry Andric } else 296*5f757f3fSDimitry Andric Resources.Stride = sizeof(v2::ResourceBindInfo); 297*5f757f3fSDimitry Andric 298*5f757f3fSDimitry Andric // PSV version 0 ends after the resource bindings. 299*5f757f3fSDimitry Andric if (PSVVersion == 0) 300*5f757f3fSDimitry Andric return Error::success(); 301*5f757f3fSDimitry Andric 302*5f757f3fSDimitry Andric // String table starts at a 4-byte offset. 303*5f757f3fSDimitry Andric Current = reinterpret_cast<const char *>( 304*5f757f3fSDimitry Andric alignTo<4>(reinterpret_cast<uintptr_t>(Current))); 305*5f757f3fSDimitry Andric 306*5f757f3fSDimitry Andric uint32_t StringTableSize = 0; 307*5f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, StringTableSize)) 308*5f757f3fSDimitry Andric return Err; 309*5f757f3fSDimitry Andric if (StringTableSize % 4 != 0) 310*5f757f3fSDimitry Andric return parseFailed("String table misaligned"); 311*5f757f3fSDimitry Andric Current += sizeof(uint32_t); 312*5f757f3fSDimitry Andric StringTable = StringRef(Current, StringTableSize); 313*5f757f3fSDimitry Andric 314*5f757f3fSDimitry Andric Current += StringTableSize; 315*5f757f3fSDimitry Andric 316*5f757f3fSDimitry Andric uint32_t SemanticIndexTableSize = 0; 317*5f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, SemanticIndexTableSize)) 318*5f757f3fSDimitry Andric return Err; 319*5f757f3fSDimitry Andric Current += sizeof(uint32_t); 320*5f757f3fSDimitry Andric 321*5f757f3fSDimitry Andric SemanticIndexTable.reserve(SemanticIndexTableSize); 322*5f757f3fSDimitry Andric for (uint32_t I = 0; I < SemanticIndexTableSize; ++I) { 323*5f757f3fSDimitry Andric uint32_t Index = 0; 324*5f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, Index)) 325*5f757f3fSDimitry Andric return Err; 326*5f757f3fSDimitry Andric Current += sizeof(uint32_t); 327*5f757f3fSDimitry Andric SemanticIndexTable.push_back(Index); 328*5f757f3fSDimitry Andric } 329*5f757f3fSDimitry Andric 330*5f757f3fSDimitry Andric uint8_t InputCount = getSigInputCount(); 331*5f757f3fSDimitry Andric uint8_t OutputCount = getSigOutputCount(); 332*5f757f3fSDimitry Andric uint8_t PatchOrPrimCount = getSigPatchOrPrimCount(); 333*5f757f3fSDimitry Andric 334*5f757f3fSDimitry Andric uint32_t ElementCount = InputCount + OutputCount + PatchOrPrimCount; 335*5f757f3fSDimitry Andric 336*5f757f3fSDimitry Andric if (ElementCount > 0) { 337*5f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, SigInputElements.Stride)) 338*5f757f3fSDimitry Andric return Err; 339*5f757f3fSDimitry Andric Current += sizeof(uint32_t); 340*5f757f3fSDimitry Andric // Assign the stride to all the arrays. 341*5f757f3fSDimitry Andric SigOutputElements.Stride = SigPatchOrPrimElements.Stride = 342*5f757f3fSDimitry Andric SigInputElements.Stride; 343*5f757f3fSDimitry Andric 344*5f757f3fSDimitry Andric if (Data.end() - Current < ElementCount * SigInputElements.Stride) 345*5f757f3fSDimitry Andric return parseFailed( 346*5f757f3fSDimitry Andric "Signature elements extend beyond the size of the part"); 347*5f757f3fSDimitry Andric 348*5f757f3fSDimitry Andric size_t InputSize = SigInputElements.Stride * InputCount; 349*5f757f3fSDimitry Andric SigInputElements.Data = Data.substr(Current - Data.begin(), InputSize); 350*5f757f3fSDimitry Andric Current += InputSize; 351*5f757f3fSDimitry Andric 352*5f757f3fSDimitry Andric size_t OutputSize = SigOutputElements.Stride * OutputCount; 353*5f757f3fSDimitry Andric SigOutputElements.Data = Data.substr(Current - Data.begin(), OutputSize); 354*5f757f3fSDimitry Andric Current += OutputSize; 355*5f757f3fSDimitry Andric 356*5f757f3fSDimitry Andric size_t PSize = SigPatchOrPrimElements.Stride * PatchOrPrimCount; 357*5f757f3fSDimitry Andric SigPatchOrPrimElements.Data = Data.substr(Current - Data.begin(), PSize); 358*5f757f3fSDimitry Andric Current += PSize; 359*5f757f3fSDimitry Andric } 360*5f757f3fSDimitry Andric 361*5f757f3fSDimitry Andric ArrayRef<uint8_t> OutputVectorCounts = getOutputVectorCounts(); 362*5f757f3fSDimitry Andric uint8_t PatchConstOrPrimVectorCount = getPatchConstOrPrimVectorCount(); 363*5f757f3fSDimitry Andric uint8_t InputVectorCount = getInputVectorCount(); 364*5f757f3fSDimitry Andric 365*5f757f3fSDimitry Andric auto maskDwordSize = [](uint8_t Vector) { 366*5f757f3fSDimitry Andric return (static_cast<uint32_t>(Vector) + 7) >> 3; 367*5f757f3fSDimitry Andric }; 368*5f757f3fSDimitry Andric 369*5f757f3fSDimitry Andric auto mapTableSize = [maskDwordSize](uint8_t X, uint8_t Y) { 370*5f757f3fSDimitry Andric return maskDwordSize(Y) * X * 4; 371*5f757f3fSDimitry Andric }; 372*5f757f3fSDimitry Andric 373*5f757f3fSDimitry Andric if (usesViewID()) { 374*5f757f3fSDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) { 375*5f757f3fSDimitry Andric // The vector mask is one bit per component and 4 components per vector. 376*5f757f3fSDimitry Andric // We can compute the number of dwords required by rounding up to the next 377*5f757f3fSDimitry Andric // multiple of 8. 378*5f757f3fSDimitry Andric uint32_t NumDwords = 379*5f757f3fSDimitry Andric maskDwordSize(static_cast<uint32_t>(OutputVectorCounts[I])); 380*5f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 381*5f757f3fSDimitry Andric OutputVectorMasks[I].Data = Data.substr(Current - Data.begin(), NumBytes); 382*5f757f3fSDimitry Andric Current += NumBytes; 383*5f757f3fSDimitry Andric } 384*5f757f3fSDimitry Andric 385*5f757f3fSDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0) { 386*5f757f3fSDimitry Andric uint32_t NumDwords = maskDwordSize(PatchConstOrPrimVectorCount); 387*5f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 388*5f757f3fSDimitry Andric PatchOrPrimMasks.Data = Data.substr(Current - Data.begin(), NumBytes); 389*5f757f3fSDimitry Andric Current += NumBytes; 390*5f757f3fSDimitry Andric } 391*5f757f3fSDimitry Andric } 392*5f757f3fSDimitry Andric 393*5f757f3fSDimitry Andric // Input/Output mapping table 394*5f757f3fSDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) { 395*5f757f3fSDimitry Andric if (InputVectorCount == 0 || OutputVectorCounts[I] == 0) 396*5f757f3fSDimitry Andric continue; 397*5f757f3fSDimitry Andric uint32_t NumDwords = mapTableSize(InputVectorCount, OutputVectorCounts[I]); 398*5f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 399*5f757f3fSDimitry Andric InputOutputMap[I].Data = Data.substr(Current - Data.begin(), NumBytes); 400*5f757f3fSDimitry Andric Current += NumBytes; 401*5f757f3fSDimitry Andric } 402*5f757f3fSDimitry Andric 403*5f757f3fSDimitry Andric // Hull shader: Input/Patch mapping table 404*5f757f3fSDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0 && 405*5f757f3fSDimitry Andric InputVectorCount > 0) { 406*5f757f3fSDimitry Andric uint32_t NumDwords = 407*5f757f3fSDimitry Andric mapTableSize(InputVectorCount, PatchConstOrPrimVectorCount); 408*5f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 409*5f757f3fSDimitry Andric InputPatchMap.Data = Data.substr(Current - Data.begin(), NumBytes); 410*5f757f3fSDimitry Andric Current += NumBytes; 411*5f757f3fSDimitry Andric } 412*5f757f3fSDimitry Andric 413*5f757f3fSDimitry Andric // Domain Shader: Patch/Output mapping table 414*5f757f3fSDimitry Andric if (ShaderStage == Triple::Domain && PatchConstOrPrimVectorCount > 0 && 415*5f757f3fSDimitry Andric OutputVectorCounts[0] > 0) { 416*5f757f3fSDimitry Andric uint32_t NumDwords = 417*5f757f3fSDimitry Andric mapTableSize(PatchConstOrPrimVectorCount, OutputVectorCounts[0]); 418*5f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 419*5f757f3fSDimitry Andric PatchOutputMap.Data = Data.substr(Current - Data.begin(), NumBytes); 420*5f757f3fSDimitry Andric Current += NumBytes; 42106c3fb27SDimitry Andric } 42206c3fb27SDimitry Andric 42306c3fb27SDimitry Andric return Error::success(); 42406c3fb27SDimitry Andric } 425*5f757f3fSDimitry Andric 426*5f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const { 427*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 428*5f757f3fSDimitry Andric return P->SigInputElements; 429*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 430*5f757f3fSDimitry Andric return P->SigInputElements; 431*5f757f3fSDimitry Andric return 0; 432*5f757f3fSDimitry Andric } 433*5f757f3fSDimitry Andric 434*5f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const { 435*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 436*5f757f3fSDimitry Andric return P->SigOutputElements; 437*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 438*5f757f3fSDimitry Andric return P->SigOutputElements; 439*5f757f3fSDimitry Andric return 0; 440*5f757f3fSDimitry Andric } 441*5f757f3fSDimitry Andric 442*5f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const { 443*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 444*5f757f3fSDimitry Andric return P->SigPatchOrPrimElements; 445*5f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 446*5f757f3fSDimitry Andric return P->SigPatchOrPrimElements; 447*5f757f3fSDimitry Andric return 0; 448*5f757f3fSDimitry Andric } 449