Viewing file: DXContainer.h (12.05 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===- DXContainer.h - DXContainer file implementation ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares the DXContainerFile class, which implements the ObjectFile // interface for DXContainer files. // // //===----------------------------------------------------------------------===//
#ifndef LLVM_OBJECT_DXCONTAINER_H #define LLVM_OBJECT_DXCONTAINER_H
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/DXContainer.h" #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/TargetParser/Triple.h" #include <array> #include <variant>
namespace llvm { namespace object {
namespace detail { template <typename T> std::enable_if_t<std::is_arithmetic<T>::value, void> swapBytes(T &value) { sys::swapByteOrder(value); }
template <typename T> std::enable_if_t<std::is_class<T>::value, void> swapBytes(T &value) { value.swapBytes(); } } // namespace detail
// This class provides a view into the underlying resource array. The Resource // data is little-endian encoded and may not be properly aligned to read // directly from. The dereference operator creates a copy of the data and byte // swaps it as appropriate. template <typename T> struct ViewArray { StringRef Data; uint32_t Stride = sizeof(T); // size of each element in the list.
ViewArray() = default; ViewArray(StringRef D, size_t S) : Data(D), Stride(S) {}
using value_type = T; static constexpr uint32_t MaxStride() { return static_cast<uint32_t>(sizeof(value_type)); }
struct iterator { StringRef Data; uint32_t Stride; // size of each element in the list. const char *Current;
iterator(const ViewArray &A, const char *C) : Data(A.Data), Stride(A.Stride), Current(C) {} iterator(const iterator &) = default;
value_type operator*() { // Explicitly zero the structure so that unused fields are zeroed. It is // up to the user to know if the fields are used by verifying the PSV // version. value_type Val; std::memset(&Val, 0, sizeof(value_type)); if (Current >= Data.end()) return Val; memcpy(static_cast<void *>(&Val), Current, std::min(Stride, MaxStride())); if (sys::IsBigEndianHost) detail::swapBytes(Val); return Val; }
iterator operator++() { if (Current < Data.end()) Current += Stride; return *this; }
iterator operator++(int) { iterator Tmp = *this; ++*this; return Tmp; }
iterator operator--() { if (Current > Data.begin()) Current -= Stride; return *this; }
iterator operator--(int) { iterator Tmp = *this; --*this; return Tmp; }
bool operator==(const iterator I) { return I.Current == Current; } bool operator!=(const iterator I) { return !(*this == I); } };
iterator begin() const { return iterator(*this, Data.begin()); }
iterator end() const { return iterator(*this, Data.end()); }
size_t size() const { return Data.size() / Stride; }
bool isEmpty() const { return Data.empty(); } };
namespace DirectX { class PSVRuntimeInfo {
using ResourceArray = ViewArray<dxbc::PSV::v2::ResourceBindInfo>; using SigElementArray = ViewArray<dxbc::PSV::v0::SignatureElement>;
StringRef Data; uint32_t Size; using InfoStruct = std::variant<std::monostate, dxbc::PSV::v0::RuntimeInfo, dxbc::PSV::v1::RuntimeInfo, dxbc::PSV::v2::RuntimeInfo, dxbc::PSV::v3::RuntimeInfo>; InfoStruct BasicInfo; ResourceArray Resources; StringRef StringTable; SmallVector<uint32_t> SemanticIndexTable; SigElementArray SigInputElements; SigElementArray SigOutputElements; SigElementArray SigPatchOrPrimElements;
std::array<ViewArray<uint32_t>, 4> OutputVectorMasks; ViewArray<uint32_t> PatchOrPrimMasks; std::array<ViewArray<uint32_t>, 4> InputOutputMap; ViewArray<uint32_t> InputPatchMap; ViewArray<uint32_t> PatchOutputMap;
public: PSVRuntimeInfo(StringRef D) : Data(D), Size(0) {}
// Parsing depends on the shader kind Error parse(uint16_t ShaderKind);
uint32_t getSize() const { return Size; } uint32_t getResourceCount() const { return Resources.size(); } ResourceArray getResources() const { return Resources; }
uint32_t getVersion() const { return Size >= sizeof(dxbc::PSV::v3::RuntimeInfo) ? 3 : (Size >= sizeof(dxbc::PSV::v2::RuntimeInfo) ? 2 : (Size >= sizeof(dxbc::PSV::v1::RuntimeInfo)) ? 1 : 0); }
uint32_t getResourceStride() const { return Resources.Stride; }
const InfoStruct &getInfo() const { return BasicInfo; }
template <typename T> const T *getInfoAs() const { if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) return static_cast<const T *>(P); if (std::is_same<T, dxbc::PSV::v3::RuntimeInfo>::value) return nullptr;
if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) return static_cast<const T *>(P); if (std::is_same<T, dxbc::PSV::v2::RuntimeInfo>::value) return nullptr;
if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) return static_cast<const T *>(P); if (std::is_same<T, dxbc::PSV::v1::RuntimeInfo>::value) return nullptr;
if (const auto *P = std::get_if<dxbc::PSV::v0::RuntimeInfo>(&BasicInfo)) return static_cast<const T *>(P); return nullptr; }
StringRef getStringTable() const { return StringTable; } ArrayRef<uint32_t> getSemanticIndexTable() const { return SemanticIndexTable; }
uint8_t getSigInputCount() const; uint8_t getSigOutputCount() const; uint8_t getSigPatchOrPrimCount() const;
SigElementArray getSigInputElements() const { return SigInputElements; } SigElementArray getSigOutputElements() const { return SigOutputElements; } SigElementArray getSigPatchOrPrimElements() const { return SigPatchOrPrimElements; }
ViewArray<uint32_t> getOutputVectorMasks(size_t Idx) const { assert(Idx < 4); return OutputVectorMasks[Idx]; }
ViewArray<uint32_t> getPatchOrPrimMasks() const { return PatchOrPrimMasks; }
ViewArray<uint32_t> getInputOutputMap(size_t Idx) const { assert(Idx < 4); return InputOutputMap[Idx]; }
ViewArray<uint32_t> getInputPatchMap() const { return InputPatchMap; } ViewArray<uint32_t> getPatchOutputMap() const { return PatchOutputMap; }
uint32_t getSigElementStride() const { return SigInputElements.Stride; }
bool usesViewID() const { if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>()) return P->UsesViewID != 0; return false; }
uint8_t getInputVectorCount() const { if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>()) return P->SigInputVectors; return 0; }
ArrayRef<uint8_t> getOutputVectorCounts() const { if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>()) return ArrayRef<uint8_t>(P->SigOutputVectors); return ArrayRef<uint8_t>(); }
uint8_t getPatchConstOrPrimVectorCount() const { if (const auto *P = getInfoAs<dxbc::PSV::v1::RuntimeInfo>()) return P->GeomData.SigPatchConstOrPrimVectors; return 0; } };
class Signature { ViewArray<dxbc::ProgramSignatureElement> Parameters; uint32_t StringTableOffset; StringRef StringTable;
public: ViewArray<dxbc::ProgramSignatureElement>::iterator begin() const { return Parameters.begin(); }
ViewArray<dxbc::ProgramSignatureElement>::iterator end() const { return Parameters.end(); }
StringRef getName(uint32_t Offset) const { assert(Offset >= StringTableOffset && Offset < StringTableOffset + StringTable.size() && "Offset out of range."); // Name offsets are from the start of the signature data, not from the start // of the string table. The header encodes the start offset of the sting // table, so we convert the offset here. uint32_t TableOffset = Offset - StringTableOffset; return StringTable.slice(TableOffset, StringTable.find('\0', TableOffset)); }
bool isEmpty() const { return Parameters.isEmpty(); }
Error initialize(StringRef Part); };
} // namespace DirectX
class DXContainer { public: using DXILData = std::pair<dxbc::ProgramHeader, const char *>;
private: DXContainer(MemoryBufferRef O);
MemoryBufferRef Data; dxbc::Header Header; SmallVector<uint32_t, 4> PartOffsets; std::optional<DXILData> DXIL; std::optional<uint64_t> ShaderFeatureFlags; std::optional<dxbc::ShaderHash> Hash; std::optional<DirectX::PSVRuntimeInfo> PSVInfo; DirectX::Signature InputSignature; DirectX::Signature OutputSignature; DirectX::Signature PatchConstantSignature;
Error parseHeader(); Error parsePartOffsets(); Error parseDXILHeader(StringRef Part); Error parseShaderFeatureFlags(StringRef Part); Error parseHash(StringRef Part); Error parsePSVInfo(StringRef Part); Error parseSignature(StringRef Part, DirectX::Signature &Array); friend class PartIterator;
public: // The PartIterator is a wrapper around the iterator for the PartOffsets // member of the DXContainer. It contains a refernce to the container, and the // current iterator value, as well as storage for a parsed part header. class PartIterator { const DXContainer &Container; SmallVectorImpl<uint32_t>::const_iterator OffsetIt; struct PartData { dxbc::PartHeader Part; uint32_t Offset; StringRef Data; } IteratorState;
friend class DXContainer;
PartIterator(const DXContainer &C, SmallVectorImpl<uint32_t>::const_iterator It) : Container(C), OffsetIt(It) { if (OffsetIt == Container.PartOffsets.end()) updateIteratorImpl(Container.PartOffsets.back()); else updateIterator(); }
// Updates the iterator's state data. This results in copying the part // header into the iterator and handling any required byte swapping. This is // called when incrementing or decrementing the iterator. void updateIterator() { if (OffsetIt != Container.PartOffsets.end()) updateIteratorImpl(*OffsetIt); }
// Implementation for updating the iterator state based on a specified // offest. void updateIteratorImpl(const uint32_t Offset);
public: PartIterator &operator++() { if (OffsetIt == Container.PartOffsets.end()) return *this; ++OffsetIt; updateIterator(); return *this; }
PartIterator operator++(int) { PartIterator Tmp = *this; ++(*this); return Tmp; }
bool operator==(const PartIterator &RHS) const { return OffsetIt == RHS.OffsetIt; }
bool operator!=(const PartIterator &RHS) const { return OffsetIt != RHS.OffsetIt; }
const PartData &operator*() { return IteratorState; } const PartData *operator->() { return &IteratorState; } };
PartIterator begin() const { return PartIterator(*this, PartOffsets.begin()); }
PartIterator end() const { return PartIterator(*this, PartOffsets.end()); }
StringRef getData() const { return Data.getBuffer(); } static Expected<DXContainer> create(MemoryBufferRef Object);
const dxbc::Header &getHeader() const { return Header; }
const std::optional<DXILData> &getDXIL() const { return DXIL; }
std::optional<uint64_t> getShaderFeatureFlags() const { return ShaderFeatureFlags; }
std::optional<dxbc::ShaderHash> getShaderHash() const { return Hash; }
const std::optional<DirectX::PSVRuntimeInfo> &getPSVInfo() const { return PSVInfo; };
const DirectX::Signature &getInputSignature() const { return InputSignature; } const DirectX::Signature &getOutputSignature() const { return OutputSignature; } const DirectX::Signature &getPatchConstantSignature() const { return PatchConstantSignature; } };
} // namespace object } // namespace llvm
#endif // LLVM_OBJECT_DXCONTAINER_H
|