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" 125f757f3fSDimitry 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 75*0fca6ea1SDimitry Andric Error DXContainer::parseShaderFeatureFlags(StringRef Part) { 76*0fca6ea1SDimitry Andric if (ShaderFeatureFlags) 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; 81*0fca6ea1SDimitry Andric ShaderFeatureFlags = 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 1045f757f3fSDimitry Andric Error DirectX::Signature::initialize(StringRef Part) { 1055f757f3fSDimitry Andric dxbc::ProgramSignatureHeader SigHeader; 1065f757f3fSDimitry Andric if (Error Err = readStruct(Part, Part.begin(), SigHeader)) 1075f757f3fSDimitry Andric return Err; 1085f757f3fSDimitry Andric size_t Size = sizeof(dxbc::ProgramSignatureElement) * SigHeader.ParamCount; 1095f757f3fSDimitry Andric 1105f757f3fSDimitry Andric if (Part.size() < Size + SigHeader.FirstParamOffset) 1115f757f3fSDimitry Andric return parseFailed("Signature parameters extend beyond the part boundary"); 1125f757f3fSDimitry Andric 1135f757f3fSDimitry Andric Parameters.Data = Part.substr(SigHeader.FirstParamOffset, Size); 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric StringTableOffset = SigHeader.FirstParamOffset + static_cast<uint32_t>(Size); 1165f757f3fSDimitry Andric StringTable = Part.substr(SigHeader.FirstParamOffset + Size); 1175f757f3fSDimitry Andric 1185f757f3fSDimitry Andric for (const auto &Param : Parameters) { 1195f757f3fSDimitry Andric if (Param.NameOffset < StringTableOffset) 1205f757f3fSDimitry Andric return parseFailed("Invalid parameter name offset: name starts before " 1215f757f3fSDimitry Andric "the first name offset"); 1225f757f3fSDimitry Andric if (Param.NameOffset - StringTableOffset > StringTable.size()) 1235f757f3fSDimitry Andric return parseFailed("Invalid parameter name offset: name starts after the " 1245f757f3fSDimitry Andric "end of the part data"); 1255f757f3fSDimitry Andric } 1265f757f3fSDimitry Andric return Error::success(); 1275f757f3fSDimitry Andric } 1285f757f3fSDimitry 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: 171*0fca6ea1SDimitry Andric if (Error Err = parseShaderFeatureFlags(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; 1825f757f3fSDimitry Andric case dxbc::PartType::ISG1: 1835f757f3fSDimitry Andric if (Error Err = InputSignature.initialize(PartData)) 1845f757f3fSDimitry Andric return Err; 1855f757f3fSDimitry Andric break; 1865f757f3fSDimitry Andric case dxbc::PartType::OSG1: 1875f757f3fSDimitry Andric if (Error Err = OutputSignature.initialize(PartData)) 1885f757f3fSDimitry Andric return Err; 1895f757f3fSDimitry Andric break; 1905f757f3fSDimitry Andric case dxbc::PartType::PSG1: 1915f757f3fSDimitry Andric if (Error Err = PatchConstantSignature.initialize(PartData)) 1925f757f3fSDimitry Andric return Err; 1935f757f3fSDimitry 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. 250*0fca6ea1SDimitry Andric if (PSVVersion == 3) { 251*0fca6ea1SDimitry Andric v3::RuntimeInfo Info; 252*0fca6ea1SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info)) 253*0fca6ea1SDimitry Andric return Err; 254*0fca6ea1SDimitry Andric if (sys::IsBigEndianHost) 255*0fca6ea1SDimitry Andric Info.swapBytes(ShaderStage); 256*0fca6ea1SDimitry Andric BasicInfo = Info; 257*0fca6ea1SDimitry Andric } else if (PSVVersion == 2) { 25806c3fb27SDimitry Andric v2::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; 26406c3fb27SDimitry Andric } else if (PSVVersion == 1) { 26506c3fb27SDimitry Andric v1::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; 2715f757f3fSDimitry Andric } else if (PSVVersion == 0) { 27206c3fb27SDimitry Andric v0::RuntimeInfo Info; 27306c3fb27SDimitry Andric if (Error Err = readStruct(PSVInfoData, Current, Info)) 27406c3fb27SDimitry Andric return Err; 27506c3fb27SDimitry Andric if (sys::IsBigEndianHost) 27606c3fb27SDimitry Andric Info.swapBytes(ShaderStage); 27706c3fb27SDimitry Andric BasicInfo = Info; 2785f757f3fSDimitry Andric } else 2795f757f3fSDimitry Andric return parseFailed( 2805f757f3fSDimitry Andric "Cannot read PSV Runtime Info, unsupported PSV version."); 2815f757f3fSDimitry Andric 28206c3fb27SDimitry Andric Current += Size; 28306c3fb27SDimitry Andric 28406c3fb27SDimitry Andric uint32_t ResourceCount = 0; 28506c3fb27SDimitry Andric if (Error Err = readInteger(Data, Current, ResourceCount)) 28606c3fb27SDimitry Andric return Err; 28706c3fb27SDimitry Andric Current += sizeof(uint32_t); 28806c3fb27SDimitry Andric 28906c3fb27SDimitry Andric if (ResourceCount > 0) { 29006c3fb27SDimitry Andric if (Error Err = readInteger(Data, Current, Resources.Stride)) 29106c3fb27SDimitry Andric return Err; 29206c3fb27SDimitry Andric Current += sizeof(uint32_t); 29306c3fb27SDimitry Andric 29406c3fb27SDimitry Andric size_t BindingDataSize = Resources.Stride * ResourceCount; 29506c3fb27SDimitry Andric Resources.Data = Data.substr(Current - Data.begin(), BindingDataSize); 29606c3fb27SDimitry Andric 29706c3fb27SDimitry Andric if (Resources.Data.size() < BindingDataSize) 29806c3fb27SDimitry Andric return parseFailed( 29906c3fb27SDimitry Andric "Resource binding data extends beyond the bounds of the part"); 30006c3fb27SDimitry Andric 30106c3fb27SDimitry Andric Current += BindingDataSize; 3025f757f3fSDimitry Andric } else 3035f757f3fSDimitry Andric Resources.Stride = sizeof(v2::ResourceBindInfo); 3045f757f3fSDimitry Andric 3055f757f3fSDimitry Andric // PSV version 0 ends after the resource bindings. 3065f757f3fSDimitry Andric if (PSVVersion == 0) 3075f757f3fSDimitry Andric return Error::success(); 3085f757f3fSDimitry Andric 3095f757f3fSDimitry Andric // String table starts at a 4-byte offset. 3105f757f3fSDimitry Andric Current = reinterpret_cast<const char *>( 3115f757f3fSDimitry Andric alignTo<4>(reinterpret_cast<uintptr_t>(Current))); 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric uint32_t StringTableSize = 0; 3145f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, StringTableSize)) 3155f757f3fSDimitry Andric return Err; 3165f757f3fSDimitry Andric if (StringTableSize % 4 != 0) 3175f757f3fSDimitry Andric return parseFailed("String table misaligned"); 3185f757f3fSDimitry Andric Current += sizeof(uint32_t); 3195f757f3fSDimitry Andric StringTable = StringRef(Current, StringTableSize); 3205f757f3fSDimitry Andric 3215f757f3fSDimitry Andric Current += StringTableSize; 3225f757f3fSDimitry Andric 3235f757f3fSDimitry Andric uint32_t SemanticIndexTableSize = 0; 3245f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, SemanticIndexTableSize)) 3255f757f3fSDimitry Andric return Err; 3265f757f3fSDimitry Andric Current += sizeof(uint32_t); 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric SemanticIndexTable.reserve(SemanticIndexTableSize); 3295f757f3fSDimitry Andric for (uint32_t I = 0; I < SemanticIndexTableSize; ++I) { 3305f757f3fSDimitry Andric uint32_t Index = 0; 3315f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, Index)) 3325f757f3fSDimitry Andric return Err; 3335f757f3fSDimitry Andric Current += sizeof(uint32_t); 3345f757f3fSDimitry Andric SemanticIndexTable.push_back(Index); 3355f757f3fSDimitry Andric } 3365f757f3fSDimitry Andric 3375f757f3fSDimitry Andric uint8_t InputCount = getSigInputCount(); 3385f757f3fSDimitry Andric uint8_t OutputCount = getSigOutputCount(); 3395f757f3fSDimitry Andric uint8_t PatchOrPrimCount = getSigPatchOrPrimCount(); 3405f757f3fSDimitry Andric 3415f757f3fSDimitry Andric uint32_t ElementCount = InputCount + OutputCount + PatchOrPrimCount; 3425f757f3fSDimitry Andric 3435f757f3fSDimitry Andric if (ElementCount > 0) { 3445f757f3fSDimitry Andric if (Error Err = readInteger(Data, Current, SigInputElements.Stride)) 3455f757f3fSDimitry Andric return Err; 3465f757f3fSDimitry Andric Current += sizeof(uint32_t); 3475f757f3fSDimitry Andric // Assign the stride to all the arrays. 3485f757f3fSDimitry Andric SigOutputElements.Stride = SigPatchOrPrimElements.Stride = 3495f757f3fSDimitry Andric SigInputElements.Stride; 3505f757f3fSDimitry Andric 351*0fca6ea1SDimitry Andric if (Data.end() - Current < 352*0fca6ea1SDimitry Andric (ptrdiff_t)(ElementCount * SigInputElements.Stride)) 3535f757f3fSDimitry Andric return parseFailed( 3545f757f3fSDimitry Andric "Signature elements extend beyond the size of the part"); 3555f757f3fSDimitry Andric 3565f757f3fSDimitry Andric size_t InputSize = SigInputElements.Stride * InputCount; 3575f757f3fSDimitry Andric SigInputElements.Data = Data.substr(Current - Data.begin(), InputSize); 3585f757f3fSDimitry Andric Current += InputSize; 3595f757f3fSDimitry Andric 3605f757f3fSDimitry Andric size_t OutputSize = SigOutputElements.Stride * OutputCount; 3615f757f3fSDimitry Andric SigOutputElements.Data = Data.substr(Current - Data.begin(), OutputSize); 3625f757f3fSDimitry Andric Current += OutputSize; 3635f757f3fSDimitry Andric 3645f757f3fSDimitry Andric size_t PSize = SigPatchOrPrimElements.Stride * PatchOrPrimCount; 3655f757f3fSDimitry Andric SigPatchOrPrimElements.Data = Data.substr(Current - Data.begin(), PSize); 3665f757f3fSDimitry Andric Current += PSize; 3675f757f3fSDimitry Andric } 3685f757f3fSDimitry Andric 3695f757f3fSDimitry Andric ArrayRef<uint8_t> OutputVectorCounts = getOutputVectorCounts(); 3705f757f3fSDimitry Andric uint8_t PatchConstOrPrimVectorCount = getPatchConstOrPrimVectorCount(); 3715f757f3fSDimitry Andric uint8_t InputVectorCount = getInputVectorCount(); 3725f757f3fSDimitry Andric 3735f757f3fSDimitry Andric auto maskDwordSize = [](uint8_t Vector) { 3745f757f3fSDimitry Andric return (static_cast<uint32_t>(Vector) + 7) >> 3; 3755f757f3fSDimitry Andric }; 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric auto mapTableSize = [maskDwordSize](uint8_t X, uint8_t Y) { 3785f757f3fSDimitry Andric return maskDwordSize(Y) * X * 4; 3795f757f3fSDimitry Andric }; 3805f757f3fSDimitry Andric 3815f757f3fSDimitry Andric if (usesViewID()) { 3825f757f3fSDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) { 3835f757f3fSDimitry Andric // The vector mask is one bit per component and 4 components per vector. 3845f757f3fSDimitry Andric // We can compute the number of dwords required by rounding up to the next 3855f757f3fSDimitry Andric // multiple of 8. 3865f757f3fSDimitry Andric uint32_t NumDwords = 3875f757f3fSDimitry Andric maskDwordSize(static_cast<uint32_t>(OutputVectorCounts[I])); 3885f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 3895f757f3fSDimitry Andric OutputVectorMasks[I].Data = Data.substr(Current - Data.begin(), NumBytes); 3905f757f3fSDimitry Andric Current += NumBytes; 3915f757f3fSDimitry Andric } 3925f757f3fSDimitry Andric 3935f757f3fSDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0) { 3945f757f3fSDimitry Andric uint32_t NumDwords = maskDwordSize(PatchConstOrPrimVectorCount); 3955f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 3965f757f3fSDimitry Andric PatchOrPrimMasks.Data = Data.substr(Current - Data.begin(), NumBytes); 3975f757f3fSDimitry Andric Current += NumBytes; 3985f757f3fSDimitry Andric } 3995f757f3fSDimitry Andric } 4005f757f3fSDimitry Andric 4015f757f3fSDimitry Andric // Input/Output mapping table 4025f757f3fSDimitry Andric for (uint32_t I = 0; I < OutputVectorCounts.size(); ++I) { 4035f757f3fSDimitry Andric if (InputVectorCount == 0 || OutputVectorCounts[I] == 0) 4045f757f3fSDimitry Andric continue; 4055f757f3fSDimitry Andric uint32_t NumDwords = mapTableSize(InputVectorCount, OutputVectorCounts[I]); 4065f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 4075f757f3fSDimitry Andric InputOutputMap[I].Data = Data.substr(Current - Data.begin(), NumBytes); 4085f757f3fSDimitry Andric Current += NumBytes; 4095f757f3fSDimitry Andric } 4105f757f3fSDimitry Andric 4115f757f3fSDimitry Andric // Hull shader: Input/Patch mapping table 4125f757f3fSDimitry Andric if (ShaderStage == Triple::Hull && PatchConstOrPrimVectorCount > 0 && 4135f757f3fSDimitry Andric InputVectorCount > 0) { 4145f757f3fSDimitry Andric uint32_t NumDwords = 4155f757f3fSDimitry Andric mapTableSize(InputVectorCount, PatchConstOrPrimVectorCount); 4165f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 4175f757f3fSDimitry Andric InputPatchMap.Data = Data.substr(Current - Data.begin(), NumBytes); 4185f757f3fSDimitry Andric Current += NumBytes; 4195f757f3fSDimitry Andric } 4205f757f3fSDimitry Andric 4215f757f3fSDimitry Andric // Domain Shader: Patch/Output mapping table 4225f757f3fSDimitry Andric if (ShaderStage == Triple::Domain && PatchConstOrPrimVectorCount > 0 && 4235f757f3fSDimitry Andric OutputVectorCounts[0] > 0) { 4245f757f3fSDimitry Andric uint32_t NumDwords = 4255f757f3fSDimitry Andric mapTableSize(PatchConstOrPrimVectorCount, OutputVectorCounts[0]); 4265f757f3fSDimitry Andric size_t NumBytes = NumDwords * sizeof(uint32_t); 4275f757f3fSDimitry Andric PatchOutputMap.Data = Data.substr(Current - Data.begin(), NumBytes); 4285f757f3fSDimitry Andric Current += NumBytes; 42906c3fb27SDimitry Andric } 43006c3fb27SDimitry Andric 43106c3fb27SDimitry Andric return Error::success(); 43206c3fb27SDimitry Andric } 4335f757f3fSDimitry Andric 4345f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const { 435*0fca6ea1SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) 436*0fca6ea1SDimitry Andric return P->SigInputElements; 4375f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 4385f757f3fSDimitry Andric return P->SigInputElements; 4395f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 4405f757f3fSDimitry Andric return P->SigInputElements; 4415f757f3fSDimitry Andric return 0; 4425f757f3fSDimitry Andric } 4435f757f3fSDimitry Andric 4445f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const { 445*0fca6ea1SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) 446*0fca6ea1SDimitry Andric return P->SigOutputElements; 4475f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 4485f757f3fSDimitry Andric return P->SigOutputElements; 4495f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 4505f757f3fSDimitry Andric return P->SigOutputElements; 4515f757f3fSDimitry Andric return 0; 4525f757f3fSDimitry Andric } 4535f757f3fSDimitry Andric 4545f757f3fSDimitry Andric uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const { 455*0fca6ea1SDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) 456*0fca6ea1SDimitry Andric return P->SigPatchOrPrimElements; 4575f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) 4585f757f3fSDimitry Andric return P->SigPatchOrPrimElements; 4595f757f3fSDimitry Andric if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) 4605f757f3fSDimitry Andric return P->SigPatchOrPrimElements; 4615f757f3fSDimitry Andric return 0; 4625f757f3fSDimitry Andric } 463