brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.0 KiB · b00e45d Raw
409 lines · cpp
1//===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// Binary emitter for yaml to DXContainer binary11///12//===----------------------------------------------------------------------===//13 14#include "llvm/BinaryFormat/DXContainer.h"15#include "llvm/MC/DXContainerPSVInfo.h"16#include "llvm/MC/DXContainerRootSignature.h"17#include "llvm/ObjectYAML/ObjectYAML.h"18#include "llvm/ObjectYAML/yaml2obj.h"19#include "llvm/Support/Errc.h"20#include "llvm/Support/Error.h"21#include "llvm/Support/raw_ostream.h"22 23using namespace llvm;24 25namespace {26class DXContainerWriter {27public:28  DXContainerWriter(DXContainerYAML::Object &ObjectFile)29      : ObjectFile(ObjectFile) {}30 31  Error write(raw_ostream &OS);32 33private:34  DXContainerYAML::Object &ObjectFile;35 36  Error computePartOffsets();37  Error validatePartOffsets();38  Error validateSize(uint32_t Computed);39 40  void writeHeader(raw_ostream &OS);41  Error writeParts(raw_ostream &OS);42};43} // namespace44 45Error DXContainerWriter::validateSize(uint32_t Computed) {46  if (!ObjectFile.Header.FileSize)47    ObjectFile.Header.FileSize = Computed;48  else if (*ObjectFile.Header.FileSize < Computed)49    return createStringError(errc::result_out_of_range,50                             "File size specified is too small.");51  return Error::success();52}53 54Error DXContainerWriter::validatePartOffsets() {55  if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())56    return createStringError(57        errc::invalid_argument,58        "Mismatch between number of parts and part offsets.");59  uint32_t RollingOffset =60      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));61  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {62    if (RollingOffset > std::get<1>(I))63      return createStringError(errc::invalid_argument,64                               "Offset mismatch, not enough space for data.");65    RollingOffset =66        std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;67  }68  if (Error Err = validateSize(RollingOffset))69    return Err;70 71  return Error::success();72}73 74Error DXContainerWriter::computePartOffsets() {75  if (ObjectFile.Header.PartOffsets)76    return validatePartOffsets();77  uint32_t RollingOffset =78      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));79  ObjectFile.Header.PartOffsets = std::vector<uint32_t>();80  for (const auto &Part : ObjectFile.Parts) {81    ObjectFile.Header.PartOffsets->push_back(RollingOffset);82    RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;83  }84  if (Error Err = validateSize(RollingOffset))85    return Err;86 87  return Error::success();88}89 90void DXContainerWriter::writeHeader(raw_ostream &OS) {91  dxbc::Header Header;92  memcpy(Header.Magic, "DXBC", 4);93  memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);94  Header.Version.Major = ObjectFile.Header.Version.Major;95  Header.Version.Minor = ObjectFile.Header.Version.Minor;96  Header.FileSize = *ObjectFile.Header.FileSize;97  Header.PartCount = ObjectFile.Parts.size();98  if (sys::IsBigEndianHost)99    Header.swapBytes();100  OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));101  SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),102                                ObjectFile.Header.PartOffsets->end());103  if (sys::IsBigEndianHost)104    for (auto &O : Offsets)105      sys::swapByteOrder(O);106  OS.write(reinterpret_cast<char *>(Offsets.data()),107           Offsets.size() * sizeof(uint32_t));108}109 110Error DXContainerWriter::writeParts(raw_ostream &OS) {111  uint32_t RollingOffset =112      sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));113  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {114    if (RollingOffset < std::get<1>(I)) {115      uint32_t PadBytes = std::get<1>(I) - RollingOffset;116      OS.write_zeros(PadBytes);117    }118    DXContainerYAML::Part P = std::get<0>(I);119    RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);120    uint32_t PartSize = P.Size;121 122    OS.write(P.Name.c_str(), 4);123    if (sys::IsBigEndianHost)124      sys::swapByteOrder(P.Size);125    OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));126 127    dxbc::PartType PT = dxbc::parsePartType(P.Name);128 129    uint64_t DataStart = OS.tell();130    switch (PT) {131    case dxbc::PartType::DXIL: {132      if (!P.Program)133        continue;134      dxbc::ProgramHeader Header;135      Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,136                                                       P.Program->MinorVersion);137      Header.Unused = 0;138      Header.ShaderKind = P.Program->ShaderKind;139      memcpy(Header.Bitcode.Magic, "DXIL", 4);140      Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;141      Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;142      Header.Bitcode.Unused = 0;143 144      // Compute the optional fields if needed...145      if (P.Program->DXILOffset)146        Header.Bitcode.Offset = *P.Program->DXILOffset;147      else148        Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);149 150      if (P.Program->DXILSize)151        Header.Bitcode.Size = *P.Program->DXILSize;152      else153        Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;154 155      if (P.Program->Size)156        Header.Size = *P.Program->Size;157      else158        Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;159 160      uint32_t BitcodeOffset = Header.Bitcode.Offset;161      if (sys::IsBigEndianHost)162        Header.swapBytes();163      OS.write(reinterpret_cast<const char *>(&Header),164               sizeof(dxbc::ProgramHeader));165      if (P.Program->DXIL) {166        if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {167          uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);168          OS.write_zeros(PadBytes);169        }170        OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),171                 P.Program->DXIL->size());172      }173      break;174    }175    case dxbc::PartType::SFI0: {176      // If we don't have any flags we can continue here and the data will be177      // zeroed out.178      if (!P.Flags.has_value())179        continue;180      uint64_t Flags = P.Flags->getEncodedFlags();181      if (sys::IsBigEndianHost)182        sys::swapByteOrder(Flags);183      OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));184      break;185    }186    case dxbc::PartType::HASH: {187      if (!P.Hash.has_value())188        continue;189      dxbc::ShaderHash Hash = {0, {0}};190      if (P.Hash->IncludesSource)191        Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);192      memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);193      if (sys::IsBigEndianHost)194        Hash.swapBytes();195      OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));196      break;197    }198    case dxbc::PartType::PSV0: {199      if (!P.Info.has_value())200        continue;201      mcdxbc::PSVRuntimeInfo PSV;202      memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));203      PSV.Resources = P.Info->Resources;204      PSV.EntryName = P.Info->EntryName;205 206      for (auto El : P.Info->SigInputElements)207        PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{208            El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,209            El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,210            El.Stream});211 212      for (auto El : P.Info->SigOutputElements)213        PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{214            El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,215            El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,216            El.Stream});217 218      for (auto El : P.Info->SigPatchOrPrimElements)219        PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{220            El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,221            El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,222            El.Stream});223 224      static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());225      for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {226        PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),227                                        P.Info->OutputVectorMasks[I].begin(),228                                        P.Info->OutputVectorMasks[I].end());229        PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),230                                     P.Info->InputOutputMap[I].begin(),231                                     P.Info->InputOutputMap[I].end());232      }233 234      PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),235                                  P.Info->PatchOrPrimMasks.begin(),236                                  P.Info->PatchOrPrimMasks.end());237      PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),238                               P.Info->InputPatchMap.begin(),239                               P.Info->InputPatchMap.end());240      PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),241                                P.Info->PatchOutputMap.begin(),242                                P.Info->PatchOutputMap.end());243 244      PSV.finalize(static_cast<Triple::EnvironmentType>(245          Triple::Pixel + P.Info->Info.ShaderStage));246      PSV.write(OS, P.Info->Version);247      break;248    }249    case dxbc::PartType::ISG1:250    case dxbc::PartType::OSG1:251    case dxbc::PartType::PSG1: {252      mcdxbc::Signature Sig;253      if (P.Signature.has_value()) {254        for (const auto &Param : P.Signature->Parameters) {255          Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,256                       Param.CompType, Param.Register, Param.Mask,257                       Param.ExclusiveMask, Param.MinPrecision);258        }259      }260      Sig.write(OS);261      break;262    }263    case dxbc::PartType::Unknown:264      break; // Skip any handling for unrecognized parts.265    case dxbc::PartType::RTS0:266      if (!P.RootSignature.has_value())267        continue;268 269      mcdxbc::RootSignatureDesc RS;270      RS.Flags = P.RootSignature->getEncodedFlags();271      RS.Version = P.RootSignature->Version;272      RS.NumStaticSamplers = P.RootSignature->NumStaticSamplers;273 274      for (DXContainerYAML::RootParameterLocationYaml &L :275           P.RootSignature->Parameters.Locations) {276 277        const dxbc::RootParameterType Type = L.Header.Type;278        const dxbc::ShaderVisibility Visibility = L.Header.Visibility;279 280        switch (Type) {281        case dxbc::RootParameterType::Constants32Bit: {282          const DXContainerYAML::RootConstantsYaml &ConstantYaml =283              P.RootSignature->Parameters.getOrInsertConstants(L);284          mcdxbc::RootConstants Constants;285 286          Constants.Num32BitValues = ConstantYaml.Num32BitValues;287          Constants.RegisterSpace = ConstantYaml.RegisterSpace;288          Constants.ShaderRegister = ConstantYaml.ShaderRegister;289          RS.ParametersContainer.addParameter(Type, Visibility, Constants);290          break;291        }292        case dxbc::RootParameterType::CBV:293        case dxbc::RootParameterType::SRV:294        case dxbc::RootParameterType::UAV: {295          const DXContainerYAML::RootDescriptorYaml &DescriptorYaml =296              P.RootSignature->Parameters.getOrInsertDescriptor(L);297 298          mcdxbc::RootDescriptor Descriptor;299          Descriptor.RegisterSpace = DescriptorYaml.RegisterSpace;300          Descriptor.ShaderRegister = DescriptorYaml.ShaderRegister;301          if (RS.Version > 1)302            Descriptor.Flags = DescriptorYaml.getEncodedFlags();303          RS.ParametersContainer.addParameter(Type, Visibility, Descriptor);304          break;305        }306        case dxbc::RootParameterType::DescriptorTable: {307          const DXContainerYAML::DescriptorTableYaml &TableYaml =308              P.RootSignature->Parameters.getOrInsertTable(L);309          mcdxbc::DescriptorTable Table;310          for (const auto &R : TableYaml.Ranges) {311            mcdxbc::DescriptorRange Range;312            Range.RangeType = R.RangeType;313            Range.NumDescriptors = R.NumDescriptors;314            Range.BaseShaderRegister = R.BaseShaderRegister;315            Range.RegisterSpace = R.RegisterSpace;316            Range.OffsetInDescriptorsFromTableStart =317                R.OffsetInDescriptorsFromTableStart;318 319            if (RS.Version > 1)320              Range.Flags = R.getEncodedFlags();321 322            Table.Ranges.push_back(Range);323          }324          RS.ParametersContainer.addParameter(Type, Visibility, Table);325          break;326        }327        }328      }329 330      for (const auto &Param : P.RootSignature->samplers()) {331        mcdxbc::StaticSampler NewSampler;332        NewSampler.Filter = Param.Filter;333        NewSampler.AddressU = Param.AddressU;334        NewSampler.AddressV = Param.AddressV;335        NewSampler.AddressW = Param.AddressW;336        NewSampler.MipLODBias = Param.MipLODBias;337        NewSampler.MaxAnisotropy = Param.MaxAnisotropy;338        NewSampler.ComparisonFunc = Param.ComparisonFunc;339        NewSampler.BorderColor = Param.BorderColor;340        NewSampler.MinLOD = Param.MinLOD;341        NewSampler.MaxLOD = Param.MaxLOD;342        NewSampler.ShaderRegister = Param.ShaderRegister;343        NewSampler.RegisterSpace = Param.RegisterSpace;344        NewSampler.ShaderVisibility = Param.ShaderVisibility;345 346        if (RS.Version > 2)347          NewSampler.Flags = Param.getEncodedFlags();348 349        RS.StaticSamplers.push_back(NewSampler);350      }351 352      // Handling of offsets353      RS.RootParameterOffset = RS.computeRootParametersOffset();354      if (P.RootSignature->RootParametersOffset &&355          P.RootSignature->RootParametersOffset.value() !=356              RS.RootParameterOffset) {357        return createStringError(358            errc::invalid_argument,359            "Specified RootParametersOffset does not match required value: %d.",360            RS.RootParameterOffset);361      }362 363      RS.StaticSamplersOffset = RS.computeStaticSamplersOffset();364      if (P.RootSignature->StaticSamplersOffset &&365          P.RootSignature->StaticSamplersOffset.value() !=366              RS.StaticSamplersOffset) {367        return createStringError(368            errc::invalid_argument,369            "Specified StaticSamplersOffset does not match computed value: %d.",370            RS.StaticSamplersOffset);371      }372 373      RS.write(OS);374      break;375    }376    uint64_t BytesWritten = OS.tell() - DataStart;377    RollingOffset += BytesWritten;378    if (BytesWritten < PartSize)379      OS.write_zeros(PartSize - BytesWritten);380    RollingOffset += PartSize;381  }382 383  return Error::success();384}385 386Error DXContainerWriter::write(raw_ostream &OS) {387  if (Error Err = computePartOffsets())388    return Err;389  writeHeader(OS);390  return writeParts(OS);391}392 393namespace llvm {394namespace yaml {395 396bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,397                      ErrorHandler EH) {398  DXContainerWriter Writer(Doc);399  if (Error Err = Writer.write(Out)) {400    handleAllErrors(std::move(Err),401                    [&](const ErrorInfoBase &Err) { EH(Err.message()); });402    return false;403  }404  return true;405}406 407} // namespace yaml408} // namespace llvm409