Просмотр исходного кода

Refactor PSV code for improved maintainability and error handling (#3115)

Tex Riddell 5 лет назад
Родитель
Сommit
b3df129d1e
1 измененных файлов с 379 добавлено и 404 удалено
  1. 379 404
      include/dxc/DxilContainer/DxilPipelineStateValidation.h

+ 379 - 404
include/dxc/DxilContainer/DxilPipelineStateValidation.h

@@ -14,17 +14,25 @@
 
 #include <stdint.h>
 #include <string.h>
+#include "assert.h"
+
 #ifndef UINT_MAX
 #define UINT_MAX 0xffffffff
 #endif
 // How many dwords are required for mask with one bit per component, 4 components per vector
 inline uint32_t PSVComputeMaskDwordsFromVectors(uint32_t Vectors) { return (Vectors + 7) >> 3; }
-inline uint32_t PSVComputeInputOutputTableSize(uint32_t InputVectors, uint32_t OutputVectors) {
-  return sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(OutputVectors) * InputVectors * 4;
+inline uint32_t PSVComputeInputOutputTableDwords(uint32_t InputVectors, uint32_t OutputVectors) {
+  return PSVComputeMaskDwordsFromVectors(OutputVectors) * InputVectors * 4;
 }
 #define PSVALIGN(ptr, alignbits) (((ptr) + ((1 << (alignbits))-1)) & ~((1 << (alignbits))-1))
 #define PSVALIGN4(ptr) (((ptr) + 3) & ~3)
 
+#ifdef DBG
+#define PSV_RETB(exp) do { if(!(exp)) { assert(false && #exp); return false; } } while(0)
+#else   // DBG
+#define PSV_RETB(exp) do { if(!(exp)) { return false; } } while(0)
+#endif  // DBG
+
 struct VSInfo {
   char OutputPositionPresent;
 };
@@ -335,230 +343,122 @@ public:
 struct PSVInitInfo
 {
   PSVInitInfo(uint32_t psvVersion)
-    : PSVVersion(psvVersion),
-    ResourceCount(0),
-    ShaderStage(PSVShaderKind::Invalid),
-    StringTable(),
-    SemanticIndexTable(),
-    UsesViewID(0),
-    SigInputElements(0),
-    SigOutputElements(0),
-    SigPatchConstOrPrimElements(0),
-    SigInputVectors(0),
-    SigPatchConstOrPrimVectors(0)
+    : PSVVersion(psvVersion)
   {}
-  uint32_t PSVVersion;
-  uint32_t ResourceCount;
-  PSVShaderKind ShaderStage;
+  uint32_t PSVVersion = 0;
+  uint32_t ResourceCount = 0;
+  PSVShaderKind ShaderStage = PSVShaderKind::Invalid;
   PSVStringTable StringTable;
   PSVSemanticIndexTable SemanticIndexTable;
-  uint8_t UsesViewID;
-  uint8_t SigInputElements;
-  uint8_t SigOutputElements;
-  uint8_t SigPatchConstOrPrimElements;
-  uint8_t SigInputVectors;
-  uint8_t SigPatchConstOrPrimVectors;
+  uint8_t UsesViewID = 0;
+  uint8_t SigInputElements = 0;
+  uint8_t SigOutputElements = 0;
+  uint8_t SigPatchConstOrPrimElements = 0;
+  uint8_t SigInputVectors = 0;
+  uint8_t SigPatchConstOrPrimVectors = 0;
   uint8_t SigOutputVectors[4] = {0, 0, 0, 0};
+
+  static_assert(MAX_PSV_VERSION == 1, "otherwise this needs updating.");
+  uint32_t RuntimeInfoSize() const {
+    if (PSVVersion < 1)
+      return sizeof(PSVRuntimeInfo0);
+    return sizeof(PSVRuntimeInfo1);
+  }
+  uint32_t ResourceBindInfoSize() const {
+    return sizeof(PSVResourceBindInfo0);
+  }
+  uint32_t SignatureElementSize() const {
+    return sizeof(PSVSignatureElement0);
+  }
 };
 
 class DxilPipelineStateValidation
 {
-  uint32_t m_uPSVRuntimeInfoSize;
-  PSVRuntimeInfo0* m_pPSVRuntimeInfo0;
-  PSVRuntimeInfo1* m_pPSVRuntimeInfo1;
-  uint32_t m_uResourceCount;
-  uint32_t m_uPSVResourceBindInfoSize;
-  void* m_pPSVResourceBindInfo;
+  uint32_t m_uPSVRuntimeInfoSize = 0;
+  PSVRuntimeInfo0* m_pPSVRuntimeInfo0 = nullptr;
+  PSVRuntimeInfo1 *m_pPSVRuntimeInfo1 = nullptr;
+  uint32_t m_uResourceCount = 0;
+  uint32_t m_uPSVResourceBindInfoSize = 0;
+  void *m_pPSVResourceBindInfo = nullptr;
   PSVStringTable m_StringTable;
   PSVSemanticIndexTable m_SemanticIndexTable;
-  uint32_t m_uPSVSignatureElementSize;
-  void* m_pSigInputElements;
-  void* m_pSigOutputElements;
-  void* m_pSigPatchConstOrPrimElements;
-  uint32_t* m_pViewIDOutputMask;
-  uint32_t* m_pViewIDPCOrPrimOutputMask;
-  uint32_t* m_pInputToOutputTable;
-  uint32_t* m_pInputToPCOutputTable;
-  uint32_t* m_pPCInputToOutputTable;
+  uint32_t m_uPSVSignatureElementSize = 0;
+  void *m_pSigInputElements = nullptr;
+  void *m_pSigOutputElements = nullptr;
+  void *m_pSigPatchConstOrPrimElements = nullptr;
+  uint32_t *m_pViewIDOutputMask = nullptr;
+  uint32_t *m_pViewIDPCOrPrimOutputMask = nullptr;
+  uint32_t *m_pInputToOutputTable = nullptr;
+  uint32_t *m_pInputToPCOutputTable = nullptr;
+  uint32_t *m_pPCInputToOutputTable = nullptr;
 
 public:
-  DxilPipelineStateValidation() :
-    m_uPSVRuntimeInfoSize(0),
-    m_pPSVRuntimeInfo0(nullptr),
-    m_pPSVRuntimeInfo1(nullptr),
-    m_uResourceCount(0),
-    m_uPSVResourceBindInfoSize(0),
-    m_pPSVResourceBindInfo(nullptr),
-    m_StringTable(),
-    m_SemanticIndexTable(),
-    m_uPSVSignatureElementSize(0),
-    m_pSigInputElements(nullptr),
-    m_pSigOutputElements(nullptr),
-    m_pSigPatchConstOrPrimElements(nullptr),
-    m_pViewIDOutputMask(nullptr),
-    m_pViewIDPCOrPrimOutputMask(nullptr),
-    m_pInputToOutputTable(nullptr),
-    m_pInputToPCOutputTable(nullptr),
-    m_pPCInputToOutputTable(nullptr)
-  {
-  }
-
-  // Init() from PSV0 blob part that looks like:
-  // uint32_t PSVRuntimeInfo_size
-  // { PSVRuntimeInfoN structure }
-  // uint32_t ResourceCount
-  // If ResourceCount > 0:
-  //    uint32_t PSVResourceBindInfo_size
-  //    { PSVResourceBindInfoN structure } * ResourceCount
-  // If PSVRuntimeInfo1:
-  //    uint32_t StringTableSize (dword aligned)
-  //    If StringTableSize:
-  //      { StringTableSize bytes, null terminated }
-  //    uint32_t SemanticIndexTableEntries (number of dwords)
-  //    If SemanticIndexTableEntries:
-  //      { semantic index } * SemanticIndexTableEntries
-  //    If SigInputElements || SigOutputElements || SigPatchConstOrPrimElements:
-  //      uint32_t PSVSignatureElement_size
-  //      { PSVSignatureElementN structure } * SigInputElements
-  //      { PSVSignatureElementN structure } * SigOutputElements
-  //      { PSVSignatureElementN structure } * SigPatchConstOrPrimElements
-  //    If (UsesViewID):
-  //      For (i : each stream index 0-3):
-  //        If (SigOutputVectors[i] non-zero):
-  //          { uint32_t * PSVComputeMaskDwordsFromVectors(SigOutputVectors[i]) }
-  //            - Outputs affected by ViewID as a bitmask
-  //      If (HS and SigPatchConstOrPrimVectors non-zero):
-  //        { uint32_t * PSVComputeMaskDwordsFromVectors(SigPatchConstOrPrimVectors) }
-  //          - PCOutputs affected by ViewID as a bitmask
-  //    For (i : each stream index 0-3):
-  //      If (SigInputVectors and SigOutputVectors[i] non-zero):
-  //        { PSVComputeInputOutputTableSize(SigInputVectors, SigOutputVectors[i]) }
-  //          - Outputs affected by inputs as a table of bitmasks
-  //    If (HS and SigPatchConstOrPrimVectors and SigInputVectors non-zero):
-  //      { PSVComputeInputOutputTableSize(SigInputVectors, SigPatchConstOrPrimVectors) }
-  //        - Patch constant outputs affected by inputs as a table of bitmasks
-  //    If (DS and SigOutputVectors[0] and SigPatchConstOrPrimVectors non-zero):
-  //      { PSVComputeInputOutputTableSize(SigPatchConstOrPrimVectors, SigOutputVectors[0]) }
-  //        - Outputs affected by patch constant inputs as a table of bitmasks
-  // returns true if no errors occurred.
-  bool InitFromPSV0(const void* pBits, uint32_t size) {
-    if(!(pBits != nullptr)) return false;
-    uint8_t* pCurBits = (uint8_t*)const_cast<void*>(pBits);
-    uint32_t minsize = sizeof(PSVRuntimeInfo0) + sizeof(uint32_t) * 2;
-    if(!(size >= minsize)) return false;
-    m_uPSVRuntimeInfoSize = *((const uint32_t*)pCurBits);
-    if(!(m_uPSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo0))) return false;
-    pCurBits += sizeof(uint32_t);
-    minsize = m_uPSVRuntimeInfoSize + sizeof(uint32_t) * 2;
-    if(!(size >= minsize)) return false;
-    m_pPSVRuntimeInfo0 = const_cast<PSVRuntimeInfo0*>((const PSVRuntimeInfo0*)pCurBits);
-    if(m_uPSVRuntimeInfoSize >= sizeof(PSVRuntimeInfo1))
-      m_pPSVRuntimeInfo1 = const_cast<PSVRuntimeInfo1*>((const PSVRuntimeInfo1*)pCurBits);
-    pCurBits += m_uPSVRuntimeInfoSize;
-    m_uResourceCount = *(const uint32_t*)pCurBits;
-    pCurBits += sizeof(uint32_t);
-    if (m_uResourceCount > 0) {
-      minsize += sizeof(uint32_t);
-      if(!(size >= minsize)) return false;
-      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<uint8_t*>(pCurBits));
-    }
-    pCurBits += m_uPSVResourceBindInfoSize * m_uResourceCount;
-
-    if (m_pPSVRuntimeInfo1) {
-      minsize += sizeof(uint32_t) * 2;    // m_StringTable.Size and m_SemanticIndexTable.Entries
-      if (!(size >= minsize)) return false;
-      m_StringTable.Size = PSVALIGN4(*(uint32_t*)pCurBits);
-      if (m_StringTable.Size != *(uint32_t*)pCurBits)
-        return false;   // Illegal: Size not aligned
-      minsize += m_StringTable.Size;
-      if (!(size >= minsize)) return false;
-      pCurBits += sizeof(uint32_t);
-      m_StringTable.Table = (const char *)pCurBits;
-      pCurBits += m_StringTable.Size;
-
-      m_SemanticIndexTable.Entries = *(uint32_t*)pCurBits;
-      minsize += sizeof(uint32_t) * m_SemanticIndexTable.Entries;
-      if (!(size >= minsize)) return false;
-      pCurBits += sizeof(uint32_t);
-      m_SemanticIndexTable.Table = (uint32_t*)pCurBits;
-      pCurBits += sizeof(uint32_t) * m_SemanticIndexTable.Entries;
-
-      // Dxil Signature Elements
-      if (m_pPSVRuntimeInfo1->SigInputElements || m_pPSVRuntimeInfo1->SigOutputElements || m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
-        minsize += sizeof(uint32_t);
-        if (!(size >= minsize)) return false;
-        m_uPSVSignatureElementSize = *(uint32_t*)pCurBits;
-        if (m_uPSVSignatureElementSize < sizeof(PSVSignatureElement0))
-          return false;   // Illegal: Size smaller than first version
-        pCurBits += sizeof(uint32_t);
-        minsize += m_uPSVSignatureElementSize * (m_pPSVRuntimeInfo1->SigInputElements + m_pPSVRuntimeInfo1->SigOutputElements + m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements);
-        if (!(size >= minsize)) return false;
-      }
-      if (m_pPSVRuntimeInfo1->SigInputElements) {
-        m_pSigInputElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigInputElements;
-      }
-      if (m_pPSVRuntimeInfo1->SigOutputElements) {
-        m_pSigOutputElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigOutputElements;
-      }
-      if (m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
-        m_pSigPatchConstOrPrimElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements;
-      }
+  DxilPipelineStateValidation() {}
 
-      // ViewID dependencies
-      if (m_pPSVRuntimeInfo1->UsesViewID) {
-        for (unsigned i = 0; i < 4; i++) {
-          if (m_pPSVRuntimeInfo1->SigOutputVectors[i]) {
-            minsize += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-            if (!(size >= minsize)) return false;
-            m_pViewIDOutputMask = (uint32_t*)pCurBits;
-            pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-          }
-          if (!IsGS())
-            break;
-        }
-        if ((IsHS() || IsMS()) && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors) {
-          minsize += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-          if (!(size >= minsize)) return false;
-          m_pViewIDPCOrPrimOutputMask = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-        }
-      }
+  enum class RWMode {
+    Read,
+    CalcSize,
+    Write,
+  };
 
-      // Input to Output dependencies
-      for (unsigned i = 0; i < 4; i++) {
-        if (!IsMS() && m_pPSVRuntimeInfo1->SigOutputVectors[i] > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-          minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-          if (!(size >= minsize)) return false;
-          m_pInputToOutputTable = (uint32_t*)pCurBits;
-          pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-        }
-        if (!IsGS())
-          break;
-      }
-      if ((IsHS() || IsMS()) && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-        if (!(size >= minsize)) return false;
-        m_pInputToPCOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-      }
-      if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0) {
-        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
-        if (!(size >= minsize)) return false;
-        m_pPCInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
-      }
-    }
+  class CheckedReaderWriter {
+  private:
+    char *Ptr;
+    uint32_t Size;
+    uint32_t Offset;
+    RWMode Mode;
+
+  public:
+    CheckedReaderWriter(const void *ptr, uint32_t size, RWMode mode)
+      : Ptr(reinterpret_cast<char*>(const_cast<void*>(ptr))),
+        Size(mode == RWMode::CalcSize ? 0 : size), Offset(0), Mode(mode) {}
+
+    uint32_t GetSize() { return Size; }
+    RWMode GetMode() { return Mode; }
+
+    // Return true if size fits in remaing buffer.
+    bool CheckBounds(size_t size);
+    // Increment Offset by size. Return false on error.
+    bool IncrementPos(size_t size);
+
+    // Cast and return true if it fits.
+    template <typename _T> bool Cast(_T **ppPtr, size_t size);
+    template <typename _T> bool Cast(_T **ppPtr);
+
+    // Map* methods increment Offset.
+
+    // Assign pointer, increment Offset, and return true if size fits.
+    template<typename _T> bool MapPtr(_T **ppPtr, size_t size = 0);
+    // Read value, increment Offset, and return true if value fits.
+    template <typename _T> bool MapValue(_T *pValue, const _T init = {});
+    // Assign pointer, increment Offset, and return true if array fits.
+    template <typename _T>
+    bool MapArray(_T **ppPtr, size_t count, size_t eltSize);
+    //template <> bool MapArray<void>(void **ppPtr, size_t count, size_t eltSize);
+    // Assign pointer, increment Offset, and return true if array fits.
+    template <typename _T> bool MapArray(_T **ppPtr, size_t count = 1);
+
+    void Clear();
+  };
+
+  // Assigned derived ptr to base if size large enough.
+  template<typename _Base, typename _T>
+  bool AssignDerived(_T** ppDerived, _Base* pBase, uint32_t size) {
+    if ((size_t)size < sizeof(_T))
+      return false;   // size not large enough for type
+    *ppDerived = reinterpret_cast<_T *>(pBase);
     return true;
   }
 
+private:
+  bool ReadOrWrite(const void *pBits, uint32_t *pSize, RWMode mode,
+                   const PSVInitInfo &initInfo = PSVInitInfo(MAX_PSV_VERSION));
+
+public:
+  bool InitFromPSV0(const void* pBits, uint32_t size) {
+    return ReadOrWrite(pBits, &size, RWMode::Read);
+  }
+
   // Initialize a new buffer
   // call with null pBuffer to get required size
 
@@ -569,174 +469,8 @@ public:
   }
 
   bool InitNew(const PSVInitInfo &initInfo, void *pBuffer, uint32_t *pSize) {
-    if(!(pSize)) return false;
-    if (initInfo.PSVVersion > MAX_PSV_VERSION) return false;
-
-    // Versioned structure sizes
-    m_uPSVRuntimeInfoSize = sizeof(PSVRuntimeInfo0);
-    m_uPSVResourceBindInfoSize = sizeof(PSVResourceBindInfo0);
-    m_uPSVSignatureElementSize = sizeof(PSVSignatureElement0);
-    if (initInfo.PSVVersion > 0) {
-      m_uPSVRuntimeInfoSize = sizeof(PSVRuntimeInfo1);
-    }
-
-    // PSVVersion 0
-    uint32_t size = m_uPSVRuntimeInfoSize + sizeof(uint32_t) * 2;
-    if (initInfo.ResourceCount) {
-      size += sizeof(uint32_t) + (m_uPSVResourceBindInfoSize * initInfo.ResourceCount);
-    }
-
-    // PSVVersion 1
-    if (initInfo.PSVVersion > 0) {
-      size += sizeof(uint32_t) + PSVALIGN4(initInfo.StringTable.Size);
-      size += sizeof(uint32_t) + sizeof(uint32_t) * initInfo.SemanticIndexTable.Entries;
-      if (initInfo.SigInputElements || initInfo.SigOutputElements || initInfo.SigPatchConstOrPrimElements) {
-        size += sizeof(uint32_t);   // PSVSignatureElement_size
-      }
-      size += m_uPSVSignatureElementSize * initInfo.SigInputElements;
-      size += m_uPSVSignatureElementSize * initInfo.SigOutputElements;
-      size += m_uPSVSignatureElementSize * initInfo.SigPatchConstOrPrimElements;
-
-      if (initInfo.UsesViewID) {
-        for (unsigned i = 0; i < 4; i++) {
-          size += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(initInfo.SigOutputVectors[i]);
-          if (initInfo.ShaderStage != PSVShaderKind::Geometry)
-            break;
-        }
-        if (initInfo.ShaderStage == PSVShaderKind::Hull || initInfo.ShaderStage == PSVShaderKind::Mesh)
-          size += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(initInfo.SigPatchConstOrPrimVectors);
-      }
-      if (initInfo.SigInputVectors > 0) {
-        for (unsigned i = 0; i < 4; i++) {
-          if (initInfo.SigOutputVectors[i] > 0) {
-            size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigOutputVectors[i]);
-            if (initInfo.ShaderStage != PSVShaderKind::Geometry)
-              break;
-          }
-        }
-        if (initInfo.ShaderStage == PSVShaderKind::Hull && initInfo.SigPatchConstOrPrimVectors > 0 && initInfo.SigInputVectors > 0) {
-          size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigPatchConstOrPrimVectors);
-        }
-      }
-      if (initInfo.ShaderStage == PSVShaderKind::Domain && initInfo.SigOutputVectors[0] > 0 && initInfo.SigPatchConstOrPrimVectors > 0) {
-        size += PSVComputeInputOutputTableSize(initInfo.SigPatchConstOrPrimVectors, initInfo.SigOutputVectors[0]);
-      }
-    }
-
-    // Validate or return required size
-    if (pBuffer) {
-      if(!(*pSize >= size)) return false;
-    } else {
-      *pSize = size;
-      return true;
-    }
-
-    // PSVVersion 0
-    memset(pBuffer, 0, size);
-    uint8_t* pCurBits = (uint8_t*)pBuffer;
-    *(uint32_t*)pCurBits = m_uPSVRuntimeInfoSize;
-    pCurBits += sizeof(uint32_t);
-    m_pPSVRuntimeInfo0 = (PSVRuntimeInfo0*)pCurBits;
-    if (initInfo.PSVVersion > 0) {
-      m_pPSVRuntimeInfo1 = (PSVRuntimeInfo1*)pCurBits;
-    }
-    pCurBits += m_uPSVRuntimeInfoSize;
-
-    // Set resource info:
-    m_uResourceCount = initInfo.ResourceCount;
-    *(uint32_t*)pCurBits = m_uResourceCount;
-    pCurBits += sizeof(uint32_t);
-    if (m_uResourceCount > 0) {
-      *(uint32_t*)pCurBits = m_uPSVResourceBindInfoSize;
-      pCurBits += sizeof(uint32_t);
-      m_pPSVResourceBindInfo = pCurBits;
-    }
-    pCurBits += m_uPSVResourceBindInfoSize * m_uResourceCount;
-
-    // PSVVersion 1
-    if (initInfo.PSVVersion) {
-      m_pPSVRuntimeInfo1->ShaderStage = (uint8_t)initInfo.ShaderStage;
-      m_pPSVRuntimeInfo1->UsesViewID = initInfo.UsesViewID;
-      m_pPSVRuntimeInfo1->SigInputElements = initInfo.SigInputElements;
-      m_pPSVRuntimeInfo1->SigOutputElements = initInfo.SigOutputElements;
-      m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements = initInfo.SigPatchConstOrPrimElements;
-      m_pPSVRuntimeInfo1->SigInputVectors = initInfo.SigInputVectors;
-      memcpy(m_pPSVRuntimeInfo1->SigOutputVectors, initInfo.SigOutputVectors, 4);
-      if (IsHS() || IsDS() || IsMS()) {
-        m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors = initInfo.SigPatchConstOrPrimVectors;
-      }
-
-      // Note: if original size was unaligned, padding has already been zero initialized
-      m_StringTable.Size = PSVALIGN4(initInfo.StringTable.Size);
-      *(uint32_t*)pCurBits = m_StringTable.Size;
-      pCurBits += sizeof(uint32_t);
-      memcpy(pCurBits, initInfo.StringTable.Table, initInfo.StringTable.Size);
-      m_StringTable.Table = (const char *)pCurBits;
-      pCurBits += m_StringTable.Size;
-
-      m_SemanticIndexTable.Entries = initInfo.SemanticIndexTable.Entries;
-      *(uint32_t*)pCurBits = m_SemanticIndexTable.Entries;
-      pCurBits += sizeof(uint32_t);
-      memcpy(pCurBits, initInfo.SemanticIndexTable.Table, sizeof(uint32_t) * initInfo.SemanticIndexTable.Entries);
-      m_SemanticIndexTable.Table = (const uint32_t*)pCurBits;
-      pCurBits += sizeof(uint32_t) * m_SemanticIndexTable.Entries;
-
-      // Dxil Signature Elements
-      if (m_pPSVRuntimeInfo1->SigInputElements || m_pPSVRuntimeInfo1->SigOutputElements || m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
-        *(uint32_t*)pCurBits = m_uPSVSignatureElementSize;
-        pCurBits += sizeof(uint32_t);
-      }
-      if (m_pPSVRuntimeInfo1->SigInputElements) {
-        m_pSigInputElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigInputElements;
-      }
-      if (m_pPSVRuntimeInfo1->SigOutputElements) {
-        m_pSigOutputElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigOutputElements;
-      }
-      if (m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
-        m_pSigPatchConstOrPrimElements = (PSVSignatureElement0*)pCurBits;
-        pCurBits += m_uPSVSignatureElementSize * m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements;
-      }
-
-      // ViewID dependencies
-      if (m_pPSVRuntimeInfo1->UsesViewID) {
-        for (unsigned i = 0; i < 4; i++) {
-          if (m_pPSVRuntimeInfo1->SigOutputVectors[i]) {
-            m_pViewIDOutputMask = (uint32_t*)pCurBits;
-            pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-          }
-          if (!IsGS())
-            break;
-        }
-        if ((IsHS() || IsMS()) && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors) {
-          m_pViewIDPCOrPrimOutputMask = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-        }
-      }
-
-      // Input to Output dependencies
-      if (m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-        for (unsigned i = 0; i < 4; i++) {
-          if (m_pPSVRuntimeInfo1->SigOutputVectors[i] > 0) {
-            m_pInputToOutputTable = (uint32_t*)pCurBits;
-            pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i]);
-          }
-          if (!IsGS())
-            break;
-        }
-        if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-          m_pInputToPCOutputTable = (uint32_t*)pCurBits;
-          pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
-        }
-      }
-      if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0) {
-        m_pPCInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
-      }
-    }
-
-    return true;
+    RWMode Mode = nullptr != pBuffer ? RWMode::Write : RWMode::CalcSize;
+    return ReadOrWrite(pBuffer, pSize, Mode, initInfo);
   }
 
   PSVRuntimeInfo0* GetPSVRuntimeInfo0() const {
@@ -751,15 +485,23 @@ public:
     return m_uResourceCount;
   }
 
-  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) const {
-    if (index < m_uResourceCount && m_pPSVResourceBindInfo &&
-        sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize) {
-      return (PSVResourceBindInfo0*)((uint8_t*)m_pPSVResourceBindInfo +
-        (index * m_uPSVResourceBindInfoSize));
+  template <typename _T>
+  _T *GetRecord(void *pRecords, uint32_t recordSize, uint32_t numRecords,
+                uint32_t index) const {
+    if (pRecords && index < numRecords && sizeof(_T) <= recordSize) {
+      __analysis_assume((size_t)index * (size_t)recordSize <= UINT_MAX);
+      return reinterpret_cast<_T *>(reinterpret_cast<uint8_t *>(pRecords) +
+                                    (index * recordSize));
     }
     return nullptr;
   }
 
+  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) const {
+    return GetRecord<PSVResourceBindInfo0>(m_pPSVResourceBindInfo,
+                                           m_uPSVResourceBindInfoSize,
+                                           m_uResourceCount, index);
+  }
+
   const PSVStringTable &GetStringTable() const { return m_StringTable; }
   const PSVSemanticIndexTable &GetSemanticIndexTable() const { return m_SemanticIndexTable; }
 
@@ -780,31 +522,19 @@ public:
     return 0;
   }
   PSVSignatureElement0* GetInputElement0(uint32_t index) const {
-    if (m_pPSVRuntimeInfo1 && m_pSigInputElements &&
-        index < m_pPSVRuntimeInfo1->SigInputElements &&
-        sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
-      return (PSVSignatureElement0*)((uint8_t*)m_pSigInputElements +
-        (index * m_uPSVSignatureElementSize));
-    }
-    return nullptr;
+    return GetRecord<PSVSignatureElement0>(
+        m_pSigInputElements, m_uPSVSignatureElementSize,
+        m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigInputElements : 0, index);
   }
   PSVSignatureElement0* GetOutputElement0(uint32_t index) const {
-    if (m_pPSVRuntimeInfo1 && m_pSigOutputElements &&
-        index < m_pPSVRuntimeInfo1->SigOutputElements &&
-        sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
-      return (PSVSignatureElement0*)((uint8_t*)m_pSigOutputElements +
-        (index * m_uPSVSignatureElementSize));
-    }
-    return nullptr;
+    return GetRecord<PSVSignatureElement0>(
+        m_pSigOutputElements, m_uPSVSignatureElementSize,
+        m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigOutputElements : 0, index);
   }
   PSVSignatureElement0* GetPatchConstOrPrimElement0(uint32_t index) const {
-    if (m_pPSVRuntimeInfo1 && m_pSigPatchConstOrPrimElements &&
-        index < m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements &&
-        sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
-      return (PSVSignatureElement0*)((uint8_t*)m_pSigPatchConstOrPrimElements +
-        (index * m_uPSVSignatureElementSize));
-    }
-    return nullptr;
+    return GetRecord<PSVSignatureElement0>(
+        m_pSigPatchConstOrPrimElements, m_uPSVSignatureElementSize,
+        m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements : 0, index);
   }
   // More convenient wrapper:
   PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) const {
@@ -845,7 +575,7 @@ public:
     return PSVDependencyTable();
   }
   PSVDependencyTable GetInputToPCOutputTable() const {
-    if ((IsHS() || IsMS()) && m_pInputToPCOutputTable && m_pPSVRuntimeInfo1) {
+    if (IsHS() && m_pInputToPCOutputTable && m_pPSVRuntimeInfo1) {
       return PSVDependencyTable(m_pInputToPCOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
     }
     return PSVDependencyTable();
@@ -858,6 +588,249 @@ public:
   }
 };
 
+// Return true if size fits in remaing buffer.
+inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::CheckBounds(size_t size) {
+  if (Mode != RWMode::CalcSize) {
+    PSV_RETB(size <= UINT_MAX);
+    PSV_RETB(Offset <= Size);
+    return (uint32_t)size <= Size - Offset;
+  }
+  return true;
+}
+// Increment Offset by size. Return false on error.
+inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::IncrementPos(size_t size) {
+  PSV_RETB(size <= UINT_MAX);
+  uint32_t uSize = size;
+  if (Mode == RWMode::CalcSize) {
+    PSV_RETB(uSize <= Size + uSize);
+    Size += uSize;
+  }
+  PSV_RETB(CheckBounds(size));
+  Offset += size;
+  return true;
+}
+
+// Cast and return true if it fits.
+template <typename _T> inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::Cast(_T **ppPtr, size_t size) {
+  PSV_RETB(CheckBounds(size));
+  *ppPtr = reinterpret_cast<_T*>(Ptr + Offset);
+  return true;
+}
+template <typename _T>
+inline bool DxilPipelineStateValidation::CheckedReaderWriter::Cast(_T **ppPtr) {
+  return Cast(ppPtr, sizeof(_T));
+}
+
+// Map* methods increment Offset.
+
+// Assign pointer, increment Offset, and return true if size fits.
+template<typename _T>
+inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::MapPtr(_T **ppPtr, size_t size) {
+  PSV_RETB(Cast(ppPtr, size));
+  PSV_RETB(IncrementPos(size));
+  return true;
+}
+// Read value, increment Offset, and return true if value fits.
+template <typename _T>
+inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::MapValue(_T *pValue, const _T init) {
+  _T *pPtr = nullptr;
+  PSV_RETB(MapPtr(&pPtr, sizeof(_T)));
+  switch (Mode) {
+  case RWMode::Read: *pValue = *pPtr; break;
+  case RWMode::CalcSize: *pValue = init; break;
+  case RWMode::Write: *pPtr = *pValue = init; break;
+  }
+  return true;
+}
+// Assign pointer, increment Offset, and return true if array fits.
+template <typename _T>
+inline bool DxilPipelineStateValidation::CheckedReaderWriter::MapArray(
+    _T **ppPtr, size_t count, size_t eltSize) {
+  PSV_RETB(count <= UINT_MAX && eltSize <= UINT_MAX && eltSize >= sizeof(_T));
+  return count ? MapPtr(ppPtr, eltSize * count) : true;
+}
+//template <> bool MapArray<void>(void **ppPtr, size_t count, size_t eltSize);
+template <>
+inline bool DxilPipelineStateValidation::CheckedReaderWriter::MapArray<void>(
+    void **ppPtr, size_t count, size_t eltSize) {
+  PSV_RETB(count <= UINT_MAX && eltSize <= UINT_MAX && eltSize > 0);
+  return count ? MapPtr(ppPtr, eltSize * count) : true;
+}
+
+// Assign pointer, increment Offset, and return true if array fits.
+template <typename _T>
+inline bool
+DxilPipelineStateValidation::CheckedReaderWriter::MapArray(_T **ppPtr, size_t count) {
+  return count ? MapArray(ppPtr, count, sizeof(_T)) : true;
+}
+
+inline void DxilPipelineStateValidation::CheckedReaderWriter::Clear() {
+  if (Mode == RWMode::Write) {
+    memset(Ptr, 0, Size);
+  }
+}
+
+// PSV0 blob part looks like:
+// uint32_t PSVRuntimeInfo_size
+// { PSVRuntimeInfoN structure }
+// uint32_t ResourceCount
+// If ResourceCount > 0:
+//    uint32_t PSVResourceBindInfo_size
+//    { PSVResourceBindInfoN structure } * ResourceCount
+// If PSVRuntimeInfo1:
+//    uint32_t StringTableSize (dword aligned)
+//    If StringTableSize:
+//      { StringTableSize bytes, null terminated }
+//    uint32_t SemanticIndexTableEntries (number of dwords)
+//    If SemanticIndexTableEntries:
+//      { semantic index } * SemanticIndexTableEntries
+//    If SigInputElements || SigOutputElements || SigPatchConstOrPrimElements:
+//      uint32_t PSVSignatureElement_size
+//      { PSVSignatureElementN structure } * SigInputElements
+//      { PSVSignatureElementN structure } * SigOutputElements
+//      { PSVSignatureElementN structure } * SigPatchConstOrPrimElements
+//    If (UsesViewID):
+//      For (i : each stream index 0-3):
+//        If (SigOutputVectors[i] non-zero):
+//          { uint32_t * PSVComputeMaskDwordsFromVectors(SigOutputVectors[i]) }
+//            - Outputs affected by ViewID as a bitmask
+//      If (HS and SigPatchConstOrPrimVectors non-zero):
+//        { uint32_t * PSVComputeMaskDwordsFromVectors(SigPatchConstOrPrimVectors) }
+//          - PCOutputs affected by ViewID as a bitmask
+//    For (i : each stream index 0-3):
+//      If (SigInputVectors and SigOutputVectors[i] non-zero):
+//        { uint32_t * PSVComputeInputOutputTableDwords(SigInputVectors, SigOutputVectors[i]) }
+//          - Outputs affected by inputs as a table of bitmasks
+//    If (HS and SigPatchConstOrPrimVectors and SigInputVectors non-zero):
+//      { uint32_t * PSVComputeInputOutputTableDwords(SigInputVectors, SigPatchConstOrPrimVectors) }
+//        - Patch constant outputs affected by inputs as a table of bitmasks
+//    If (DS and SigOutputVectors[0] and SigPatchConstOrPrimVectors non-zero):
+//      { uint32_t * PSVComputeInputOutputTableDwords(SigPatchConstOrPrimVectors, SigOutputVectors[0]) }
+//        - Outputs affected by patch constant inputs as a table of bitmasks
+// returns true if no errors occurred.
+inline bool DxilPipelineStateValidation::ReadOrWrite(
+    const void *pBits, uint32_t *pSize, RWMode mode,
+    const PSVInitInfo &initInfo) {
+  PSV_RETB(pSize != nullptr);
+  PSV_RETB(pBits != nullptr || mode == RWMode::CalcSize);
+  PSV_RETB(initInfo.PSVVersion <= MAX_PSV_VERSION);
+
+  CheckedReaderWriter rw(pBits, *pSize, mode);
+  rw.Clear();
+
+  PSV_RETB(rw.MapValue(&m_uPSVRuntimeInfoSize, initInfo.RuntimeInfoSize()));
+  PSV_RETB(rw.MapArray(&m_pPSVRuntimeInfo0, 1, m_uPSVRuntimeInfoSize));
+  AssignDerived(&m_pPSVRuntimeInfo1, m_pPSVRuntimeInfo0, m_uPSVRuntimeInfoSize); // failure ok
+
+  // In RWMode::CalcSize, use temp runtime info to hold needed values from initInfo
+  PSVRuntimeInfo1 tempRuntimeInfo = {};
+  if (mode == RWMode::CalcSize && initInfo.PSVVersion > 0) {
+    m_pPSVRuntimeInfo1 = &tempRuntimeInfo;
+  }
+
+  PSV_RETB(rw.MapValue(&m_uResourceCount, initInfo.ResourceCount));
+
+  if (m_uResourceCount > 0) {
+    PSV_RETB(rw.MapValue(&m_uPSVResourceBindInfoSize, initInfo.ResourceBindInfoSize()));
+    PSV_RETB(sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize);
+    PSV_RETB(rw.MapArray(&m_pPSVResourceBindInfo, m_uResourceCount, m_uPSVResourceBindInfoSize));
+  }
+
+  if (m_pPSVRuntimeInfo1) {
+    if (mode != RWMode::Read) {
+      m_pPSVRuntimeInfo1->ShaderStage = (uint8_t)initInfo.ShaderStage;
+      m_pPSVRuntimeInfo1->SigInputElements = initInfo.SigInputElements;
+      m_pPSVRuntimeInfo1->SigOutputElements = initInfo.SigOutputElements;
+      m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements = initInfo.SigPatchConstOrPrimElements;
+      m_pPSVRuntimeInfo1->UsesViewID = initInfo.UsesViewID;
+      for (unsigned i = 0; i < 4; i++) {
+        m_pPSVRuntimeInfo1->SigOutputVectors[i] = initInfo.SigOutputVectors[i];
+      }
+      if (IsHS() || IsDS() || IsMS()) {
+        m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors = initInfo.SigPatchConstOrPrimVectors;
+      }
+      m_pPSVRuntimeInfo1->SigInputVectors = initInfo.SigInputVectors;
+    }
+
+    PSV_RETB(rw.MapValue(&m_StringTable.Size, PSVALIGN4(initInfo.StringTable.Size)));
+    PSV_RETB(PSVALIGN4(m_StringTable.Size) == m_StringTable.Size);
+    if (m_StringTable.Size) {
+      PSV_RETB(rw.MapArray(&m_StringTable.Table, m_StringTable.Size));
+      if (mode == RWMode::Write) {
+        memcpy(const_cast<char*>(m_StringTable.Table), initInfo.StringTable.Table, initInfo.StringTable.Size);
+      }
+    }
+
+    PSV_RETB(rw.MapValue(&m_SemanticIndexTable.Entries, initInfo.SemanticIndexTable.Entries));
+    if (m_SemanticIndexTable.Entries) {
+      PSV_RETB(rw.MapArray(&m_SemanticIndexTable.Table, m_SemanticIndexTable.Entries));
+      if (mode == RWMode::Write) {
+        memcpy(const_cast<uint32_t*>(m_SemanticIndexTable.Table), initInfo.SemanticIndexTable.Table, sizeof(uint32_t) * initInfo.SemanticIndexTable.Entries);
+      }
+    }
+
+    // Dxil Signature Elements
+    if (m_pPSVRuntimeInfo1->SigInputElements || m_pPSVRuntimeInfo1->SigOutputElements || m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
+      PSV_RETB(rw.MapValue(&m_uPSVSignatureElementSize, initInfo.SignatureElementSize()));
+      PSV_RETB(sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize);
+      if (m_pPSVRuntimeInfo1->SigInputElements) {
+        PSV_RETB(rw.MapArray(&m_pSigInputElements, m_pPSVRuntimeInfo1->SigInputElements, m_uPSVSignatureElementSize));
+      }
+      if (m_pPSVRuntimeInfo1->SigOutputElements) {
+        PSV_RETB(rw.MapArray(&m_pSigOutputElements, m_pPSVRuntimeInfo1->SigOutputElements, m_uPSVSignatureElementSize));
+      }
+      if (m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
+        PSV_RETB(rw.MapArray(&m_pSigPatchConstOrPrimElements, m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements, m_uPSVSignatureElementSize));
+      }
+    }
+
+    // ViewID dependencies
+    if (m_pPSVRuntimeInfo1->UsesViewID) {
+      for (unsigned i = 0; i < 4; i++) {
+        if (m_pPSVRuntimeInfo1->SigOutputVectors[i]) {
+          PSV_RETB(rw.MapArray(&m_pViewIDOutputMask,
+            PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors[i])));
+        }
+        if (!IsGS())
+          break;
+      }
+      if ((IsHS() || IsMS()) && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors) {
+        PSV_RETB(rw.MapArray(&m_pViewIDPCOrPrimOutputMask,
+          PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors)));
+      }
+    }
+
+    // Input to Output dependencies
+    for (unsigned i = 0; i < 4; i++) {
+      if (!IsMS() && m_pPSVRuntimeInfo1->SigOutputVectors[i] > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
+        PSV_RETB(rw.MapArray(&m_pInputToOutputTable,
+          PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i])));
+      }
+      if (!IsGS())
+        break;
+    }
+    if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
+      PSV_RETB(rw.MapArray(&m_pInputToPCOutputTable,
+        PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors)));
+    }
+    if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0) {
+      PSV_RETB(rw.MapArray(&m_pPCInputToOutputTable,
+        PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0])));
+    }
+  }
+
+  if (mode == RWMode::CalcSize) {
+    *pSize = rw.GetSize();
+    m_pPSVRuntimeInfo1 = nullptr; // clear ptr to tempRuntimeInfo
+  }
+  return true;
+}
+
 namespace hlsl {
 
   class ViewIDValidator {
@@ -885,4 +858,6 @@ namespace hlsl {
 
 }
 
+#undef PSV_RETB
+
 #endif  // __DXIL_PIPELINE_STATE_VALIDATION__H__