///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// DxilRootSignature.cpp                                                     //
// Copyright (C) Microsoft Corporation. All rights reserved.                 //
// This file is distributed under the University of Illinois Open Source     //
// License. See LICENSE.TXT for details.                                     //
//                                                                           //
// Provides support for manipulating root signature structures.              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "dxc/HLSL/DxilConstants.h"
#include "dxc/HLSL/DxilRootSignature.h"
#include "dxc/HLSL/DxilPipelineStateValidation.h"
#include "dxc/Support/Global.h"
#include "dxc/Support/WinIncludes.h"
#include "dxc/Support/FileIOHelper.h"
#include "dxc/dxcapi.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/DiagnosticPrinter.h"

#include <string>
#include <algorithm>
#include <utility>
#include <vector>
#include <set>

using namespace llvm;
using std::string;

namespace hlsl {

DEFINE_ENUM_FLAG_OPERATORS(DxilRootSignatureFlags)
DEFINE_ENUM_FLAG_OPERATORS(DxilRootDescriptorFlags)
DEFINE_ENUM_FLAG_OPERATORS(DxilDescriptorRangeType)
DEFINE_ENUM_FLAG_OPERATORS(DxilDescriptorRangeFlags)

// Execute (error) and throw.
#define EAT(x) { (x); throw ::hlsl::Exception(E_FAIL); }

//////////////////////////////////////////////////////////////////////////////
// Root signature handler.

RootSignatureHandle::RootSignatureHandle(RootSignatureHandle&& other) {
  m_pDesc = nullptr;
  m_pSerialized = nullptr;
  std::swap(m_pDesc, other.m_pDesc);
  std::swap(m_pSerialized, other.m_pSerialized);
}

void RootSignatureHandle::Assign(const DxilVersionedRootSignatureDesc *pDesc,
                                 IDxcBlob *pSerialized) {
  Clear();
  m_pDesc = pDesc;
  m_pSerialized = pSerialized;
  if (m_pSerialized)
    m_pSerialized->AddRef();
}

void RootSignatureHandle::Clear() {
  hlsl::DeleteRootSignature(m_pDesc);
  m_pDesc = nullptr;
  if (m_pSerialized != nullptr) {
    m_pSerialized->Release();
    m_pSerialized = nullptr;
  }
}

const uint8_t *RootSignatureHandle::GetSerializedBytes() const {
  DXASSERT_NOMSG(m_pSerialized != nullptr);
  return (uint8_t *)m_pSerialized->GetBufferPointer();
}

unsigned RootSignatureHandle::GetSerializedSize() const {
  DXASSERT_NOMSG(m_pSerialized != nullptr);
  return m_pSerialized->GetBufferSize();
}

void RootSignatureHandle::EnsureSerializedAvailable() {
  DXASSERT_NOMSG(!IsEmpty());
  if (m_pSerialized == nullptr) {
    CComPtr<IDxcBlob> pResult;
    hlsl::SerializeRootSignature(m_pDesc, &pResult, nullptr, false);
    IFTBOOL(pResult != nullptr, E_FAIL);
    m_pSerialized = pResult.Detach();
  }
}

void RootSignatureHandle::Deserialize() {
  DXASSERT_NOMSG(m_pSerialized && !m_pDesc);
  DeserializeRootSignature((uint8_t*)m_pSerialized->GetBufferPointer(), (uint32_t)m_pSerialized->GetBufferSize(), &m_pDesc);
}

void RootSignatureHandle::LoadSerialized(const uint8_t *pData,
                                         unsigned length) {
  DXASSERT_NOMSG(IsEmpty());
  IDxcBlobEncoding *pCreated;
  IFT(DxcCreateBlobWithEncodingOnHeapCopy(pData, length, CP_UTF8, &pCreated));
  m_pSerialized = pCreated;
}

//////////////////////////////////////////////////////////////////////////////
// Simple serializer.

class SimpleSerializer {
  struct Segment {
    void *pData;
    unsigned cbSize;
    bool bOwner;
    unsigned Offset;
    Segment *pNext;
  };

public:
  SimpleSerializer();
  ~SimpleSerializer();

  HRESULT AddBlock(void *pData, unsigned cbSize, unsigned *pOffset);
  HRESULT ReserveBlock(void **ppData, unsigned cbSize, unsigned *pOffset);

  HRESULT Compact(_Out_writes_bytes_(cbSize) char *pData, unsigned cbSize);
  unsigned GetSize();

protected:
  unsigned m_cbSegments;
  Segment *m_pSegment;
  Segment **m_ppSegment;
};

SimpleSerializer::SimpleSerializer() {
  m_cbSegments = 0;
  m_pSegment = nullptr;
  m_ppSegment = &m_pSegment;
}

SimpleSerializer::~SimpleSerializer() {
  while (m_pSegment) {
    Segment *pSegment = m_pSegment;
    m_pSegment = pSegment->pNext;

    if (pSegment->bOwner) {
      delete pSegment->pData;
    }

    delete pSegment;
  }
}

HRESULT SimpleSerializer::AddBlock(void *pData, unsigned cbSize,
                                   unsigned *pOffset) {
  Segment *pSegment = nullptr;
  IFRBOOL(!(cbSize != 0 && pData == nullptr), E_FAIL);

  IFROOM(pSegment = new (std::nothrow) Segment);
  pSegment->pData = pData;

  m_cbSegments = (m_cbSegments + 3) & ~3;
  pSegment->Offset = m_cbSegments;
  pSegment->cbSize = cbSize;
  pSegment->bOwner = false;
  pSegment->pNext = nullptr;

  m_cbSegments += pSegment->cbSize;
  *m_ppSegment = pSegment;
  m_ppSegment = &pSegment->pNext;

  if (pOffset != nullptr) {
    *pOffset = pSegment->Offset;
  }

  return S_OK;
}

HRESULT SimpleSerializer::ReserveBlock(void **ppData, unsigned cbSize,
                                       unsigned *pOffset) {
  HRESULT hr = S_OK;
  Segment *pSegment = nullptr;
  void *pClonedData = nullptr;

  IFCOOM(pSegment = new (std::nothrow) Segment);
  pSegment->pData = nullptr;

  IFCOOM(pClonedData = new (std::nothrow) char[cbSize]);
  pSegment->pData = pClonedData;

  m_cbSegments = (m_cbSegments + 3) & ~3;
  pSegment->Offset = m_cbSegments;
  pSegment->cbSize = cbSize;
  pSegment->bOwner = true;
  pSegment->pNext = nullptr;

  m_cbSegments += pSegment->cbSize;
  *m_ppSegment = pSegment;
  m_ppSegment = &pSegment->pNext;

  *ppData = pClonedData;
  if (pOffset) {
    *pOffset = pSegment->Offset;
  }

Cleanup:
  if (FAILED(hr)) {
    delete[] pClonedData;
    delete pSegment;
  }
  return hr;
}

HRESULT SimpleSerializer::Compact(_Out_writes_bytes_(cbSize) char *pData,
                                  unsigned cbSize) {
  unsigned cb = GetSize();
  IFRBOOL(cb <= cbSize, E_FAIL);
  DXASSERT_NOMSG(cb <= UINT32_MAX / 2);

  char *p = (char *)pData;
  cb = 0;

  for (Segment *pSegment = m_pSegment; pSegment; pSegment = pSegment->pNext) {
    unsigned cbAlign = ((cb + 3) & ~3) - cb;

    _Analysis_assume_(p + cbAlign <= pData + cbSize);
    memset(p, 0xab, cbAlign);

    p += cbAlign;
    cb += cbAlign;

    _Analysis_assume_(p + pSegment->cbSize <= pData + cbSize);
    memcpy(p, pSegment->pData, pSegment->cbSize);

    p += pSegment->cbSize;
    cb += pSegment->cbSize;
  }

  // Trailing zeros
  _Analysis_assume_(p + cbSize - cb <= pData + cbSize);
  memset(p, 0xab, cbSize - cb);

  return S_OK;
}

unsigned SimpleSerializer::GetSize() {
  // Round up to 4==sizeof(unsigned).
  return ((m_cbSegments + 3) >> 2) * 4;
}

//////////////////////////////////////////////////////////////////////////////
// Interval helper.

template <typename T>
class CIntervalCollection {
private:
  std::set<T> m_set;
public:
  const T* FindIntersectingInterval(const T &I) {
    auto it = m_set.find(I);
    if (it != m_set.end())
      return &*it;
    return nullptr;
  }
  void Insert(const T& value) {
    auto result = m_set.insert(value);
    UNREFERENCED_PARAMETER(result);
#if DBG
    DXASSERT(result.second, "otherwise interval collides with existing in collection");
#endif
  }
};

//////////////////////////////////////////////////////////////////////////////
// Verifier classes.

class DescriptorTableVerifier {
public:
  void Verify(const DxilDescriptorRange1 *pRanges, unsigned NumRanges,
              unsigned iRTS, DiagnosticPrinter &DiagPrinter);
};

class StaticSamplerVerifier {
public:
  void Verify(const DxilStaticSamplerDesc *pDesc, DiagnosticPrinter &DiagPrinter);
};

class RootSignatureVerifier {
public:
  RootSignatureVerifier();
  ~RootSignatureVerifier();

  void AllowReservedRegisterSpace(bool bAllow);

  // Call this before calling VerifyShader, as it accumulates root signature state.
  void VerifyRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
                           DiagnosticPrinter &DiagPrinter);

  void VerifyShader(DxilShaderVisibility VisType,
                    const void *pPSVData,
                    uint32_t PSVSize,
                    DiagnosticPrinter &DiagPrinter);

  typedef enum NODE_TYPE {
    DESCRIPTOR_TABLE_ENTRY,
    ROOT_DESCRIPTOR,
    ROOT_CONSTANT,
    STATIC_SAMPLER
  } NODE_TYPE;

private:
  static const unsigned kMinVisType = (unsigned)DxilShaderVisibility::All;
  static const unsigned kMaxVisType = (unsigned)DxilShaderVisibility::Pixel;
  static const unsigned kMinDescType = (unsigned)DxilDescriptorRangeType::SRV;
  static const unsigned kMaxDescType = (unsigned)DxilDescriptorRangeType::Sampler;

  struct RegisterRange {
    NODE_TYPE nt;
    unsigned space;
    unsigned lb;    // inclusive lower bound
    unsigned ub;    // inclusive upper bound
    unsigned iRP;
    unsigned iDTS;
    // Sort by space, then lower bound.
    bool operator<(const RegisterRange& other) const {
      return space < other.space ||
        (space == other.space && ub < other.lb);
    }
    // Like a regular -1,0,1 comparison, but 0 indicates overlap.
    int overlap(const RegisterRange& other) const {
      if (space < other.space) return -1;
      if (space > other.space) return 1;
      if (ub < other.lb) return -1;
      if (lb > other.ub) return 1;
      return 0;
    }
    // Check containment.
    bool contains(const RegisterRange& other) const {
      return (space == other.space) && (lb <= other.lb && other.ub <= ub);
    }
  };
  typedef CIntervalCollection<RegisterRange> RegisterRanges;

  void AddRegisterRange(unsigned iRTS, NODE_TYPE nt, unsigned iDTS,
                        DxilDescriptorRangeType DescType,
                        DxilShaderVisibility VisType,
                        unsigned NumRegisters, unsigned BaseRegister,
                        unsigned RegisterSpace, DiagnosticPrinter &DiagPrinter);

  const RegisterRange *FindCoveringInterval(DxilDescriptorRangeType RangeType,
                                            DxilShaderVisibility VisType,
                                            unsigned Num,
                                            unsigned LB,
                                            unsigned Space);

  RegisterRanges &
  GetRanges(DxilShaderVisibility VisType, DxilDescriptorRangeType DescType) {
    return RangeKinds[(unsigned)VisType][(unsigned)DescType];
  }

  RegisterRanges RangeKinds[kMaxVisType + 1][kMaxDescType + 1];
  bool m_bAllowReservedRegisterSpace;
  DxilRootSignatureFlags m_RootSignatureFlags;
};

void DescriptorTableVerifier::Verify(const DxilDescriptorRange1 *pRanges,
                                     uint32_t NumRanges, uint32_t iRP,
                                     DiagnosticPrinter &DiagPrinter) {
  bool bHasSamplers = false;
  bool bHasResources = false;

  uint64_t iAppendStartSlot = 0;
  for (unsigned iDTS = 0; iDTS < NumRanges; iDTS++) {
    const DxilDescriptorRange1 *pRange = &pRanges[iDTS];

    switch (pRange->RangeType) {
    case DxilDescriptorRangeType::SRV:
    case DxilDescriptorRangeType::UAV:
    case DxilDescriptorRangeType::CBV:
      bHasResources = true;
      break;
    case DxilDescriptorRangeType::Sampler:
      bHasSamplers = true;
      break;
    default:
      EAT(DiagPrinter << "Unsupported RangeType value " << (uint32_t)pRange->RangeType
                      << " (descriptor table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
    }

    // Samplers cannot be mixed with other resources.
    if (bHasResources && bHasSamplers) {
      EAT(DiagPrinter << "Samplers cannot be mixed with other "
                      << "resource types in a descriptor table (root "
                      << "parameter [" << iRP << "]).\n");
    }

    // NumDescriptors is not 0.
    if (pRange->NumDescriptors == 0) {
      EAT(DiagPrinter << "NumDescriptors cannot be 0 (descriptor "
                      << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
    }

    // Range start.
    uint64_t iStartSlot = iAppendStartSlot;
    if (pRange->OffsetInDescriptorsFromTableStart != DxilDescriptorRangeOffsetAppend) {
      iStartSlot = pRange->OffsetInDescriptorsFromTableStart;
    }
    if (iStartSlot > UINT_MAX) {
      EAT(DiagPrinter << "Cannot append range with implicit lower "
                      << "bound after an unbounded range (descriptor "
                      << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
    }

    // Descriptor range and shader register range overlow.
    if (pRange->NumDescriptors != UINT_MAX) {
      // Bounded range.
      uint64_t ub1 = (uint64_t)pRange->BaseShaderRegister +
                     (uint64_t)pRange->NumDescriptors - 1ull;
      if (ub1 > UINT_MAX) {
        EAT(DiagPrinter << "Overflow for shader register range: "
                        << "BaseShaderRegister=" << pRange->BaseShaderRegister
                        << ", NumDescriptor=" << pRange->NumDescriptors
                        << "; (descriptor table slot [" << iDTS
                        << "], root parameter [" << iRP << "]).\n");
      }

      uint64_t ub2 = (uint64_t)iStartSlot + (uint64_t)pRange->NumDescriptors - 1ull;
      if (ub2 > UINT_MAX) {
        EAT(DiagPrinter << "Overflow for descriptor range (descriptor "
                        << "table slot [" << iDTS << "], root parameter [" << iRP << "])\n");
      }

      iAppendStartSlot = iStartSlot + (uint64_t)pRange->NumDescriptors;
    } else {
      // Unbounded range.
      iAppendStartSlot = 1ull + (uint64_t)UINT_MAX;
    }
  }
}

RootSignatureVerifier::RootSignatureVerifier() {
  m_RootSignatureFlags = DxilRootSignatureFlags::None;
  m_bAllowReservedRegisterSpace = false;
}

RootSignatureVerifier::~RootSignatureVerifier() {}

void RootSignatureVerifier::AllowReservedRegisterSpace(bool bAllow) {
  m_bAllowReservedRegisterSpace = bAllow;
}

const char* RangeTypeString(DxilDescriptorRangeType rt)
{
  static const char *RangeType[] = {"SRV", "UAV", "CBV", "SAMPLER"};
  return (rt <= DxilDescriptorRangeType::Sampler) ? RangeType[(unsigned)rt]
                                                  : "unknown";
}

const char *VisTypeString(DxilShaderVisibility vis) {
  static const char *Vis[] = {"ALL",    "VERTEX",   "HULL",
                              "DOMAIN", "GEOMETRY", "PIXEL"};
  unsigned idx = (unsigned)vis;
  return vis <= DxilShaderVisibility::Pixel ? Vis[idx] : "unknown";
}

static bool IsDxilShaderVisibility(DxilShaderVisibility v) {
  return v <= DxilShaderVisibility::Pixel;
}

void RootSignatureVerifier::AddRegisterRange(unsigned iRP,
                                             NODE_TYPE nt,
                                             unsigned iDTS,
                                             DxilDescriptorRangeType DescType,
                                             DxilShaderVisibility VisType,
                                             unsigned NumRegisters,
                                             unsigned BaseRegister,
                                             unsigned RegisterSpace,
                                             DiagnosticPrinter &DiagPrinter) {
  RegisterRange interval;
  interval.space = RegisterSpace;
  interval.lb = BaseRegister;
  interval.ub = (NumRegisters != UINT_MAX) ? BaseRegister + NumRegisters - 1 : UINT_MAX;
  interval.nt = nt;
  interval.iDTS = iDTS;
  interval.iRP = iRP;

  if (!m_bAllowReservedRegisterSpace &&
       (RegisterSpace >= DxilSystemReservedRegisterSpaceValuesStart) &&
       (RegisterSpace <= DxilSystemReservedRegisterSpaceValuesEnd)) {
    if (nt == DESCRIPTOR_TABLE_ENTRY) {
      EAT(DiagPrinter << "Root parameter [" << iRP << "] descriptor table entry [" << iDTS
                      << "] specifies RegisterSpace=" << std::hex << RegisterSpace
                      << ", which is invalid since RegisterSpace values in the range "
                      << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
                      << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
                      << "] are reserved for system use.\n");
    }
    else {
      EAT(DiagPrinter << "Root parameter [" << iRP
                      << "] specifies RegisterSpace=" << std::hex << RegisterSpace
                      << ", which is invalid since RegisterSpace values in the range "
                      << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
                      << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
                      << "] are reserved for system use.\n");
    }
  }

  const RegisterRange *pNode = nullptr;
  DxilShaderVisibility NodeVis = VisType;
  if (VisType == DxilShaderVisibility::All) {
    // Check for overlap with each visibility type.
    for (unsigned iVT = kMinVisType; iVT <= kMaxVisType; iVT++) {
      pNode = GetRanges((DxilShaderVisibility)iVT, DescType).FindIntersectingInterval(interval);
      if (pNode != nullptr)
        break;
    }
  } else {
    // Check for overlap with the same visibility.
    pNode = GetRanges(VisType, DescType).FindIntersectingInterval(interval);

    // Check for overlap with ALL visibility.
    if (pNode == nullptr) {
      pNode = GetRanges(DxilShaderVisibility::All, DescType).FindIntersectingInterval(interval);
      NodeVis = DxilShaderVisibility::All;
    }
  }

  if (pNode != nullptr) {
    const int strSize = 132;
    char testString[strSize];
    char nodeString[strSize];
    switch (nt) {
    case DESCRIPTOR_TABLE_ENTRY:
      StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s, descriptor table slot [%u])",
        iRP, VisTypeString(VisType), iDTS);
      break;
    case ROOT_DESCRIPTOR:
    case ROOT_CONSTANT:
      StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s)",
        iRP, VisTypeString(VisType));
      break;
    case STATIC_SAMPLER:
      StringCchPrintfA(testString, strSize, "(static sampler [%u], visibility %s)",
        iRP, VisTypeString(VisType));
      break;
    default:
      DXASSERT_NOMSG(false);
      break;
    }

    switch (pNode->nt)
    {
    case DESCRIPTOR_TABLE_ENTRY:
      StringCchPrintfA(nodeString, strSize, "(root parameter[%u], visibility %s, descriptor table slot [%u])",
        pNode->iRP, VisTypeString(NodeVis), pNode->iDTS);
      break;
    case ROOT_DESCRIPTOR:
    case ROOT_CONSTANT:
      StringCchPrintfA(nodeString, strSize, "(root parameter [%u], visibility %s)",
        pNode->iRP, VisTypeString(NodeVis));
      break;
    case STATIC_SAMPLER:
      StringCchPrintfA(nodeString, strSize, "(static sampler [%u], visibility %s)",
        pNode->iRP, VisTypeString(NodeVis));
      break;
    default:
      DXASSERT_NOMSG(false);
      break;
    }
    EAT(DiagPrinter << "Shader register range of type " << RangeTypeString(DescType)
                    << " " << testString << " overlaps with another "
                    << "shader register range " << nodeString << ".\n");
  }

  // Insert node.
  GetRanges(VisType, DescType).Insert(interval);
}

const RootSignatureVerifier::RegisterRange *
RootSignatureVerifier::FindCoveringInterval(DxilDescriptorRangeType RangeType,
                                            DxilShaderVisibility VisType,
                                            unsigned Num,
                                            unsigned LB,
                                            unsigned Space) {
  RegisterRange RR;
  RR.space = Space;
  RR.lb = LB;
  RR.ub = LB + Num - 1;
  const RootSignatureVerifier::RegisterRange *pRange = GetRanges(DxilShaderVisibility::All, RangeType).FindIntersectingInterval(RR);
  if (!pRange && VisType != DxilShaderVisibility::All) {
    pRange = GetRanges(VisType, RangeType).FindIntersectingInterval(RR);
  }
  if (pRange && !pRange->contains(RR)) {
    pRange = nullptr;
  }
  return pRange;
}

static DxilDescriptorRangeType GetRangeType(DxilRootParameterType RPT) {
  switch (RPT) {
  case DxilRootParameterType::CBV: return DxilDescriptorRangeType::CBV;
  case DxilRootParameterType::SRV: return DxilDescriptorRangeType::SRV;
  case DxilRootParameterType::UAV: return DxilDescriptorRangeType::UAV;
  default:
    break;
  }

  DXASSERT_NOMSG(false);
  return DxilDescriptorRangeType::SRV;
}

void RootSignatureVerifier::VerifyRootSignature(
                                const DxilVersionedRootSignatureDesc *pVersionedRootSignature,
                                DiagnosticPrinter &DiagPrinter) {
  const DxilVersionedRootSignatureDesc *pUpconvertedRS = nullptr;

  // Up-convert root signature to the latest RS version.
  ConvertRootSignature(pVersionedRootSignature, DxilRootSignatureVersion::Version_1_1, &pUpconvertedRS);
  DXASSERT_NOMSG(pUpconvertedRS->Version == DxilRootSignatureVersion::Version_1_1);

  // Ensure this gets deleted as necessary.
  struct SigGuard {
    const DxilVersionedRootSignatureDesc *Orig, *Guard;
    SigGuard(const DxilVersionedRootSignatureDesc *pOrig, const DxilVersionedRootSignatureDesc *pGuard)
      : Orig(pOrig), Guard(pGuard) { }
    ~SigGuard() {
      if (Orig != Guard) {
        DeleteRootSignature(Guard);
      }
    }
  };
  SigGuard S(pVersionedRootSignature, pUpconvertedRS);

  const DxilRootSignatureDesc1 *pRootSignature = &pUpconvertedRS->Desc_1_1;

  // Flags (assume they are bits that can be combined with OR).
  if ((pRootSignature->Flags & ~DxilRootSignatureFlags::ValidFlags) != DxilRootSignatureFlags::None) {
    EAT(DiagPrinter << "Unsupported bit-flag set (root signature flags " 
                    << std::hex << (uint32_t)pRootSignature->Flags << ").\n");
  }

  m_RootSignatureFlags = pRootSignature->Flags;

  for (unsigned iRP = 0; iRP < pRootSignature->NumParameters; iRP++) {
    const DxilRootParameter1 *pSlot = &pRootSignature->pParameters[iRP];
    // Shader visibility.
    DxilShaderVisibility Visibility = pSlot->ShaderVisibility;
    if (!IsDxilShaderVisibility(Visibility)) {
      EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
                      << " (root parameter [" << iRP << "]).\n");
    }

    DxilRootParameterType ParameterType = pSlot->ParameterType;
    switch (ParameterType) {
    case DxilRootParameterType::DescriptorTable: {
      DescriptorTableVerifier DTV;
      DTV.Verify(pSlot->DescriptorTable.pDescriptorRanges,
                 pSlot->DescriptorTable.NumDescriptorRanges, iRP, DiagPrinter);

      for (unsigned iDTS = 0; iDTS < pSlot->DescriptorTable.NumDescriptorRanges; iDTS++) {
        const DxilDescriptorRange1 *pRange = &pSlot->DescriptorTable.pDescriptorRanges[iDTS];
        unsigned RangeFlags = (unsigned)pRange->Flags;

        // Verify range flags.
        if (RangeFlags & ~(unsigned)DxilDescriptorRangeFlags::ValidFlags) {
          EAT(DiagPrinter << "Unsupported bit-flag set (descriptor range flags "
                          << (uint32_t)pRange->Flags << ").\n");
        }
        switch (pRange->RangeType) {
        case DxilDescriptorRangeType::Sampler: {
          if (RangeFlags & (unsigned)(DxilDescriptorRangeFlags::DataVolatile |
                                      DxilDescriptorRangeFlags::DataStatic |
                                      DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute)) {
            EAT(DiagPrinter << "Sampler descriptor ranges can't specify DATA_* flags "
                            << "since there is no data pointed to by samplers "
                            << "(descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
          }
          break;
        }
        default: {
          unsigned NumDataFlags = 0;
          if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataVolatile) { NumDataFlags++; }
          if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) { NumDataFlags++; }
          if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
          if (NumDataFlags > 1) {
            EAT(DiagPrinter << "Descriptor range flags cannot specify more than one DATA_* flag "
                            << "at a time (descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
          }
          if ((RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) && 
              (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DescriptorsVolatile)) {
            EAT(DiagPrinter << "Descriptor range flags cannot specify DESCRIPTORS_VOLATILE with the DATA_STATIC flag at the same time (descriptor range flags " << (uint32_t)pRange->Flags << "). "
                            << "DATA_STATIC_WHILE_SET_AT_EXECUTE is fine to combine with DESCRIPTORS_VOLATILE, since DESCRIPTORS_VOLATILE still requires descriptors don't change during execution. \n");
          }
          break;
        }
        }

        AddRegisterRange(iRP,
                         DESCRIPTOR_TABLE_ENTRY,
                         iDTS,
                         pRange->RangeType,
                         Visibility,
                         pRange->NumDescriptors,
                         pRange->BaseShaderRegister,
                         pRange->RegisterSpace,
                         DiagPrinter);
      }
      break;
    }

    case DxilRootParameterType::Constants32Bit:
      AddRegisterRange(iRP,
                       ROOT_CONSTANT,
                       (unsigned)-1,
                       DxilDescriptorRangeType::CBV,
                       Visibility,
                       1,
                       pSlot->Constants.ShaderRegister,
                       pSlot->Constants.RegisterSpace,
                       DiagPrinter);
      break;

    case DxilRootParameterType::CBV:
    case DxilRootParameterType::SRV:
    case DxilRootParameterType::UAV: {
      // Verify root descriptor flags.
      unsigned Flags = (unsigned)pSlot->Descriptor.Flags;
      if (Flags & ~(unsigned)DxilRootDescriptorFlags::ValidFlags) {
        EAT(DiagPrinter << "Unsupported bit-flag set (root descriptor flags " << std::hex << Flags << ").\n");
      }

      unsigned NumDataFlags = 0;
      if (Flags & (unsigned)DxilRootDescriptorFlags::DataVolatile) { NumDataFlags++; }
      if (Flags & (unsigned)DxilRootDescriptorFlags::DataStatic) { NumDataFlags++; }
      if (Flags & (unsigned)DxilRootDescriptorFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
      if (NumDataFlags > 1) {
        EAT(DiagPrinter << "Root descriptor flags cannot specify more "
                        << "than one DATA_* flag at a time (root "
                        << "descriptor flags " << NumDataFlags << ").\n");
      }

      AddRegisterRange(iRP, ROOT_DESCRIPTOR, (unsigned)-1,
                       GetRangeType(ParameterType), Visibility, 1,
                       pSlot->Descriptor.ShaderRegister,
                       pSlot->Descriptor.RegisterSpace, DiagPrinter);
      break;
    }

    default:
      EAT(DiagPrinter << "Unsupported ParameterType value " << (uint32_t)ParameterType
                      << " (root parameter " << iRP << ")\n");
    }
  }

  for (unsigned iSS = 0; iSS < pRootSignature->NumStaticSamplers; iSS++) {
    const DxilStaticSamplerDesc *pSS = &pRootSignature->pStaticSamplers[iSS];
    // Shader visibility.
    DxilShaderVisibility Visibility = pSS->ShaderVisibility;
    if (!IsDxilShaderVisibility(Visibility)) {
      EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
                      << " (static sampler [" << iSS << "]).\n");
    }

    StaticSamplerVerifier SSV;
    SSV.Verify(pSS, DiagPrinter);
    AddRegisterRange(iSS, STATIC_SAMPLER, (unsigned)-1,
                     DxilDescriptorRangeType::Sampler, Visibility, 1,
                     pSS->ShaderRegister, pSS->RegisterSpace, DiagPrinter);
  }
}

void RootSignatureVerifier::VerifyShader(DxilShaderVisibility VisType,
                                         const void *pPSVData,
                                         uint32_t PSVSize,
                                         DiagnosticPrinter &DiagPrinter) {
  DxilPipelineStateValidation PSV;
  IFTBOOL(PSV.InitFromPSV0(pPSVData, PSVSize), E_INVALIDARG);

  bool bShaderDeniedByRootSig = false;
  switch (VisType) {
  case DxilShaderVisibility::Vertex:
    if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyVertexShaderRootAccess) != DxilRootSignatureFlags::None) {
      bShaderDeniedByRootSig = true;
    }
    break;
  case DxilShaderVisibility::Hull:
    if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyHullShaderRootAccess) != DxilRootSignatureFlags::None) {
      bShaderDeniedByRootSig = true;
    }
    break;
  case DxilShaderVisibility::Domain:
    if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyDomainShaderRootAccess) != DxilRootSignatureFlags::None) {
      bShaderDeniedByRootSig = true;
    }
    break;
  case DxilShaderVisibility::Geometry:
    if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyGeometryShaderRootAccess) != DxilRootSignatureFlags::None) {
      bShaderDeniedByRootSig = true;
    }
    break;
  case DxilShaderVisibility::Pixel:
    if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyPixelShaderRootAccess) != DxilRootSignatureFlags::None) {
      bShaderDeniedByRootSig = true;
    }
    break;
  default:
    break;
  }

  bool bShaderHasRootBindings = false;

  for (unsigned iResource = 0; iResource < PSV.GetBindCount(); iResource++) {
    const PSVResourceBindInfo0 *pBindInfo0 = PSV.GetPSVResourceBindInfo0(iResource);
    DXASSERT_NOMSG(pBindInfo0);

    unsigned Space = pBindInfo0->Space;
    unsigned LB = pBindInfo0->LowerBound;
    unsigned UB = pBindInfo0->UpperBound;
    unsigned Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
    PSVResourceType ResType = (PSVResourceType)pBindInfo0->ResType;

    switch(ResType) {
    case PSVResourceType::Sampler: {
      bShaderHasRootBindings = true;
      auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::Sampler, VisType, Num, LB, Space);
      if(!pCoveringRange) {
        EAT(DiagPrinter << "Shader sampler descriptor range (RegisterSpace=" << Space 
                        << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB 
                        << ") is not fully bound in root signature.\n");
      }
      break;
    }

    case PSVResourceType::SRVTyped:
    case PSVResourceType::SRVRaw:
    case PSVResourceType::SRVStructured: {
      bShaderHasRootBindings = true;
      auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::SRV, VisType, Num, LB, Space);
      if (pCoveringRange) {
        if(pCoveringRange->nt == ROOT_DESCRIPTOR && ResType == PSVResourceType::SRVTyped) {
          EAT(DiagPrinter << "A Shader is declaring a resource object as a texture using "
                          << "a register mapped to a root descriptor SRV (RegisterSpace=" << Space
                          << ", ShaderRegister=" << LB << ").  "
                          << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
        }
      }
      else {
        EAT(DiagPrinter << "Shader SRV descriptor range (RegisterSpace=" << Space
                        << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
                        << ") is not fully bound in root signature.\n");
      }
      break;
    }

    case PSVResourceType::UAVTyped:
    case PSVResourceType::UAVRaw:
    case PSVResourceType::UAVStructured:
    case PSVResourceType::UAVStructuredWithCounter: {
      bShaderHasRootBindings = true;
      auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::UAV, VisType, Num, LB, Space);
      if (pCoveringRange) {
        if (pCoveringRange->nt == ROOT_DESCRIPTOR) {
          if (ResType == PSVResourceType::UAVTyped) {
            EAT(DiagPrinter << "A shader is declaring a typed UAV using a register mapped "
                            << "to a root descriptor UAV (RegisterSpace=" << Space 
                            << ", ShaderRegister=" << LB << ").  "
                            << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
          }
          if (ResType == PSVResourceType::UAVStructuredWithCounter) {
            EAT(DiagPrinter << "A Shader is declaring a structured UAV with counter using "
                            << "a register mapped to a root descriptor UAV (RegisterSpace=" << Space
                            << ", ShaderRegister=" << LB << ").  "
                            << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
          }
        }
      }
      else {
        EAT(DiagPrinter << "Shader UAV descriptor range (RegisterSpace=" << Space
                        << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
                        << ") is not fully bound in root signature.\n");
      }
      break;
    }

    case PSVResourceType::CBV: {
      bShaderHasRootBindings = true;
      auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::CBV, VisType, Num, LB, Space);
      if (!pCoveringRange) {
        EAT(DiagPrinter << "Shader CBV descriptor range (RegisterSpace=" << Space
                        << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
                        << ") is not fully bound in root signature.\n");
      }
      break;
    }

    default:
      break;
    }
  }

  if (bShaderHasRootBindings && bShaderDeniedByRootSig) {
    EAT(DiagPrinter << "Shader has root bindings but root signature uses a DENY flag "
                    << "to disallow root binding access to the shader stage.\n");
  }
}

BOOL isNaN(const float &a) {
  static const unsigned exponentMask = 0x7f800000;
  static const unsigned mantissaMask = 0x007fffff;
  unsigned u = *(const unsigned *)&a;
  return (((u & exponentMask) == exponentMask) && (u & mantissaMask)); // NaN
}

static bool IsDxilTextureAddressMode(DxilTextureAddressMode v) {
  return DxilTextureAddressMode::Wrap <= v &&
         v <= DxilTextureAddressMode::MirrorOnce;
}
static bool IsDxilComparisonFunc(DxilComparisonFunc v) {
  return DxilComparisonFunc::Never <= v && v <= DxilComparisonFunc::Always;
}

// This validation closely mirrors CCreateSamplerStateValidator's checks
void StaticSamplerVerifier::Verify(const DxilStaticSamplerDesc* pDesc,
                                   DiagnosticPrinter &DiagPrinter) {
  if (!pDesc) {
    EAT(DiagPrinter << "Static sampler: A nullptr pSamplerDesc was specified.\n");
  }

  bool bIsComparison = false;
  switch (pDesc->Filter) {
  case DxilFilter::MINIMUM_MIN_MAG_MIP_POINT:
  case DxilFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR:
  case DxilFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT:
  case DxilFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MINIMUM_MIN_MAG_MIP_LINEAR:
  case DxilFilter::MINIMUM_ANISOTROPIC:
  case DxilFilter::MAXIMUM_MIN_MAG_MIP_POINT:
  case DxilFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR:
  case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT:
  case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MAXIMUM_MIN_MAG_MIP_LINEAR:
  case DxilFilter::MAXIMUM_ANISOTROPIC:
    break;
  case DxilFilter::MIN_MAG_MIP_POINT:
  case DxilFilter::MIN_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MIN_POINT_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MIN_POINT_MAG_MIP_LINEAR:
  case DxilFilter::MIN_LINEAR_MAG_MIP_POINT:
  case DxilFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  case DxilFilter::MIN_MAG_LINEAR_MIP_POINT:
  case DxilFilter::MIN_MAG_MIP_LINEAR:
  case DxilFilter::ANISOTROPIC:
    break;
  case DxilFilter::COMPARISON_MIN_MAG_MIP_POINT:
  case DxilFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
  case DxilFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
  case DxilFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
  case DxilFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
  case DxilFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  case DxilFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
  case DxilFilter::COMPARISON_MIN_MAG_MIP_LINEAR:
  case DxilFilter::COMPARISON_ANISOTROPIC:
    bIsComparison = true;
    break;
  default:
    EAT(DiagPrinter << "Static sampler: Filter unrecognized.\n");
  }

  if (!IsDxilTextureAddressMode(pDesc->AddressU)) {
    EAT(DiagPrinter << "Static sampler: AddressU unrecognized.\n");
  }
  if (!IsDxilTextureAddressMode(pDesc->AddressV)) {
    EAT(DiagPrinter << "Static sampler: AddressV unrecognized.\n");
  }
  if (!IsDxilTextureAddressMode(pDesc->AddressW)) {
    EAT(DiagPrinter << "Static sampler: AddressW unrecognized.\n");
  }

  if (isNaN(pDesc->MipLODBias) || (pDesc->MipLODBias < DxilMipLodBiaxMin) ||
      (pDesc->MipLODBias > DxilMipLodBiaxMax)) {
    EAT(DiagPrinter << "Static sampler: MipLODBias must be in the "
                    << "range [" << DxilMipLodBiaxMin << " to " << DxilMipLodBiaxMax
                    <<"].  " << pDesc->MipLODBias << "specified.\n");
  }

  if (pDesc->MaxAnisotropy > DxilMapAnisotropy) {
    EAT(DiagPrinter << "Static sampler: MaxAnisotropy must be in "
                    << "the range [0 to " << DxilMapAnisotropy << "].  "
                    << pDesc->MaxAnisotropy << " specified.\n");
  }

  if (bIsComparison && !IsDxilComparisonFunc(pDesc->ComparisonFunc)) {
    EAT(DiagPrinter << "Static sampler: ComparisonFunc unrecognized.");
  }

  if (isNaN(pDesc->MinLOD)) {
    EAT(DiagPrinter << "Static sampler: MinLOD be in the range [-INF to +INF].  "
                    << pDesc->MinLOD << " specified.\n");
  }

  if (isNaN(pDesc->MaxLOD)) {
    EAT(DiagPrinter << "Static sampler: MaxLOD be in the range [-INF to +INF].  "
                    << pDesc->MaxLOD << " specified.\n");
  }
}

//////////////////////////////////////////////////////////////////////////////

template <typename T>
void DeleteRootSignatureTemplate(const T &RS) {
  for (unsigned i = 0; i < RS.NumParameters; i++) {
    const auto &P = RS.pParameters[i];
    if (P.ParameterType == DxilRootParameterType::DescriptorTable) {
      delete[] P.DescriptorTable.pDescriptorRanges;
    }
  }

  delete[] RS.pParameters;
  delete[] RS.pStaticSamplers;
}

void DeleteRootSignature(const DxilVersionedRootSignatureDesc * pRootSignature)
{
  if (pRootSignature == nullptr)
    return;

  switch (pRootSignature->Version)
  {
  case DxilRootSignatureVersion::Version_1_0:
    DeleteRootSignatureTemplate<DxilRootSignatureDesc>(pRootSignature->Desc_1_0);
    break;
  case DxilRootSignatureVersion::Version_1_1:
  default:
    DXASSERT(pRootSignature->Version == DxilRootSignatureVersion::Version_1_1, "else version is incorrect");
    DeleteRootSignatureTemplate<DxilRootSignatureDesc1>(pRootSignature->Desc_1_1);
    break;
  }

  delete pRootSignature;
}

// GetFlags/SetFlags overloads.
static DxilRootDescriptorFlags GetFlags(const DxilRootDescriptor &)
{
  // Upconvert root parameter flags to be volatile.
  return DxilRootDescriptorFlags::DataVolatile;
}
static void SetFlags(DxilRootDescriptor &, DxilRootDescriptorFlags)
{
  // Drop the flags; none existed in rs_1_0.
}
static DxilRootDescriptorFlags GetFlags(const DxilRootDescriptor1 &D)
{
  return D.Flags;
}
static void SetFlags(DxilRootDescriptor1 &D, DxilRootDescriptorFlags Flags)
{
  D.Flags = Flags;
}
static DxilRootDescriptorFlags GetFlags(const DxilContainerRootDescriptor1 &D)
{
  return (DxilRootDescriptorFlags)D.Flags;
}
static void SetFlags(DxilContainerRootDescriptor1 &D, DxilRootDescriptorFlags Flags)
{
  D.Flags = (uint32_t)Flags;
}
static DxilDescriptorRangeFlags GetFlags(const DxilDescriptorRange &D)
{
  // Upconvert range flags to be volatile.
  DxilDescriptorRangeFlags Flags = DxilDescriptorRangeFlags::DescriptorsVolatile;

  // Sampler does not have data.
  if (D.RangeType != DxilDescriptorRangeType::Sampler)
    Flags = (DxilDescriptorRangeFlags)((unsigned)Flags | (unsigned)DxilDescriptorRangeFlags::DataVolatile);

  return Flags;
}
static void SetFlags(DxilDescriptorRange &, DxilDescriptorRangeFlags)
{
}
static DxilDescriptorRangeFlags GetFlags(const DxilContainerDescriptorRange &D)
{
  // Upconvert range flags to be volatile.
  DxilDescriptorRangeFlags Flags = DxilDescriptorRangeFlags::DescriptorsVolatile;

  // Sampler does not have data.
  if (D.RangeType != (uint32_t)DxilDescriptorRangeType::Sampler)
    Flags |= DxilDescriptorRangeFlags::DataVolatile;

  return Flags;
}
static void SetFlags(DxilContainerDescriptorRange &, DxilDescriptorRangeFlags)
{
}
static DxilDescriptorRangeFlags GetFlags(const DxilDescriptorRange1 &D)
{
  return D.Flags;
}
static void SetFlags(DxilDescriptorRange1 &D, DxilDescriptorRangeFlags Flags)
{
  D.Flags = Flags;
}
static DxilDescriptorRangeFlags GetFlags(const DxilContainerDescriptorRange1 &D)
{
  return (DxilDescriptorRangeFlags)D.Flags;
}
static void SetFlags(DxilContainerDescriptorRange1 &D, DxilDescriptorRangeFlags Flags)
{
  D.Flags = (uint32_t)Flags;
}

template<typename IN_DXIL_ROOT_SIGNATURE_DESC,
  typename OUT_DXIL_ROOT_SIGNATURE_DESC,
  typename OUT_DXIL_ROOT_PARAMETER,
  typename OUT_DXIL_ROOT_DESCRIPTOR,
  typename OUT_DXIL_DESCRIPTOR_RANGE>
void ConvertRootSignatureTemplate(const IN_DXIL_ROOT_SIGNATURE_DESC &DescIn,
                                  DxilRootSignatureVersion DescVersionOut,
                                  OUT_DXIL_ROOT_SIGNATURE_DESC &DescOut)
{
  const IN_DXIL_ROOT_SIGNATURE_DESC *pDescIn = &DescIn;
  OUT_DXIL_ROOT_SIGNATURE_DESC *pDescOut = &DescOut;

  // Root signature descriptor.
  pDescOut->Flags = pDescIn->Flags;
  pDescOut->NumParameters = 0;
  pDescOut->NumStaticSamplers = 0;
  // Intialize all pointers early so that clean up works properly.
  pDescOut->pParameters = nullptr;
  pDescOut->pStaticSamplers = nullptr;

  // Root signature parameters.
  if (pDescIn->NumParameters > 0) {
    pDescOut->pParameters = new OUT_DXIL_ROOT_PARAMETER[pDescIn->NumParameters];
    pDescOut->NumParameters = pDescIn->NumParameters;
    memset((void *)pDescOut->pParameters, 0, pDescOut->NumParameters*sizeof(OUT_DXIL_ROOT_PARAMETER));
  }

  for (unsigned iRP = 0; iRP < pDescIn->NumParameters; iRP++) {
    const auto &ParamIn = pDescIn->pParameters[iRP];
    OUT_DXIL_ROOT_PARAMETER &ParamOut = (OUT_DXIL_ROOT_PARAMETER &)pDescOut->pParameters[iRP];

    ParamOut.ParameterType = ParamIn.ParameterType;
    ParamOut.ShaderVisibility = ParamIn.ShaderVisibility;

    switch (ParamIn.ParameterType) {
    case DxilRootParameterType::DescriptorTable: {
      ParamOut.DescriptorTable.pDescriptorRanges = nullptr;
      unsigned NumRanges = ParamIn.DescriptorTable.NumDescriptorRanges;
      if (NumRanges > 0) {
        ParamOut.DescriptorTable.pDescriptorRanges = new OUT_DXIL_DESCRIPTOR_RANGE[NumRanges];
        ParamOut.DescriptorTable.NumDescriptorRanges = NumRanges;
      }

      for (unsigned i = 0; i < NumRanges; i++) {
        const auto &RangeIn = ParamIn.DescriptorTable.pDescriptorRanges[i];
        OUT_DXIL_DESCRIPTOR_RANGE &RangeOut = (OUT_DXIL_DESCRIPTOR_RANGE &)ParamOut.DescriptorTable.pDescriptorRanges[i];

        RangeOut.RangeType = RangeIn.RangeType;
        RangeOut.NumDescriptors = RangeIn.NumDescriptors;
        RangeOut.BaseShaderRegister = RangeIn.BaseShaderRegister;
        RangeOut.RegisterSpace = RangeIn.RegisterSpace;
        RangeOut.OffsetInDescriptorsFromTableStart = RangeIn.OffsetInDescriptorsFromTableStart;
        DxilDescriptorRangeFlags Flags = GetFlags(RangeIn);
        SetFlags(RangeOut, Flags);
      }
      break;
    }
    case DxilRootParameterType::Constants32Bit: {
      ParamOut.Constants.Num32BitValues = ParamIn.Constants.Num32BitValues;
      ParamOut.Constants.ShaderRegister = ParamIn.Constants.ShaderRegister;
      ParamOut.Constants.RegisterSpace = ParamIn.Constants.RegisterSpace;
      break;
    }
    case DxilRootParameterType::CBV:
    case DxilRootParameterType::SRV:
    case DxilRootParameterType::UAV: {
      ParamOut.Descriptor.ShaderRegister = ParamIn.Descriptor.ShaderRegister;
      ParamOut.Descriptor.RegisterSpace = ParamIn.Descriptor.RegisterSpace;
      DxilRootDescriptorFlags Flags = GetFlags(ParamIn.Descriptor);
      SetFlags(ParamOut.Descriptor, Flags);
      break;
    }
    default:
      IFT(E_FAIL);
    }
  }

  // Static samplers.
  if (pDescIn->NumStaticSamplers > 0) {
    pDescOut->pStaticSamplers = new DxilStaticSamplerDesc[pDescIn->NumStaticSamplers];
    pDescOut->NumStaticSamplers = pDescIn->NumStaticSamplers;
    memcpy((void*)pDescOut->pStaticSamplers, pDescIn->pStaticSamplers, pDescOut->NumStaticSamplers*sizeof(DxilStaticSamplerDesc));
  }
}

void ConvertRootSignature(const DxilVersionedRootSignatureDesc * pRootSignatureIn,
                          DxilRootSignatureVersion RootSignatureVersionOut,
                          const DxilVersionedRootSignatureDesc ** ppRootSignatureOut) {
  IFTBOOL(pRootSignatureIn != nullptr && ppRootSignatureOut != nullptr, E_INVALIDARG);
  *ppRootSignatureOut = nullptr;

  if (pRootSignatureIn->Version == RootSignatureVersionOut){
    // No conversion. Return the original root signature pointer; no cloning.
    *ppRootSignatureOut = pRootSignatureIn;
    return;
  }

  DxilVersionedRootSignatureDesc *pRootSignatureOut = nullptr;

  try {
    pRootSignatureOut = new DxilVersionedRootSignatureDesc();
    memset(pRootSignatureOut, 0, sizeof(*pRootSignatureOut));

    // Convert root signature.
    switch (RootSignatureVersionOut) {
    case DxilRootSignatureVersion::Version_1_0:
      switch (pRootSignatureIn->Version) {
      case DxilRootSignatureVersion::Version_1_1:
        pRootSignatureOut->Version = DxilRootSignatureVersion::Version_1_0;
        ConvertRootSignatureTemplate<
          DxilRootSignatureDesc1,
          DxilRootSignatureDesc,
          DxilRootParameter,
          DxilRootDescriptor,
          DxilDescriptorRange>(pRootSignatureIn->Desc_1_1,
            DxilRootSignatureVersion::Version_1_0,
            pRootSignatureOut->Desc_1_0);
        break;
      default:
        IFT(E_INVALIDARG);
      }
      break;

    case DxilRootSignatureVersion::Version_1_1:
      switch (pRootSignatureIn->Version) {
      case DxilRootSignatureVersion::Version_1_0:
        pRootSignatureOut->Version = DxilRootSignatureVersion::Version_1_1;
        ConvertRootSignatureTemplate<
          DxilRootSignatureDesc,
          DxilRootSignatureDesc1,
          DxilRootParameter1,
          DxilRootDescriptor1,
          DxilDescriptorRange1>(pRootSignatureIn->Desc_1_0,
            DxilRootSignatureVersion::Version_1_1,
            pRootSignatureOut->Desc_1_1);
        break;
      default:
        IFT(E_INVALIDARG);
      }
      break;

    default:
      IFT(E_INVALIDARG);
      break;
    }
  }
  catch (...) {
    DeleteRootSignature(pRootSignatureOut);
    throw;
  }

  *ppRootSignatureOut = pRootSignatureOut;
}

template<typename T_ROOT_SIGNATURE_DESC,
  typename T_ROOT_PARAMETER,
  typename T_ROOT_DESCRIPTOR_INTERNAL,
  typename T_DESCRIPTOR_RANGE_INTERNAL>
void SerializeRootSignatureTemplate(_In_ const T_ROOT_SIGNATURE_DESC* pRootSignature,
                                    DxilRootSignatureVersion DescVersion,
                                    _COM_Outptr_ IDxcBlob** ppBlob,
                                    DiagnosticPrinter &DiagPrinter,
                                    _In_ bool bAllowReservedRegisterSpace) {
  DxilContainerRootSignatureDesc RS;
  uint32_t Offset;
  SimpleSerializer Serializer;
  IFT(Serializer.AddBlock(&RS, sizeof(RS), &Offset));
  IFTBOOL(Offset == 0, E_FAIL);

  const T_ROOT_SIGNATURE_DESC *pRS = pRootSignature;
  RS.Version = (uint32_t)DescVersion;
  RS.Flags = (uint32_t)pRS->Flags;
  RS.NumParameters = pRS->NumParameters;
  RS.NumStaticSamplers = pRS->NumStaticSamplers;

  DxilContainerRootParameter *pRP;
  IFT(Serializer.ReserveBlock((void**)&pRP,
    sizeof(DxilContainerRootParameter)*RS.NumParameters, &RS.RootParametersOffset));

  for (uint32_t iRP = 0; iRP < RS.NumParameters; iRP++) {
    const T_ROOT_PARAMETER *pInRP = &pRS->pParameters[iRP];
    DxilContainerRootParameter *pOutRP = &pRP[iRP];
    pOutRP->ParameterType = (uint32_t)pInRP->ParameterType;
    pOutRP->ShaderVisibility = (uint32_t)pInRP->ShaderVisibility;
    switch (pInRP->ParameterType) {
    case DxilRootParameterType::DescriptorTable: {
      DxilContainerRootDescriptorTable *p1;
      IFT(Serializer.ReserveBlock((void**)&p1,
                                  sizeof(DxilContainerRootDescriptorTable),
                                  &pOutRP->PayloadOffset));
      p1->NumDescriptorRanges = pInRP->DescriptorTable.NumDescriptorRanges;

      T_DESCRIPTOR_RANGE_INTERNAL *p2;
      IFT(Serializer.ReserveBlock((void**)&p2,
                                  sizeof(T_DESCRIPTOR_RANGE_INTERNAL)*p1->NumDescriptorRanges,
                                  &p1->DescriptorRangesOffset));

      for (uint32_t i = 0; i < p1->NumDescriptorRanges; i++) {
        p2[i].RangeType = (uint32_t)pInRP->DescriptorTable.pDescriptorRanges[i].RangeType;
        p2[i].NumDescriptors = pInRP->DescriptorTable.pDescriptorRanges[i].NumDescriptors;
        p2[i].BaseShaderRegister = pInRP->DescriptorTable.pDescriptorRanges[i].BaseShaderRegister;
        p2[i].RegisterSpace = pInRP->DescriptorTable.pDescriptorRanges[i].RegisterSpace;
        p2[i].OffsetInDescriptorsFromTableStart = pInRP->DescriptorTable.pDescriptorRanges[i].OffsetInDescriptorsFromTableStart;
        DxilDescriptorRangeFlags Flags = GetFlags(pInRP->DescriptorTable.pDescriptorRanges[i]);
        SetFlags(p2[i], Flags);
      }
      break;
    }
    case DxilRootParameterType::Constants32Bit: {
      DxilRootConstants *p;
      IFT(Serializer.ReserveBlock((void**)&p, sizeof(DxilRootConstants), &pOutRP->PayloadOffset));
      p->Num32BitValues = pInRP->Constants.Num32BitValues;
      p->ShaderRegister = pInRP->Constants.ShaderRegister;
      p->RegisterSpace = pInRP->Constants.RegisterSpace;
      break;
    }
    case DxilRootParameterType::CBV:
    case DxilRootParameterType::SRV:
    case DxilRootParameterType::UAV: {
      T_ROOT_DESCRIPTOR_INTERNAL *p;
      IFT(Serializer.ReserveBlock((void**)&p, sizeof(T_ROOT_DESCRIPTOR_INTERNAL), &pOutRP->PayloadOffset));
      p->ShaderRegister = pInRP->Descriptor.ShaderRegister;
      p->RegisterSpace = pInRP->Descriptor.RegisterSpace;
      DxilRootDescriptorFlags Flags = GetFlags(pInRP->Descriptor);
      SetFlags(*p, Flags);
      break;
    }
    default:
      EAT(DiagPrinter << "D3DSerializeRootSignature: unknown root parameter type ("
                      << (uint32_t)pInRP->ParameterType << ")\n");
    }
  }

  DxilStaticSamplerDesc *pSS;
  unsigned StaticSamplerSize = sizeof(DxilStaticSamplerDesc)*RS.NumStaticSamplers;
  IFT(Serializer.ReserveBlock((void**)&pSS, StaticSamplerSize, &RS.StaticSamplersOffset));
  memcpy(pSS, pRS->pStaticSamplers, StaticSamplerSize);

  // Create the result blob.
  CDxcMallocHeapPtr<char> bytes(DxcGetThreadMallocNoRef());
  CComPtr<IDxcBlob> pBlob;
  unsigned cb = Serializer.GetSize();
  DXASSERT_NOMSG((cb & 0x3) == 0);
  IFTBOOL(bytes.Allocate(cb), E_OUTOFMEMORY);
  IFT(Serializer.Compact(bytes.m_pData, cb));
  IFT(DxcCreateBlobOnHeap(bytes.m_pData, cb, ppBlob));
  bytes.Detach(); // Ownership transfered to ppBlob.
}

_Use_decl_annotations_
void SerializeRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
                            IDxcBlob **ppBlob, IDxcBlobEncoding **ppErrorBlob,
                            bool bAllowReservedRegisterSpace) {
  DXASSERT_NOMSG(pRootSignature != nullptr);
  DXASSERT_NOMSG(ppBlob != nullptr);
  DXASSERT_NOMSG(ppErrorBlob != nullptr);

  *ppBlob = nullptr;
  *ppErrorBlob = nullptr;

  RootSignatureVerifier RSV;
  // TODO: change SerializeRootSignature to take raw_ostream&
  string DiagString;
  raw_string_ostream DiagStream(DiagString);
  DiagnosticPrinterRawOStream DiagPrinter(DiagStream);

  // Verify root signature.
  RSV.AllowReservedRegisterSpace(bAllowReservedRegisterSpace);
  try {
    RSV.VerifyRootSignature(pRootSignature, DiagPrinter);
    switch (pRootSignature->Version)
    {
    case DxilRootSignatureVersion::Version_1_0:
      SerializeRootSignatureTemplate<
        DxilRootSignatureDesc,
        DxilRootParameter,
        DxilRootDescriptor,
        DxilContainerDescriptorRange>(&pRootSignature->Desc_1_0,
          DxilRootSignatureVersion::Version_1_0,
          ppBlob, DiagPrinter,
          bAllowReservedRegisterSpace);
      break;

    case DxilRootSignatureVersion::Version_1_1:
    default:
      DXASSERT(pRootSignature->Version == DxilRootSignatureVersion::Version_1_1, "else VerifyRootSignature didn't validate");
      SerializeRootSignatureTemplate<
        DxilRootSignatureDesc1,
        DxilRootParameter1,
        DxilContainerRootDescriptor1,
        DxilContainerDescriptorRange1>(&pRootSignature->Desc_1_1,
          DxilRootSignatureVersion::Version_1_1,
          ppBlob, DiagPrinter,
          bAllowReservedRegisterSpace);
      break;
    }
  } catch (...) {
    DiagStream.flush();
    DxcCreateBlobWithEncodingOnHeapCopy(DiagString.c_str(), DiagString.size(), CP_UTF8, ppErrorBlob);
  }
}

//=============================================================================
//
// CVersionedRootSignatureDeserializer.
//
//=============================================================================
class CVersionedRootSignatureDeserializer {
protected:
  const DxilVersionedRootSignatureDesc *m_pRootSignature;
  const DxilVersionedRootSignatureDesc *m_pRootSignature10;
  const DxilVersionedRootSignatureDesc *m_pRootSignature11;

public:
  CVersionedRootSignatureDeserializer();
  ~CVersionedRootSignatureDeserializer();

  void Initialize(_In_reads_bytes_(SrcDataSizeInBytes) const void *pSrcData,
                  _In_ uint32_t SrcDataSizeInBytes);

  const DxilVersionedRootSignatureDesc *GetRootSignatureDescAtVersion(DxilRootSignatureVersion convertToVersion);

  const DxilVersionedRootSignatureDesc *GetUnconvertedRootSignatureDesc();
};

CVersionedRootSignatureDeserializer::CVersionedRootSignatureDeserializer()
  : m_pRootSignature(nullptr)
  , m_pRootSignature10(nullptr)
  , m_pRootSignature11(nullptr) {
}

CVersionedRootSignatureDeserializer::~CVersionedRootSignatureDeserializer() {
  DeleteRootSignature(m_pRootSignature10);
  DeleteRootSignature(m_pRootSignature11);
}

void CVersionedRootSignatureDeserializer::Initialize(_In_reads_bytes_(SrcDataSizeInBytes) const void *pSrcData,
                                                     _In_ uint32_t SrcDataSizeInBytes) {
  const DxilVersionedRootSignatureDesc *pRootSignature = nullptr;
  DeserializeRootSignature(pSrcData, SrcDataSizeInBytes, &pRootSignature);

  switch (pRootSignature->Version) {
  case DxilRootSignatureVersion::Version_1_0:
    m_pRootSignature10 = pRootSignature;
    break;

  case DxilRootSignatureVersion::Version_1_1:
    m_pRootSignature11 = pRootSignature;
    break;

  default:
    DeleteRootSignature(pRootSignature);
    return;
  }

  m_pRootSignature = pRootSignature;
}

const DxilVersionedRootSignatureDesc *
CVersionedRootSignatureDeserializer::GetUnconvertedRootSignatureDesc() {
  return m_pRootSignature;
}

const DxilVersionedRootSignatureDesc *
CVersionedRootSignatureDeserializer::GetRootSignatureDescAtVersion(DxilRootSignatureVersion ConvertToVersion) {
  switch (ConvertToVersion) {
  case DxilRootSignatureVersion::Version_1_0:
    if (m_pRootSignature10 == nullptr) {
      ConvertRootSignature(m_pRootSignature,
                           ConvertToVersion,
                           (const DxilVersionedRootSignatureDesc **)&m_pRootSignature10);
    }
    return m_pRootSignature10;

  case DxilRootSignatureVersion::Version_1_1:
    if (m_pRootSignature11 == nullptr) {
      ConvertRootSignature(m_pRootSignature,
                           ConvertToVersion,
                           (const DxilVersionedRootSignatureDesc **)&m_pRootSignature11);
    }
    return m_pRootSignature11;

  default:
    IFTBOOL(false, E_FAIL);
  }

  return nullptr;
}

template<typename T_ROOT_SIGNATURE_DESC,
         typename T_ROOT_PARAMETER,
         typename T_ROOT_DESCRIPTOR,
         typename T_ROOT_DESCRIPTOR_INTERNAL,
         typename T_DESCRIPTOR_RANGE,
         typename T_DESCRIPTOR_RANGE_INTERNAL>
void DeserializeRootSignatureTemplate(_In_reads_bytes_(SrcDataSizeInBytes) const void *pSrcData,
                                      _In_ uint32_t SrcDataSizeInBytes,
                                      DxilRootSignatureVersion DescVersion,
                                      T_ROOT_SIGNATURE_DESC &RootSignatureDesc) {
  // Note that in case of failure, outside code must deallocate memory.
  T_ROOT_SIGNATURE_DESC *pRootSignature = &RootSignatureDesc;
  const char *pData = (const char *)pSrcData;
  const char *pMaxPtr = pData + SrcDataSizeInBytes;
  UNREFERENCED_PARAMETER(DescVersion);
  DXASSERT_NOMSG(((uint32_t*)pData)[0] == (uint32_t)DescVersion);

  // Root signature.
  IFTBOOL(pData + sizeof(DxilContainerRootSignatureDesc) <= pMaxPtr, E_FAIL);
  DxilContainerRootSignatureDesc *pRS = (DxilContainerRootSignatureDesc *)pData;
  pRootSignature->Flags = (DxilRootSignatureFlags)pRS->Flags;
  pRootSignature->NumParameters = pRS->NumParameters;
  pRootSignature->NumStaticSamplers = pRS->NumStaticSamplers;
  // Intialize all pointers early so that clean up works properly.
  pRootSignature->pParameters = nullptr;
  pRootSignature->pStaticSamplers = nullptr;

  size_t s = sizeof(DxilContainerRootParameter)*pRS->NumParameters;
  DxilContainerRootParameter *pInRTS = (DxilContainerRootParameter *)(pData + pRS->RootParametersOffset);
  IFTBOOL(((char*)pInRTS) + s <= pMaxPtr, E_FAIL);
  if (pRootSignature->NumParameters) {
    pRootSignature->pParameters = new T_ROOT_PARAMETER[pRootSignature->NumParameters];
  }
  memset((void *)pRootSignature->pParameters, 0, s);

  for(unsigned iRP = 0; iRP < pRootSignature->NumParameters; iRP++) {
    DxilRootParameterType ParameterType = (DxilRootParameterType)pInRTS[iRP].ParameterType;
    T_ROOT_PARAMETER *pOutRTS = (T_ROOT_PARAMETER *)&pRootSignature->pParameters[iRP];
    pOutRTS->ParameterType = ParameterType;
    pOutRTS->ShaderVisibility = (DxilShaderVisibility)pInRTS[iRP].ShaderVisibility;
    switch(ParameterType) {
    case DxilRootParameterType::DescriptorTable: {
      DxilContainerRootDescriptorTable *p1 = (DxilContainerRootDescriptorTable*)(pData + pInRTS[iRP].PayloadOffset);
      IFTBOOL((char*)p1 + sizeof(DxilContainerRootDescriptorTable) <= pMaxPtr, E_FAIL);
      pOutRTS->DescriptorTable.NumDescriptorRanges = p1->NumDescriptorRanges;
      pOutRTS->DescriptorTable.pDescriptorRanges = nullptr;
      T_DESCRIPTOR_RANGE_INTERNAL *p2 = (T_DESCRIPTOR_RANGE_INTERNAL*)(pData + p1->DescriptorRangesOffset);
      IFTBOOL((char*)p2 + sizeof(T_DESCRIPTOR_RANGE_INTERNAL) <= pMaxPtr, E_FAIL);
      if (p1->NumDescriptorRanges) {
        pOutRTS->DescriptorTable.pDescriptorRanges = new T_DESCRIPTOR_RANGE[p1->NumDescriptorRanges];
      }
      for (unsigned i = 0; i < p1->NumDescriptorRanges; i++) {
        T_DESCRIPTOR_RANGE *p3 = (T_DESCRIPTOR_RANGE *)&pOutRTS->DescriptorTable.pDescriptorRanges[i];
        p3->RangeType                         = (DxilDescriptorRangeType)p2[i].RangeType;
        p3->NumDescriptors                    = p2[i].NumDescriptors;
        p3->BaseShaderRegister                = p2[i].BaseShaderRegister;
        p3->RegisterSpace                     = p2[i].RegisterSpace;
        p3->OffsetInDescriptorsFromTableStart = p2[i].OffsetInDescriptorsFromTableStart;
        DxilDescriptorRangeFlags Flags = GetFlags(p2[i]);
        SetFlags(*p3, Flags);
      }
      break;
    }
    case DxilRootParameterType::Constants32Bit: {
      DxilRootConstants *p = (DxilRootConstants*)(pData + pInRTS[iRP].PayloadOffset);
      IFTBOOL((char*)p + sizeof(DxilRootConstants) <= pMaxPtr, E_FAIL);
      pOutRTS->Constants.Num32BitValues = p->Num32BitValues;
      pOutRTS->Constants.ShaderRegister = p->ShaderRegister;
      pOutRTS->Constants.RegisterSpace  = p->RegisterSpace;
      break;
    }
    case DxilRootParameterType::CBV:
    case DxilRootParameterType::SRV:
    case DxilRootParameterType::UAV: {
      T_ROOT_DESCRIPTOR *p = (T_ROOT_DESCRIPTOR *)(pData + pInRTS[iRP].PayloadOffset);
      IFTBOOL((char*)p + sizeof(T_ROOT_DESCRIPTOR) <= pMaxPtr, E_FAIL);
      pOutRTS->Descriptor.ShaderRegister = p->ShaderRegister;
      pOutRTS->Descriptor.RegisterSpace  = p->RegisterSpace;
      DxilRootDescriptorFlags Flags = GetFlags(*p);
      SetFlags(pOutRTS->Descriptor, Flags);
      break;
    }
    default:
      IFT(E_FAIL);
    }
  }

  s = sizeof(DxilStaticSamplerDesc)*pRS->NumStaticSamplers;
  DxilStaticSamplerDesc *pInSS = (DxilStaticSamplerDesc *)(pData + pRS->StaticSamplersOffset);
  IFTBOOL(((char*)pInSS) + s <= pMaxPtr, E_FAIL);
  if (pRootSignature->NumStaticSamplers) {
    pRootSignature->pStaticSamplers = new DxilStaticSamplerDesc[pRootSignature->NumStaticSamplers];
  }
  memcpy((void*)pRootSignature->pStaticSamplers, pInSS, s);
}

_Use_decl_annotations_
void DeserializeRootSignature(const void *pSrcData,
                              uint32_t SrcDataSizeInBytes,
                              const DxilVersionedRootSignatureDesc **ppRootSignature) {
  DxilVersionedRootSignatureDesc *pRootSignature = nullptr;
  IFTBOOL(pSrcData != nullptr && SrcDataSizeInBytes != 0 && ppRootSignature != nullptr, E_INVALIDARG);
  IFTBOOL(*ppRootSignature == nullptr, E_INVALIDARG);
  const char *pData = (const char *)pSrcData;
  IFTBOOL(pData + sizeof(uint32_t) < pData + SrcDataSizeInBytes, E_FAIL);

  DxilRootSignatureVersion Version = (DxilRootSignatureVersion)((uint32_t*)pData)[0];

  pRootSignature = new DxilVersionedRootSignatureDesc();

  try {
    switch (Version) {
    case DxilRootSignatureVersion::Version_1_0:
      pRootSignature->Version = DxilRootSignatureVersion::Version_1_0;
      DeserializeRootSignatureTemplate<
         DxilRootSignatureDesc,
         DxilRootParameter,
         DxilRootDescriptor,
         DxilRootDescriptor,
         DxilDescriptorRange,
         DxilContainerDescriptorRange>(pSrcData,
                                       SrcDataSizeInBytes,
                                       DxilRootSignatureVersion::Version_1_0,
                                       pRootSignature->Desc_1_0);
      break;

    case DxilRootSignatureVersion::Version_1_1:
      pRootSignature->Version = DxilRootSignatureVersion::Version_1_1;
      DeserializeRootSignatureTemplate<
         DxilRootSignatureDesc1,
         DxilRootParameter1,
         DxilRootDescriptor1,
         DxilContainerRootDescriptor1,
         DxilDescriptorRange1,
         DxilContainerDescriptorRange1>(pSrcData,
                                        SrcDataSizeInBytes,
                                        DxilRootSignatureVersion::Version_1_1,
                                        pRootSignature->Desc_1_1);
      break;

    default:
      IFT(E_FAIL);
      break;
    }
  } catch(...) {
    DeleteRootSignature(pRootSignature);
    throw;
  }

  *ppRootSignature = pRootSignature;
}

static DxilShaderVisibility GetVisibilityType(DXIL::ShaderKind ShaderKind) {
  switch(ShaderKind) {
  case DXIL::ShaderKind::Pixel:       return DxilShaderVisibility::Pixel;
  case DXIL::ShaderKind::Vertex:      return DxilShaderVisibility::Vertex;
  case DXIL::ShaderKind::Geometry:    return DxilShaderVisibility::Geometry;
  case DXIL::ShaderKind::Hull:        return DxilShaderVisibility::Hull;
  case DXIL::ShaderKind::Domain:      return DxilShaderVisibility::Domain;
  default:                            return DxilShaderVisibility::All;
  }
}

_Use_decl_annotations_
bool VerifyRootSignatureWithShaderPSV(const DxilVersionedRootSignatureDesc *pDesc,
                                      DXIL::ShaderKind ShaderKind,
                                      const void *pPSVData,
                                      uint32_t PSVSize,
                                      llvm::raw_ostream &DiagStream) {
  try {
    RootSignatureVerifier RSV;
    DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
    RSV.VerifyRootSignature(pDesc, DiagPrinter);
    RSV.VerifyShader(GetVisibilityType(ShaderKind), pPSVData, PSVSize, DiagPrinter);
  } catch (...) {
    return false;
  }

  return true;
}

} // namespace hlsl
