Bläddra i källkod

Partially ported RootSignatureVerifier::VerifyShader and VerifyRootSignatureWithShaderPSV

Yuri Dotsenko 8 år sedan
förälder
incheckning
67af2429a4

+ 50 - 48
include/dxc/HLSL/DxilPipelineStateValidation.h

@@ -12,6 +12,8 @@
 #ifndef __DXIL_PIPELINE_STATE_VALIDATION__H__
 #define __DXIL_PIPELINE_STATE_VALIDATION__H__
 
+#include <memory>
+
 // Versioning is additive and based on size
 struct PSVRuntimeInfo0
 {
@@ -20,20 +22,20 @@ struct PSVRuntimeInfo0
       char OutputPositionPresent;
     } VS;
     struct HSInfo {
-      UINT InputControlPointCount;      // max control points == 32
-      UINT OutputControlPointCount;     // max control points == 32
-      UINT TessellatorDomain;           // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
-      UINT TessellatorOutputPrimitive;  // hlsl::DXIL::TessellatorOutputPrimitive/D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE
+      uint32_t InputControlPointCount;      // max control points == 32
+      uint32_t OutputControlPointCount;     // max control points == 32
+      uint32_t TessellatorDomain;           // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
+      uint32_t TessellatorOutputPrimitive;  // hlsl::DXIL::TessellatorOutputPrimitive/D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE
     } HS;
     struct DSInfo {
-      UINT InputControlPointCount;      // max control points == 32
+      uint32_t InputControlPointCount;      // max control points == 32
       char OutputPositionPresent;
-      UINT TessellatorDomain;           // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
+      uint32_t TessellatorDomain;           // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
     } DS;
     struct GSInfo {
-      UINT InputPrimitive;              // hlsl::DXIL::InputPrimitive/D3D10_SB_PRIMITIVE
-      UINT OutputTopology;              // hlsl::DXIL::PrimitiveTopology/D3D10_SB_PRIMITIVE_TOPOLOGY
-      UINT OutputStreamMask;            // max streams == 4
+      uint32_t InputPrimitive;              // hlsl::DXIL::InputPrimitive/D3D10_SB_PRIMITIVE
+      uint32_t OutputTopology;              // hlsl::DXIL::PrimitiveTopology/D3D10_SB_PRIMITIVE_TOPOLOGY
+      uint32_t OutputStreamMask;            // max streams == 4
       char OutputPositionPresent;
     } GS;
     struct PSInfo {
@@ -41,8 +43,8 @@ struct PSVRuntimeInfo0
       char SampleFrequency;
     } PS;
   };
-  UINT MinimumExpectedWaveLaneCount;  // minimum lane count required, 0 if unused
-  UINT MaximumExpectedWaveLaneCount;  // maximum lane count required, 0xffffffff if unused
+  uint32_t MinimumExpectedWaveLaneCount;  // minimum lane count required, 0 if unused
+  uint32_t MaximumExpectedWaveLaneCount;  // maximum lane count required, 0xffffffff if unused
 };
 // PSVRuntimeInfo1 would derive and extend
 
@@ -66,21 +68,21 @@ enum class PSVResourceType
 // Versioning is additive and based on size
 struct PSVResourceBindInfo0
 {
-  UINT ResType;     // PSVResourceType
-  UINT Space;
-  UINT LowerBound;
-  UINT UpperBound;
+  uint32_t ResType;     // PSVResourceType
+  uint32_t Space;
+  uint32_t LowerBound;
+  uint32_t UpperBound;
 };
 // PSVResourceBindInfo1 would derive and extend
 
 class DxilPipelineStateValidation
 {
-  UINT m_uPSVRuntimeInfoSize;
+  uint32_t m_uPSVRuntimeInfoSize;
   PSVRuntimeInfo0* m_pPSVRuntimeInfo0;
-  UINT m_uResourceCount;
-  UINT m_uPSVResourceBindInfoSize;
+  uint32_t m_uResourceCount;
+  uint32_t m_uPSVResourceBindInfoSize;
   void* m_pPSVResourceBindInfo;
-  UINT m_uSize;
+  uint32_t m_uSize;
 
 public:
   DxilPipelineStateValidation() : 
@@ -93,47 +95,47 @@ public:
   }
 
   // Init() from PSV0 blob part that looks like:
-  // UINT PSVRuntimeInfo_size
+  // uint32_t PSVRuntimeInfo_size
   // { PSVRuntimeInfoN structure }
-  // UINT ResourceCount
+  // uint32_t ResourceCount
   // ---  end of blob if ResourceCount == 0  ---
-  // UINT PSVResourceBindInfo_size
+  // uint32_t PSVResourceBindInfo_size
   // { PSVResourceBindInfoN structure } * ResourceCount
   // returns true if no errors occurred.
-  bool InitFromPSV0(const void* pBits, UINT size) {
+  bool InitFromPSV0(const void* pBits, uint32_t size) {
     if(!(pBits != nullptr)) return false;
-    const BYTE* pCurBits = (BYTE*)pBits;
-    UINT minsize = sizeof(PSVRuntimeInfo0) + sizeof(UINT) * 2;
+    const uint8_t* pCurBits = (uint8_t*)pBits;
+    uint32_t minsize = sizeof(PSVRuntimeInfo0) + sizeof(uint32_t) * 2;
     if(!(size >= minsize)) return false;
-    m_uPSVRuntimeInfoSize = *((const UINT*)pCurBits);
+    m_uPSVRuntimeInfoSize = *((const uint32_t*)pCurBits);
     if(!(m_uPSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo0))) return false;
-    pCurBits += sizeof(UINT);
-    minsize = m_uPSVRuntimeInfoSize + sizeof(UINT) * 2;
+    pCurBits += sizeof(uint32_t);
+    minsize = m_uPSVRuntimeInfoSize + sizeof(uint32_t) * 2;
     if(!(size >= minsize)) return false;
     m_pPSVRuntimeInfo0 = const_cast<PSVRuntimeInfo0*>((const PSVRuntimeInfo0*)pCurBits);
     pCurBits += m_uPSVRuntimeInfoSize;
-    m_uResourceCount = *(const UINT*)pCurBits;
-    pCurBits += sizeof(UINT);
+    m_uResourceCount = *(const uint32_t*)pCurBits;
+    pCurBits += sizeof(uint32_t);
     if (m_uResourceCount > 0) {
-      minsize += sizeof(UINT);
+      minsize += sizeof(uint32_t);
       if(!(size >= minsize)) return false;
-      m_uPSVResourceBindInfoSize = *(const UINT*)pCurBits;
-      pCurBits += sizeof(UINT);
+      m_uPSVResourceBindInfoSize = *(const uint32_t*)pCurBits;
+      pCurBits += sizeof(uint32_t);
       minsize += m_uPSVResourceBindInfoSize * m_uResourceCount;
       if(!(m_uPSVResourceBindInfoSize >= sizeof(PSVResourceBindInfo0))) return false;
       if(!(size >= minsize)) return false;
-      m_pPSVResourceBindInfo = static_cast<void*>(const_cast<BYTE*>(pCurBits));
+      m_pPSVResourceBindInfo = static_cast<void*>(const_cast<uint8_t*>(pCurBits));
     }
     return true;
   }
 
   // Initialize a new buffer
   // call with null pBuffer to get required size
-  bool InitNew(UINT ResourceCount, void *pBuffer, UINT *pSize) {
+  bool InitNew(uint32_t ResourceCount, void *pBuffer, uint32_t *pSize) {
     if(!(pSize)) return false;
-    UINT size = sizeof(PSVRuntimeInfo0) + sizeof(UINT) * 2;
+    uint32_t size = sizeof(PSVRuntimeInfo0) + sizeof(uint32_t) * 2;
     if (ResourceCount) {
-      size += sizeof(UINT) + (sizeof(PSVResourceBindInfo0) * ResourceCount);
+      size += sizeof(uint32_t) + (sizeof(PSVResourceBindInfo0) * ResourceCount);
     }
     if (pBuffer) {
       if(!(*pSize >= size)) return false;
@@ -141,22 +143,22 @@ public:
       *pSize = size;
       return true;
     }
-    ::ZeroMemory(pBuffer, size);
+    memset(pBuffer, 0, size);
     m_uPSVRuntimeInfoSize = sizeof(PSVRuntimeInfo0);
-    BYTE* pCurBits = (BYTE*)pBuffer;
-    *(UINT*)pCurBits = sizeof(PSVRuntimeInfo0);
-    pCurBits += sizeof(UINT);
+    uint8_t* pCurBits = (uint8_t*)pBuffer;
+    *(uint32_t*)pCurBits = sizeof(PSVRuntimeInfo0);
+    pCurBits += sizeof(uint32_t);
     m_pPSVRuntimeInfo0 = (PSVRuntimeInfo0*)pCurBits;
     pCurBits += sizeof(PSVRuntimeInfo0);
 
     // Set resource info:
     m_uResourceCount = ResourceCount;
-    *(UINT*)pCurBits = ResourceCount;
-    pCurBits += sizeof(UINT);
+    *(uint32_t*)pCurBits = ResourceCount;
+    pCurBits += sizeof(uint32_t);
     if (ResourceCount > 0) {
       m_uPSVResourceBindInfoSize = sizeof(PSVResourceBindInfo0);
-      *(UINT*)pCurBits = m_uPSVResourceBindInfoSize;
-      pCurBits += sizeof(UINT);
+      *(uint32_t*)pCurBits = m_uPSVResourceBindInfoSize;
+      pCurBits += sizeof(uint32_t);
       m_pPSVResourceBindInfo = pCurBits;
     }
     return true;
@@ -166,14 +168,14 @@ public:
     return m_pPSVRuntimeInfo0;
   }
 
-  UINT GetBindCount() const {
+  uint32_t GetBindCount() const {
     return m_uResourceCount;
   }
 
-  PSVResourceBindInfo0* GetPSVResourceBindInfo0(UINT index) {
+  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) {
     if (index < m_uResourceCount && m_pPSVResourceBindInfo &&
         sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize) {
-      return (PSVResourceBindInfo0*)((BYTE*)m_pPSVResourceBindInfo +
+      return (PSVResourceBindInfo0*)((uint8_t*)m_pPSVResourceBindInfo +
         (index * m_uPSVResourceBindInfoSize));
     }
     return nullptr;

+ 18 - 5
include/dxc/HLSL/DxilRootSignature.h

@@ -19,6 +19,10 @@
 struct IDxcBlob;
 struct IDxcBlobEncoding;
 
+namespace llvm {
+  class raw_ostream;
+}
+
 namespace hlsl {
 
 // Forward declarations.
@@ -318,6 +322,7 @@ public:
   bool IsEmpty() const {
     return m_pDesc == nullptr && m_pSerialized == nullptr;
   }
+  IDxcBlob *GetSerialized() const { return m_pSerialized; }
   const uint8_t *GetSerializedBytes() const;
   unsigned GetSerializedSize() const;
 
@@ -325,6 +330,9 @@ public:
   void Clear();
   void LoadSerialized(const uint8_t *pData, uint32_t length);
   void EnsureSerializedAvailable();
+  void Deserialize();
+
+  const DxilVersionedRootSignatureDesc *GetDesc() const { return m_pDesc; }
 };
 
 void DeleteRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature);  
@@ -334,16 +342,21 @@ void ConvertRootSignature(const DxilVersionedRootSignatureDesc* pRootSignatureIn
                           DxilRootSignatureVersion RootSignatureVersionOut,  
                           const DxilVersionedRootSignatureDesc ** ppRootSignatureOut);
 
-void SerializeRootSignature(
-    const DxilVersionedRootSignatureDesc *pRootSignature,
-    _Outptr_ IDxcBlob **ppBlob, _Outptr_ IDxcBlobEncoding **ppErrorBlob,
-    bool bAllowReservedRegisterSpace);
+void SerializeRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
+                            _Outptr_ IDxcBlob **ppBlob, _Outptr_ IDxcBlobEncoding **ppErrorBlob,
+                            bool bAllowReservedRegisterSpace);
 
-//QQQ
 void DeserializeRootSignature(__in_bcount(SrcDataSizeInBytes) const void *pSrcData,
                               __in uint32_t SrcDataSizeInBytes,
                               __out DxilVersionedRootSignatureDesc **ppRootSignature);
 
+// Takes PSV - pipeline state validation data, not shader container.
+bool VerifyRootSignatureWithShaderPSV(__in const DxilVersionedRootSignatureDesc *pDesc,
+                                      __in DXIL::ShaderKind ShaderKind,
+                                      _In_reads_bytes_(PSVSize) const void *pPSVData,
+                                      __in uint32_t PSVSize,
+                                      __in llvm::raw_ostream &DiagStream);
+
 } // namespace hlsl
 
 #endif // __DXC_ROOTSIGNATURE__

+ 230 - 19
lib/HLSL/DxilRootSignature.cpp

@@ -9,16 +9,23 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#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 <algorithm>
 #include <utility>
 #include <vector>
 
+using namespace llvm;
+
 namespace hlsl {
 
 DEFINE_ENUM_FLAG_OPERATORS(DxilRootSignatureFlags)
@@ -305,13 +312,19 @@ public:
   RootSignatureVerifier();
   ~RootSignatureVerifier();
 
-  // Call this before calling VerifyShader, as it accumulates root signature
-  // state.
-  HRESULT
-  VerifyRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
-                      IStream *pErrors);
   void AllowReservedRegisterSpace(bool bAllow);
 
+  //QQQ
+  // Call this before calling VerifyShader, as it accumulates root signature state.
+  HRESULT VerifyRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
+                              IStream *pErrors);
+
+  //QQQ
+  HRESULT VerifyShader(DxilShaderVisibility VisType,
+                       const void *pPSVData,
+                       uint32_t PSVSize,
+                       raw_ostream &DiagStream);
+
   typedef enum NODE_TYPE {
     DESCRIPTOR_TABLE_ENTRY,
     ROOT_DESCRIPTOR,
@@ -354,6 +367,13 @@ private:
                            unsigned NumRegisters, unsigned BaseRegister,
                            unsigned RegisterSpace, IStream *pErrors);
 
+  //QQQ
+  RegisterRange *FindCoveringInterval(DxilDescriptorRangeType RangeType,
+                                      DxilShaderVisibility VisType,
+                                      unsigned Num,
+                                      unsigned LB,
+                                      unsigned Space);
+
   RegisterRanges &
   GetRanges(DxilShaderVisibility VisType, DxilDescriptorRangeType DescType) {
     return RangeKinds[(unsigned)VisType][(unsigned)DescType];
@@ -483,15 +503,14 @@ static bool IsDxilShaderVisibility(DxilShaderVisibility v) {
 }
 
 HRESULT RootSignatureVerifier::AddRegisterRange(unsigned iRP,
-  NODE_TYPE nt,
-  unsigned iDTS,
-  DxilDescriptorRangeType DescType,
-  DxilShaderVisibility VisType,
-  unsigned NumRegisters,
-  unsigned BaseRegister,
-  unsigned RegisterSpace,
-  IStream *pErrors)
-{
+                                                NODE_TYPE nt,
+                                                unsigned iDTS,
+                                                DxilDescriptorRangeType DescType,
+                                                DxilShaderVisibility VisType,
+                                                unsigned NumRegisters,
+                                                unsigned BaseRegister,
+                                                unsigned RegisterSpace,
+                                                IStream *pErrors) {
   RegisterRange interval;
   interval.space = RegisterSpace;
   interval.lb = BaseRegister;
@@ -502,8 +521,7 @@ HRESULT RootSignatureVerifier::AddRegisterRange(unsigned iRP,
 
   if (!m_bAllowReservedRegisterSpace &&
     (RegisterSpace >= DxilSystemReservedRegisterSpaceValuesStart) &&
-    (RegisterSpace <= DxilSystemReservedRegisterSpaceValuesEnd))
-  {
+    (RegisterSpace <= DxilSystemReservedRegisterSpaceValuesEnd)) {
     if (nt == DESCRIPTOR_TABLE_ENTRY)
     {
       ErrorRootSignature(pErrors,
@@ -598,6 +616,20 @@ HRESULT RootSignatureVerifier::AddRegisterRange(unsigned iRP,
   return S_OK;
 }
 
+//QQQ
+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;
+  return GetRanges(VisType, RangeType).FindIntersectingInterval(RR);
+}
+
 static DxilDescriptorRangeType GetRangeType(DxilRootParameterType RPT) {
   switch (RPT) {
   case DxilRootParameterType::CBV: return DxilDescriptorRangeType::CBV;
@@ -609,9 +641,9 @@ static DxilDescriptorRangeType GetRangeType(DxilRootParameterType RPT) {
   return DxilDescriptorRangeType::SRV;
 }
 
-HRESULT RootSignatureVerifier::VerifyRootSignature(const DxilVersionedRootSignatureDesc *pVersionedRootSignature,
-  IStream *pErrors)
-{
+HRESULT RootSignatureVerifier::VerifyRootSignature(
+                                const DxilVersionedRootSignatureDesc *pVersionedRootSignature,
+                                IStream *pErrors) {
   const DxilVersionedRootSignatureDesc *pUpconvertedRS = NULL;
   if (pVersionedRootSignature == nullptr) {
     return E_INVALIDARG;
@@ -802,6 +834,156 @@ HRESULT RootSignatureVerifier::VerifyRootSignature(const DxilVersionedRootSignat
   return S_OK;
 }
 
+//QQQ
+HRESULT RootSignatureVerifier::VerifyShader(DxilShaderVisibility VisType,
+                                            const void *pPSVData,
+                                            uint32_t PSVSize,
+                                            raw_ostream &DiagStream) {
+  HRESULT hr = S_OK;
+  llvm::DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
+
+  DxilPipelineStateValidation PSV;
+  if (!PSV.InitFromPSV0((void*)pPSVData, PSVSize)) {
+    return 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;
+  }
+
+  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)
+        DiagPrinter << "Shader sampler descriptor range (RegisterSpace=" << Space 
+                    << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB 
+                    << ") is not fully bound in root signature\n";
+      break;
+    }
+
+    //QQQ
+#if 0
+    case PSVResourceType::SRVTyped:
+    case PSVResourceType::SRVRaw:
+    case PSVResourceType::SRVStructured: {
+      bShaderHasRootBindings = true;
+      UINT Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
+      TreeNode *pNode = FindRegisterRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, VisType, Num, LB, Space);
+      if(pNode) {
+          if(pNode->nt == ROOT_DESCRIPTOR && pBindInfo0->ResType == (UINT)PSVResourceType::SRVTyped) {
+              VH(ErrorRootSignature(ppErrorBlob, 
+                  "A Shader is declaring a resource object as a texture using a register mapped to a root descriptor SRV (RegisterSpace=%u, ShaderRegister=%u).  "
+                  "SRV or UAV root descriptors can only be Raw or Structured buffers.\n",
+                  Space, LB));
+          }
+      }
+      else {
+          VH(ErrorRootSignature(ppErrorBlob, 
+              "Shader SRV descriptor range (RegisterSpace=%u, NumDescriptors=%u, BaseShaderRegister=%u) is not fully bound in root signature\n",
+              Space, Num, LB));
+      }
+      break;
+    }
+
+    case PSVResourceType::UAVTyped:
+    case PSVResourceType::UAVRaw:
+    case PSVResourceType::UAVStructured:
+    case PSVResourceType::UAVStructuredWithCounter: {
+      bShaderHasRootBindings = true;
+      UINT Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
+      TreeNode *pNode = FindRegisterRange(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, VisType, Num, LB, Space);
+      if(pNode) {
+          if(pNode->nt == ROOT_DESCRIPTOR) {
+              if(pBindInfo0->ResType == (UINT)PSVResourceType::UAVTyped) {
+                  VH(ErrorRootSignature(ppErrorBlob, 
+                      "A Shader is declaring a typed UAV using a register mapped to a root descriptor UAV (RegisterSpace=%u, ShaderRegister=%u).  "
+                      "SRV or UAV root descriptors can only be Raw or Structured buffers.",
+                      Space, LB));
+              }
+              if(pBindInfo0->ResType == (UINT)PSVResourceType::UAVStructuredWithCounter) {
+                  VH(ErrorRootSignature(ppErrorBlob, 
+                      "A Shader is declaring a structured UAV with counter using a register mapped to a root descriptor UAV (RegisterSpace=%u, ShaderRegister=%u).  "
+                      "SRV or UAV root descriptors can only be Raw or Structured buffers.",
+                      Space, LB));
+              }
+          }
+      }
+      else {
+          VH(ErrorRootSignature(ppErrorBlob, 
+              "Shader UAV descriptor range (RegisterSpace=%u, NumDescriptors=%u, BaseShaderRegister=%u) is not fully bound in root signature",
+              Space, Num, LB));
+      }
+      break;
+    }
+
+    case PSVResourceType::CBV: {
+      bShaderHasRootBindings = true;
+      UINT Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
+      TreeNode *pNode = FindRegisterRange(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, VisType, Num, LB, Space);
+      if(!pNode) {
+          VH(ErrorRootSignature(ppErrorBlob, 
+              "Shader CBV descriptor range (RegisterSpace=%u, NumDescriptors=%u, BaseShaderRegister=%u) is not fully bound in root signature\n",
+              Space, Num, LB));
+      }
+      break;
+    }
+#endif
+    default:
+      break;
+    }
+  }
+
+  //QQQ
+#if 0
+  if (bShaderHasRootBindings && bShaderDeniedByRootSig) {
+    VH(ErrorRootSignature(ppErrorBlob, 
+        "Shader has root bindings but root signature uses a DENY flag to disallow root binding access to the shader stage.\n"));
+  }
+#endif
+
+//Cleanup:
+  return hr;
+}
+
+
 BOOL isNaN(const float &a) {
   static const unsigned exponentMask = 0x7f800000;
   static const unsigned mantissaMask = 0x007fffff;
@@ -1643,4 +1825,33 @@ void DeserializeRootSignature(__in_bcount(SrcDataSizeInBytes) const void *pSrcDa
   *ppRootSignature = pRootSignature;
 }
 
+//QQQ
+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;
+  }
+}
+
+bool VerifyRootSignatureWithShaderPSV(__in const DxilVersionedRootSignatureDesc *pDesc,
+                                      __in DXIL::ShaderKind ShaderKind,
+                                      _In_reads_bytes_(PSVSize) const void *pPSVData,
+                                      __in uint32_t PSVSize,
+                                      __in llvm::raw_ostream &DiagStream) {
+  try {
+    RootSignatureVerifier RSV;
+    //QQQ
+    IFT(RSV.VerifyRootSignature(pDesc, nullptr));
+    IFT(RSV.VerifyShader(GetVisibilityType(ShaderKind), pPSVData, PSVSize, DiagStream));
+  } catch (...) {
+    return false;
+  }
+
+  return true;
+}
+
 } // namespace hlsl