Bladeren bron

Implement ViewIDPipelineValidation

- Update PSV data for GS multi stream out and other improvements
- Add ViewIDPipelineValidation.inl
- Refactor DxilSigPoint to .inl for easy external use
- Add Barycentrics feature flag
Tex Riddell 8 jaren geleden
bovenliggende
commit
0b5ab5c87a

+ 1 - 0
include/dxc/HLSL/DxilContainer.h

@@ -104,6 +104,7 @@ static const uint64_t ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeed
 static const uint64_t ShaderFeatureInfo_WaveOps = 0x4000;
 static const uint64_t ShaderFeatureInfo_WaveOps = 0x4000;
 static const uint64_t ShaderFeatureInfo_Int64Ops = 0x8000;
 static const uint64_t ShaderFeatureInfo_Int64Ops = 0x8000;
 static const uint64_t ShaderFeatureInfo_ViewID = 0x10000;
 static const uint64_t ShaderFeatureInfo_ViewID = 0x10000;
+static const uint64_t ShaderFeatureInfo_Barycentrics = 0x20000;
 
 
 static const unsigned ShaderFeatureInfoCount = 16;
 static const unsigned ShaderFeatureInfoCount = 16;
 
 

+ 5 - 2
include/dxc/HLSL/DxilModule.h

@@ -168,7 +168,8 @@ public:
 
 
     uint64_t GetFeatureInfo() const;
     uint64_t GetFeatureInfo() const;
     bool GetWaveOps() const { return m_bWaveOps; }
     bool GetWaveOps() const { return m_bWaveOps; }
-    bool GetUsesViewId() const { return m_bViewID != 0; }
+    bool GetViewID() const { return m_bViewID; }
+    bool GetBarycentrics() const { return m_bBarycentrics; }
     void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
     void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
     void SetROVs(bool flag) { m_bROVS = flag; }
     void SetROVs(bool flag) { m_bROVS = flag; }
     void SetWaveOps(bool flag) { m_bWaveOps = flag; }
     void SetWaveOps(bool flag) { m_bWaveOps = flag; }
@@ -182,6 +183,7 @@ public:
     void Set64UAVs(bool flag) { m_b64UAVs = flag; }
     void Set64UAVs(bool flag) { m_b64UAVs = flag; }
     void SetUAVsAtEveryStage(bool flag) { m_UAVsAtEveryStage = flag; }
     void SetUAVsAtEveryStage(bool flag) { m_UAVsAtEveryStage = flag; }
     void SetViewID(bool flag) { m_bViewID = flag; }
     void SetViewID(bool flag) { m_bViewID = flag; }
+    void SetBarycentrics(bool flag) { m_bBarycentrics = flag; }
 
 
     static uint64_t GetShaderFlagsRawForCollection(); // some flags are collected (eg use 64-bit), some provided (eg allow refactoring)
     static uint64_t GetShaderFlagsRawForCollection(); // some flags are collected (eg use 64-bit), some provided (eg allow refactoring)
     uint64_t GetShaderFlagsRaw() const;
     uint64_t GetShaderFlagsRaw() const;
@@ -216,8 +218,9 @@ public:
     unsigned m_bWaveOps :1;           // SHADER_FEATURE_WAVE_OPS
     unsigned m_bWaveOps :1;           // SHADER_FEATURE_WAVE_OPS
     unsigned m_bInt64Ops :1;          // SHADER_FEATURE_INT64_OPS
     unsigned m_bInt64Ops :1;          // SHADER_FEATURE_INT64_OPS
     unsigned m_bViewID : 1;           // SHADER_FEATURE_VIEWID
     unsigned m_bViewID : 1;           // SHADER_FEATURE_VIEWID
+    unsigned m_bBarycentrics : 1;     // SHADER_FEATURE_BARYCENTRICS
 
 
-    unsigned m_align0 :10;        // align to 32 bit.
+    unsigned m_align0 : 9;        // align to 32 bit.
     uint32_t m_align1;            // align to 64 bit.
     uint32_t m_align1;            // align to 64 bit.
   };
   };
 
 

+ 230 - 119
include/dxc/HLSL/DxilPipelineStateValidation.h

@@ -14,6 +14,7 @@
 
 
 #include <stdint.h>
 #include <stdint.h>
 #include <string.h>
 #include <string.h>
+#include <memory>
 
 
 // How many dwords are required for mask with one bit per component, 4 components per vector
 // 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 PSVComputeMaskDwordsFromVectors(uint32_t Vectors) { return (Vectors + 7) >> 3; }
@@ -55,8 +56,21 @@ struct PSVRuntimeInfo0
   uint32_t MinimumExpectedWaveLaneCount;  // minimum lane count required, 0 if unused
   uint32_t MinimumExpectedWaveLaneCount;  // minimum lane count required, 0 if unused
   uint32_t MaximumExpectedWaveLaneCount;  // maximum lane count required, 0xffffffff if unused
   uint32_t MaximumExpectedWaveLaneCount;  // maximum lane count required, 0xffffffff if unused
 };
 };
+
+enum class PSVShaderKind : uint8_t    // DXIL::ShaderKind
+{
+  Pixel = 0,
+  Vertex,
+  Geometry,
+  Hull,
+  Domain,
+  Compute,
+  Invalid,
+};
+
 struct PSVRuntimeInfo1 : public PSVRuntimeInfo0
 struct PSVRuntimeInfo1 : public PSVRuntimeInfo0
 {
 {
+  uint8_t ShaderStage;              // PSVShaderKind
   uint8_t UsesViewID;
   uint8_t UsesViewID;
 
 
   // PSVSignatureElement counts
   // PSVSignatureElement counts
@@ -66,9 +80,9 @@ struct PSVRuntimeInfo1 : public PSVRuntimeInfo0
 
 
   // Number of packed vectors per signature
   // Number of packed vectors per signature
   uint8_t SigInputVectors;
   uint8_t SigInputVectors;
-  uint8_t SigOutputVectors;
-  uint8_t SigPCOutputVectors;       // HS only
-  uint8_t SigPCInputVectors;        // DS only
+  uint8_t SigPatchConstantVectors;  // Output for HS Input for DS
+  uint8_t SigOutputVectors[4];      // Array for GS Stream Out Index
+  uint8_t Reserved;
 };
 };
 
 
 enum class PSVResourceType
 enum class PSVResourceType
@@ -99,33 +113,36 @@ struct PSVResourceBindInfo0
 // PSVResourceBindInfo1 would derive and extend
 // PSVResourceBindInfo1 would derive and extend
 
 
 // Helpers for output dependencies (ViewID and Input-Output tables)
 // Helpers for output dependencies (ViewID and Input-Output tables)
-struct PSVComponentMasks {
-  uint32_t *Masks;
+struct PSVComponentMask {
+  uint32_t *Mask;
   uint32_t NumVectors;
   uint32_t NumVectors;
-  PSVComponentMasks() : Masks(nullptr), NumVectors(0) {}
-  PSVComponentMasks(uint32_t *pMasks, uint32_t outputVectors)
-  : Masks(pMasks),
+  PSVComponentMask() : Mask(nullptr), NumVectors(0) {}
+  PSVComponentMask(const PSVComponentMask &other) : Mask(other.Mask), NumVectors(other.NumVectors) {}
+  PSVComponentMask(uint32_t *pMask, uint32_t outputVectors)
+  : Mask(pMask),
     NumVectors(outputVectors)
     NumVectors(outputVectors)
   {}
   {}
-  const PSVComponentMasks &operator|=(const PSVComponentMasks &other) {
-    _Analysis_assume_(NumVectors == other.NumVectors && Masks && other.Masks);
-    uint32_t dwords = PSVComputeMaskDwordsFromVectors(NumVectors);
+  const PSVComponentMask &operator|=(const PSVComponentMask &other) {
+    uint32_t dwords = PSVComputeMaskDwordsFromVectors(NumVectors < other.NumVectors ? NumVectors : other.NumVectors);
     for (uint32_t i = 0; i < dwords; ++i) {
     for (uint32_t i = 0; i < dwords; ++i) {
-      Masks[i] |= other.Masks[i];
+      Mask[i] |= other.Mask[i];
     }
     }
+    return *this;
   }
   }
-  uint32_t Get(uint32_t ComponentIndex) const {
-    _Analysis_assume_(ComponentIndex < (NumVectors * 4));
-    return Masks[ComponentIndex >> 5] & (1 << (ComponentIndex & 0x1F));
+  bool Get(uint32_t ComponentIndex) const {
+    if(ComponentIndex < NumVectors * 4)
+      return (bool)(Mask[ComponentIndex >> 5] & (1 << (ComponentIndex & 0x1F)));
+    return false;
   }
   }
   void Set(uint32_t ComponentIndex) {
   void Set(uint32_t ComponentIndex) {
-    _Analysis_assume_(ComponentIndex < (NumVectors * 4));
-    Masks[ComponentIndex >> 5] |= (1 << (ComponentIndex & 0x1F));
+    if (ComponentIndex < NumVectors * 4)
+      Mask[ComponentIndex >> 5] |= (1 << (ComponentIndex & 0x1F));
   }
   }
   void Clear(uint32_t ComponentIndex) {
   void Clear(uint32_t ComponentIndex) {
-    _Analysis_assume_(ComponentIndex < (NumVectors * 4));
-    Masks[ComponentIndex >> 5] &= ~(1 << (ComponentIndex & 0x1F));
+    if (ComponentIndex < NumVectors * 4)
+      Mask[ComponentIndex >> 5] &= ~(1 << (ComponentIndex & 0x1F));
   }
   }
+  bool IsValid() { return Mask != nullptr; }
 };
 };
 
 
 struct PSVDependencyTable {
 struct PSVDependencyTable {
@@ -133,16 +150,18 @@ struct PSVDependencyTable {
   uint32_t InputVectors;
   uint32_t InputVectors;
   uint32_t OutputVectors;
   uint32_t OutputVectors;
   PSVDependencyTable() : Table(nullptr), InputVectors(0), OutputVectors(0) {}
   PSVDependencyTable() : Table(nullptr), InputVectors(0), OutputVectors(0) {}
+  PSVDependencyTable(const PSVDependencyTable &other) : Table(other.Table), InputVectors(other.InputVectors), OutputVectors(other.OutputVectors) {}
   PSVDependencyTable(uint32_t *pTable, uint32_t inputVectors, uint32_t outputVectors)
   PSVDependencyTable(uint32_t *pTable, uint32_t inputVectors, uint32_t outputVectors)
   : Table(pTable),
   : Table(pTable),
     InputVectors(inputVectors),
     InputVectors(inputVectors),
     OutputVectors(outputVectors)
     OutputVectors(outputVectors)
   {}
   {}
-  PSVComponentMasks GetMasksForInput(uint32_t inputComponentIndex) {
+  PSVComponentMask GetMaskForInput(uint32_t inputComponentIndex) {
     if (!Table || !InputVectors || !OutputVectors)
     if (!Table || !InputVectors || !OutputVectors)
-      return PSVComponentMasks();
-    return PSVComponentMasks(Table + (PSVComputeMaskDwordsFromVectors(OutputVectors) * inputComponentIndex), OutputVectors);
+      return PSVComponentMask();
+    return PSVComponentMask(Table + (PSVComputeMaskDwordsFromVectors(OutputVectors) * inputComponentIndex), OutputVectors);
   }
   }
+  bool IsValid() { return Table != nullptr; }
 };
 };
 
 
 // Table of null-terminated strings, overall size aligned to dword boundary, last byte must be null
 // Table of null-terminated strings, overall size aligned to dword boundary, last byte must be null
@@ -181,6 +200,40 @@ struct PSVSemanticIndexes {
   uint32_t *Get(const PSVSemanticIndexTable &table) const { table.Get(Offset); }
   uint32_t *Get(const PSVSemanticIndexTable &table) const { table.Get(Offset); }
 };
 };
 
 
+enum class PSVSemanticKind : uint8_t    // DXIL::SemanticKind
+{
+  Arbitrary,
+  VertexID,
+  InstanceID,
+  Position,
+  RenderTargetArrayIndex,
+  ViewPortArrayIndex,
+  ClipDistance,
+  CullDistance,
+  OutputControlPointID,
+  DomainLocation,
+  PrimitiveID,
+  GSInstanceID,
+  SampleIndex,
+  IsFrontFace,
+  Coverage,
+  InnerCoverage,
+  Target,
+  Depth,
+  DepthLessEqual,
+  DepthGreaterEqual,
+  StencilRef,
+  DispatchThreadID,
+  GroupID,
+  GroupIndex,
+  GroupThreadID,
+  TessFactor,
+  InsideTessFactor,
+  ViewID,
+  Barycentrics,
+  Invalid,
+};
+
 struct PSVSignatureElement0
 struct PSVSignatureElement0
 {
 {
   uint32_t SemanticName;          // Offset into PSVStringTable
   uint32_t SemanticName;          // Offset into PSVStringTable
@@ -188,7 +241,7 @@ struct PSVSignatureElement0
   uint8_t Rows;                   // Number of rows this element occupies
   uint8_t Rows;                   // Number of rows this element occupies
   uint8_t StartRow;               // Starting row of packing location if allocated
   uint8_t StartRow;               // Starting row of packing location if allocated
   uint8_t ColsAndStart;           // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated
   uint8_t ColsAndStart;           // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated
-  uint8_t SemanticKind;           // DxilProgramSigSemantic or D3D_NAME
+  uint8_t SemanticKind;           // PSVSemanticKind
   uint8_t ComponentType;          // DxilProgramSigCompType
   uint8_t ComponentType;          // DxilProgramSigCompType
   uint8_t InterpolationMode;      // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
   uint8_t InterpolationMode;      // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
   uint8_t DynamicMaskAndStream;   // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3)
   uint8_t DynamicMaskAndStream;   // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3)
@@ -212,7 +265,7 @@ public:
   bool IsAllocated() const { return !m_pElement0 ? false : !!(m_pElement0->ColsAndStart & 0x40); }
   bool IsAllocated() const { return !m_pElement0 ? false : !!(m_pElement0->ColsAndStart & 0x40); }
   int32_t GetStartRow() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)m_pElement0->StartRow; }
   int32_t GetStartRow() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)m_pElement0->StartRow; }
   int32_t GetStartCol() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)((m_pElement0->ColsAndStart >> 4) & 0x3); }
   int32_t GetStartCol() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)((m_pElement0->ColsAndStart >> 4) & 0x3); }
-  uint32_t GetSemanticKind() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->SemanticKind; }
+  PSVSemanticKind GetSemanticKind() const { return !m_pElement0 ? (PSVSemanticKind)0 : (PSVSemanticKind)m_pElement0->SemanticKind; }
   uint32_t GetComponentType() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->ComponentType; }
   uint32_t GetComponentType() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->ComponentType; }
   uint32_t GetInterpolationMode() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->InterpolationMode; }
   uint32_t GetInterpolationMode() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->InterpolationMode; }
   uint32_t GetOutputStream() const { return !m_pElement0 ? 0 : (uint32_t)(m_pElement0->DynamicMaskAndStream >> 4) & 0x3; }
   uint32_t GetOutputStream() const { return !m_pElement0 ? 0 : (uint32_t)(m_pElement0->DynamicMaskAndStream >> 4) & 0x3; }
@@ -224,6 +277,7 @@ struct PSVInitInfo
   PSVInitInfo(uint32_t psvVersion)
   PSVInitInfo(uint32_t psvVersion)
     : PSVVersion(psvVersion),
     : PSVVersion(psvVersion),
     ResourceCount(0),
     ResourceCount(0),
+    ShaderStage(PSVShaderKind::Invalid),
     StringTable(),
     StringTable(),
     SemanticIndexTable(),
     SemanticIndexTable(),
     UsesViewID(0),
     UsesViewID(0),
@@ -231,12 +285,11 @@ struct PSVInitInfo
     SigOutputElements(0),
     SigOutputElements(0),
     SigPatchConstantElements(0),
     SigPatchConstantElements(0),
     SigInputVectors(0),
     SigInputVectors(0),
-    SigOutputVectors(0),
-    SigPCOutputVectors(0),
-    SigPCInputVectors(0)
+    SigPatchConstantVectors(0)
   {}
   {}
   uint32_t PSVVersion;
   uint32_t PSVVersion;
   uint32_t ResourceCount;
   uint32_t ResourceCount;
+  PSVShaderKind ShaderStage;
   PSVStringTable StringTable;
   PSVStringTable StringTable;
   PSVSemanticIndexTable SemanticIndexTable;
   PSVSemanticIndexTable SemanticIndexTable;
   uint8_t UsesViewID;
   uint8_t UsesViewID;
@@ -244,9 +297,8 @@ struct PSVInitInfo
   uint8_t SigOutputElements;
   uint8_t SigOutputElements;
   uint8_t SigPatchConstantElements;
   uint8_t SigPatchConstantElements;
   uint8_t SigInputVectors;
   uint8_t SigInputVectors;
-  uint8_t SigOutputVectors;
-  uint8_t SigPCOutputVectors;       // HS only
-  uint8_t SigPCInputVectors;        // DS only
+  uint8_t SigPatchConstantVectors;
+  uint8_t SigOutputVectors[4] = {0, 0, 0, 0};
 };
 };
 
 
 class DxilPipelineStateValidation
 class DxilPipelineStateValidation
@@ -263,8 +315,8 @@ class DxilPipelineStateValidation
   void* m_pSigInputElements;
   void* m_pSigInputElements;
   void* m_pSigOutputElements;
   void* m_pSigOutputElements;
   void* m_pSigPatchConstantElements;
   void* m_pSigPatchConstantElements;
-  uint32_t* m_pViewIDOutputMasks;
-  uint32_t* m_pViewIDPCOutputMasks;
+  uint32_t* m_pViewIDOutputMask;
+  uint32_t* m_pViewIDPCOutputMask;
   uint32_t* m_pInputToOutputTable;
   uint32_t* m_pInputToOutputTable;
   uint32_t* m_pInputToPCOutputTable;
   uint32_t* m_pInputToPCOutputTable;
   uint32_t* m_pPCInputToOutputTable;
   uint32_t* m_pPCInputToOutputTable;
@@ -283,8 +335,8 @@ public:
     m_pSigInputElements(nullptr),
     m_pSigInputElements(nullptr),
     m_pSigOutputElements(nullptr),
     m_pSigOutputElements(nullptr),
     m_pSigPatchConstantElements(nullptr),
     m_pSigPatchConstantElements(nullptr),
-    m_pViewIDOutputMasks(nullptr),
-    m_pViewIDPCOutputMasks(nullptr),
+    m_pViewIDOutputMask(nullptr),
+    m_pViewIDPCOutputMask(nullptr),
     m_pInputToOutputTable(nullptr),
     m_pInputToOutputTable(nullptr),
     m_pInputToPCOutputTable(nullptr),
     m_pInputToPCOutputTable(nullptr),
     m_pPCInputToOutputTable(nullptr)
     m_pPCInputToOutputTable(nullptr)
@@ -310,20 +362,23 @@ public:
   //      { PSVSignatureElementN structure } * SigInputElements
   //      { PSVSignatureElementN structure } * SigInputElements
   //      { PSVSignatureElementN structure } * SigOutputElements
   //      { PSVSignatureElementN structure } * SigOutputElements
   //      { PSVSignatureElementN structure } * SigPatchConstantElements
   //      { PSVSignatureElementN structure } * SigPatchConstantElements
-  //    If (UsesViewID and SigOutputVectors non-zero):
-  //      { uint32_t * PSVComputeMaskDwordsFromVectors(SigOutputVectors) }
-  //        - Outputs affected by ViewID as a bitmask
-  //    If (UsesViewID and SigPCOutputVectors non-zero):
-  //      { uint32_t * PSVComputeMaskDwordsFromVectors(SigPCOutputVectors) }
-  //        - PCOutputs affected by ViewID as a bitmask
-  //    If (SigInputVectors and SigOutputVectors non-zero):
-  //      { PSVComputeInputOutputTableSize(SigInputVectors, SigOutputVectors) }
-  //        - Outputs affected by inputs as a table of bitmasks
-  //    If (SigPCOutputVectors and SigInputVectors non-zero): (HS only)
-  //      { PSVComputeInputOutputTableSize(SigInputVectors, SigPCOutputVectors) }
+  //    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 SigPatchConstantVectors non-zero):
+  //        { uint32_t * PSVComputeMaskDwordsFromVectors(SigPatchConstantVectors) }
+  //          - 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 SigPatchConstantVectors and SigInputVectors non-zero):
+  //      { PSVComputeInputOutputTableSize(SigInputVectors, SigPatchConstantVectors) }
   //        - Patch constant outputs affected by inputs as a table of bitmasks
   //        - Patch constant outputs affected by inputs as a table of bitmasks
-  //    If (SigOutputVectors and SigPCInputVectors non-zero): (DS only)
-  //      { PSVComputeInputOutputTableSize(SigPCInputVectors, SigOutputVectors) }
+  //    If (DS and SigOutputVectors[0] and SigPatchConstantVectors non-zero):
+  //      { PSVComputeInputOutputTableSize(SigPatchConstantVectors, SigOutputVectors[0]) }
   //        - Outputs affected by patch constant inputs as a table of bitmasks
   //        - Outputs affected by patch constant inputs as a table of bitmasks
   // returns true if no errors occurred.
   // returns true if no errors occurred.
   bool InitFromPSV0(const void* pBits, uint32_t size) {
   bool InitFromPSV0(const void* pBits, uint32_t size) {
@@ -399,38 +454,46 @@ public:
 
 
       // ViewID dependencies
       // ViewID dependencies
       if (m_pPSVRuntimeInfo1->UsesViewID) {
       if (m_pPSVRuntimeInfo1->UsesViewID) {
-        if (m_pPSVRuntimeInfo1->SigOutputVectors) {
-          minsize += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors);
-          if (!(size >= minsize)) return false;
-          m_pViewIDOutputMasks = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors);
+        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 (m_pPSVRuntimeInfo1->SigPCOutputVectors) {
-          minsize += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPCOutputVectors);
+        if (m_pPSVRuntimeInfo1->ShaderStage == (uint8_t)PSVShaderKind::Hull && m_pPSVRuntimeInfo1->SigPatchConstantVectors) {
+          minsize += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstantVectors);
           if (!(size >= minsize)) return false;
           if (!(size >= minsize)) return false;
-          m_pViewIDPCOutputMasks = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPCOutputVectors);
+          m_pViewIDPCOutputMask = (uint32_t*)pCurBits;
+          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstantVectors);
         }
         }
       }
       }
 
 
       // Input to Output dependencies
       // Input to Output dependencies
-      if (m_pPSVRuntimeInfo1->SigOutputVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
-        if (!(size >= minsize)) return false;
-        m_pInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+      for (unsigned i = 0; i < 4; i++) {
+        if (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 (m_pPSVRuntimeInfo1->SigPCOutputVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPCOutputVectors);
+      if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstantVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
+        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstantVectors);
         if (!(size >= minsize)) return false;
         if (!(size >= minsize)) return false;
         m_pInputToPCOutputTable = (uint32_t*)pCurBits;
         m_pInputToPCOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPCOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstantVectors);
       }
       }
-      if (m_pPSVRuntimeInfo1->SigOutputVectors > 0 && m_pPSVRuntimeInfo1->SigPCInputVectors > 0) {
-        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+      if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstantVectors > 0) {
+        minsize += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
         if (!(size >= minsize)) return false;
         if (!(size >= minsize)) return false;
         m_pPCInputToOutputTable = (uint32_t*)pCurBits;
         m_pPCInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
       }
       }
     }
     }
     return true;
     return true;
@@ -475,20 +538,26 @@ public:
       size += m_uPSVSignatureElementSize * initInfo.SigPatchConstantElements;
       size += m_uPSVSignatureElementSize * initInfo.SigPatchConstantElements;
 
 
       if (initInfo.UsesViewID) {
       if (initInfo.UsesViewID) {
-        size += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(initInfo.SigOutputVectors);
-        size += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(initInfo.SigPCOutputVectors);
-      }
-      if (initInfo.SigPCOutputVectors > 0 && initInfo.SigPCInputVectors > 0) {
-        return false;   // Invalid to have both
+        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)
+          size += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(initInfo.SigPatchConstantVectors);
       }
       }
-      if (initInfo.SigOutputVectors > 0 && initInfo.SigInputVectors > 0) {
-        size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigOutputVectors);
+      for (unsigned i = 0; i < 4; i++) {
+        if (initInfo.SigOutputVectors[i] > 0 && initInfo.SigInputVectors > 0) {
+          size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigOutputVectors[i]);
+          if (initInfo.ShaderStage != PSVShaderKind::Geometry)
+            break;
+        }
       }
       }
-      if (initInfo.SigPCOutputVectors > 0 && initInfo.SigInputVectors > 0) {
-        size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigPCOutputVectors);
+      if (initInfo.ShaderStage == PSVShaderKind::Hull && initInfo.SigPatchConstantVectors > 0 && initInfo.SigInputVectors > 0) {
+        size += PSVComputeInputOutputTableSize(initInfo.SigInputVectors, initInfo.SigPatchConstantVectors);
       }
       }
-      if (initInfo.SigOutputVectors > 0 && initInfo.SigPCInputVectors > 0) {
-        size += PSVComputeInputOutputTableSize(initInfo.SigPCInputVectors, initInfo.SigOutputVectors);
+      if (initInfo.ShaderStage == PSVShaderKind::Domain && initInfo.SigOutputVectors[0] > 0 && initInfo.SigPatchConstantVectors > 0) {
+        size += PSVComputeInputOutputTableSize(initInfo.SigPatchConstantVectors, initInfo.SigOutputVectors[0]);
       }
       }
     }
     }
 
 
@@ -524,14 +593,14 @@ public:
 
 
     // PSVVersion 1
     // PSVVersion 1
     if (initInfo.PSVVersion) {
     if (initInfo.PSVVersion) {
+      m_pPSVRuntimeInfo1->ShaderStage = (uint8_t)initInfo.ShaderStage;
       m_pPSVRuntimeInfo1->UsesViewID = initInfo.UsesViewID;
       m_pPSVRuntimeInfo1->UsesViewID = initInfo.UsesViewID;
       m_pPSVRuntimeInfo1->SigInputElements = initInfo.SigInputElements;
       m_pPSVRuntimeInfo1->SigInputElements = initInfo.SigInputElements;
       m_pPSVRuntimeInfo1->SigOutputElements = initInfo.SigOutputElements;
       m_pPSVRuntimeInfo1->SigOutputElements = initInfo.SigOutputElements;
       m_pPSVRuntimeInfo1->SigPatchConstantElements = initInfo.SigPatchConstantElements;
       m_pPSVRuntimeInfo1->SigPatchConstantElements = initInfo.SigPatchConstantElements;
       m_pPSVRuntimeInfo1->SigInputVectors = initInfo.SigInputVectors;
       m_pPSVRuntimeInfo1->SigInputVectors = initInfo.SigInputVectors;
-      m_pPSVRuntimeInfo1->SigOutputVectors = initInfo.SigOutputVectors;
-      m_pPSVRuntimeInfo1->SigPCOutputVectors = initInfo.SigPCOutputVectors;
-      m_pPSVRuntimeInfo1->SigPCInputVectors = initInfo.SigPCInputVectors;
+      memcpy(m_pPSVRuntimeInfo1->SigOutputVectors, initInfo.SigOutputVectors, 4);
+      m_pPSVRuntimeInfo1->SigPatchConstantVectors = initInfo.SigPatchConstantVectors;
 
 
       // Note: if original size was unaligned, padding has already been zero initialized
       // Note: if original size was unaligned, padding has already been zero initialized
       m_StringTable.Size = PSVALIGN4(initInfo.StringTable.Size);
       m_StringTable.Size = PSVALIGN4(initInfo.StringTable.Size);
@@ -568,39 +637,47 @@ public:
 
 
       // ViewID dependencies
       // ViewID dependencies
       if (m_pPSVRuntimeInfo1->UsesViewID) {
       if (m_pPSVRuntimeInfo1->UsesViewID) {
-        if (m_pPSVRuntimeInfo1->SigOutputVectors) {
-          m_pViewIDOutputMasks = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors);
+        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 (m_pPSVRuntimeInfo1->SigPCOutputVectors) {
-          m_pViewIDPCOutputMasks = (uint32_t*)pCurBits;
-          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPCOutputVectors);
+        if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstantVectors) {
+          m_pViewIDPCOutputMask = (uint32_t*)pCurBits;
+          pCurBits += sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstantVectors);
         }
         }
       }
       }
 
 
       // Input to Output dependencies
       // Input to Output dependencies
-      if (m_pPSVRuntimeInfo1->SigOutputVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
-        m_pInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+      for (unsigned i = 0; i < 4; i++) {
+        if (m_pPSVRuntimeInfo1->SigOutputVectors[i] > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
+          m_pInputToOutputTable = (uint32_t*)pCurBits;
+          pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i]);
+        }
+        if (!IsGS())
+          break;
       }
       }
-      if (m_pPSVRuntimeInfo1->SigPCOutputVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
+      if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstantVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
         m_pInputToPCOutputTable = (uint32_t*)pCurBits;
         m_pInputToPCOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPCOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstantVectors);
       }
       }
-      if (m_pPSVRuntimeInfo1->SigOutputVectors > 0 && m_pPSVRuntimeInfo1->SigPCInputVectors > 0) {
+      if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstantVectors > 0) {
         m_pPCInputToOutputTable = (uint32_t*)pCurBits;
         m_pPCInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
       }
       }
     }
     }
 
 
     return true;
     return true;
   }
   }
 
 
-  PSVRuntimeInfo0* GetPSVRuntimeInfo0() {
+  PSVRuntimeInfo0* GetPSVRuntimeInfo0() const {
     return m_pPSVRuntimeInfo0;
     return m_pPSVRuntimeInfo0;
   }
   }
 
 
-  PSVRuntimeInfo1* GetPSVRuntimeInfo1() {
+  PSVRuntimeInfo1* GetPSVRuntimeInfo1() const {
     return m_pPSVRuntimeInfo1;
     return m_pPSVRuntimeInfo1;
   }
   }
 
 
@@ -608,7 +685,7 @@ public:
     return m_uResourceCount;
     return m_uResourceCount;
   }
   }
 
 
-  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) {
+  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) const {
     if (index < m_uResourceCount && m_pPSVResourceBindInfo &&
     if (index < m_uResourceCount && m_pPSVResourceBindInfo &&
         sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize) {
         sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize) {
       return (PSVResourceBindInfo0*)((uint8_t*)m_pPSVResourceBindInfo +
       return (PSVResourceBindInfo0*)((uint8_t*)m_pPSVResourceBindInfo +
@@ -617,8 +694,8 @@ public:
     return nullptr;
     return nullptr;
   }
   }
 
 
-  const PSVStringTable &GetStringTable() { return m_StringTable; }
-  const PSVSemanticIndexTable &GetSemanticIndexTable() { return m_SemanticIndexTable; }
+  const PSVStringTable &GetStringTable() const { return m_StringTable; }
+  const PSVSemanticIndexTable &GetSemanticIndexTable() const { return m_SemanticIndexTable; }
 
 
   // Signature element access
   // Signature element access
   uint32_t GetSigInputElements() const {
   uint32_t GetSigInputElements() const {
@@ -636,7 +713,7 @@ public:
       return m_pPSVRuntimeInfo1->SigPatchConstantElements;
       return m_pPSVRuntimeInfo1->SigPatchConstantElements;
     return 0;
     return 0;
   }
   }
-  PSVSignatureElement0* GetInputElement0(uint32_t index) {
+  PSVSignatureElement0* GetInputElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigInputElements &&
     if (m_pPSVRuntimeInfo1 && m_pSigInputElements &&
         index < m_pPSVRuntimeInfo1->SigInputElements &&
         index < m_pPSVRuntimeInfo1->SigInputElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -645,7 +722,7 @@ public:
     }
     }
     return nullptr;
     return nullptr;
   }
   }
-  PSVSignatureElement0* GetOutputElement0(uint32_t index) {
+  PSVSignatureElement0* GetOutputElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigOutputElements &&
     if (m_pPSVRuntimeInfo1 && m_pSigOutputElements &&
         index < m_pPSVRuntimeInfo1->SigOutputElements &&
         index < m_pPSVRuntimeInfo1->SigOutputElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -654,7 +731,7 @@ public:
     }
     }
     return nullptr;
     return nullptr;
   }
   }
-  PSVSignatureElement0* GetPatchConstantElement0(uint32_t index) {
+  PSVSignatureElement0* GetPatchConstantElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigPatchConstantElements &&
     if (m_pPSVRuntimeInfo1 && m_pSigPatchConstantElements &&
         index < m_pPSVRuntimeInfo1->SigPatchConstantElements &&
         index < m_pPSVRuntimeInfo1->SigPatchConstantElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -664,42 +741,76 @@ public:
     return nullptr;
     return nullptr;
   }
   }
   // More convenient wrapper:
   // More convenient wrapper:
-  PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) {
+  PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) const {
     return PSVSignatureElement(m_StringTable, m_SemanticIndexTable, pElement0);
     return PSVSignatureElement(m_StringTable, m_SemanticIndexTable, pElement0);
   }
   }
 
 
+  PSVShaderKind GetShaderKind() const {
+    if (m_pPSVRuntimeInfo1 && m_pPSVRuntimeInfo1->ShaderStage < (uint8_t)PSVShaderKind::Invalid)
+      return (PSVShaderKind)m_pPSVRuntimeInfo1->ShaderStage;
+    return PSVShaderKind::Invalid;
+  }
+  bool IsVS() const { return GetShaderKind() == PSVShaderKind::Vertex; }
+  bool IsHS() const { return GetShaderKind() == PSVShaderKind::Hull; }
+  bool IsDS() const { return GetShaderKind() == PSVShaderKind::Domain; }
+  bool IsGS() const { return GetShaderKind() == PSVShaderKind::Geometry; }
+  bool IsPS() const { return GetShaderKind() == PSVShaderKind::Pixel; }
+  bool IsCS() const { return GetShaderKind() == PSVShaderKind::Compute; }
+
   // ViewID dependencies
   // ViewID dependencies
-  PSVComponentMasks GetViewIDOutputMasks() {
-    if (!m_pViewIDOutputMasks || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigOutputVectors)
-      return PSVComponentMasks();
-    return PSVComponentMasks(m_pViewIDOutputMasks, m_pPSVRuntimeInfo1->SigOutputVectors);
+  PSVComponentMask GetViewIDOutputMask(unsigned streamIndex = 0) const {
+    if (!m_pViewIDOutputMask || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex])
+      return PSVComponentMask();
+    return PSVComponentMask(m_pViewIDOutputMask, m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex]);
   }
   }
-  PSVComponentMasks GetViewIDPCOutputMasks() {
-    if (!m_pViewIDPCOutputMasks || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigPCOutputVectors)
-      return PSVComponentMasks();
-    return PSVComponentMasks(m_pViewIDPCOutputMasks, m_pPSVRuntimeInfo1->SigPCOutputVectors);
+  PSVComponentMask GetViewIDPCOutputMask() const {
+    if (!IsHS() || !m_pViewIDPCOutputMask || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigPatchConstantVectors)
+      return PSVComponentMask();
+    return PSVComponentMask(m_pViewIDPCOutputMask, m_pPSVRuntimeInfo1->SigPatchConstantVectors);
   }
   }
 
 
   // Input to Output dependencies
   // Input to Output dependencies
-  PSVDependencyTable GetInputToOutputTable() {
+  PSVDependencyTable GetInputToOutputTable(unsigned streamIndex = 0) const {
     if (m_pInputToOutputTable && m_pPSVRuntimeInfo1) {
     if (m_pInputToOutputTable && m_pPSVRuntimeInfo1) {
-      return PSVDependencyTable(m_pInputToOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+      return PSVDependencyTable(m_pInputToOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex]);
     }
     }
     return PSVDependencyTable();
     return PSVDependencyTable();
   }
   }
-  PSVDependencyTable GetInputToPCOutputTable() {
-    if (m_pInputToPCOutputTable && m_pPSVRuntimeInfo1) {
-      return PSVDependencyTable(m_pInputToPCOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPCOutputVectors);
+  PSVDependencyTable GetInputToPCOutputTable() const {
+    if (IsHS() && m_pInputToPCOutputTable && m_pPSVRuntimeInfo1) {
+      return PSVDependencyTable(m_pInputToPCOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstantVectors);
     }
     }
     return PSVDependencyTable();
     return PSVDependencyTable();
   }
   }
-  PSVDependencyTable GetPCInputToOutputTable() {
-    if (m_pPCInputToOutputTable && m_pPSVRuntimeInfo1) {
-      return PSVDependencyTable(m_pPCInputToOutputTable, m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+  PSVDependencyTable GetPCInputToOutputTable() const {
+    if (IsDS() && m_pPCInputToOutputTable && m_pPSVRuntimeInfo1) {
+      return PSVDependencyTable(m_pPCInputToOutputTable, m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
     }
     }
     return PSVDependencyTable();
     return PSVDependencyTable();
   }
   }
 };
 };
 
 
+namespace hlsl {
+
+  class ViewIDValidator {
+  public:
+    enum class Result {
+      Success = 0,
+      InsufficientSpace,
+      InsufficientPCSpace,
+      MismatchedSignatures,
+      MismatchedPCSignatures,
+      InvalidUsage,
+      InvalidPSVVersion,
+      InvalidPSV,
+    };
+    virtual ~ViewIDValidator() {}
+    virtual Result ValidateStage(const DxilPipelineStateValidation &PSV,
+                                 unsigned &mismatchElementId) = 0;
+  };
+
+  std::unique_ptr<ViewIDValidator> NewViewIDValidator(unsigned viewIDCount, unsigned gsRastStreamIndex);
+
+}
 
 
 #endif  // __DXIL_PIPELINE_STATE_VALIDATION__H__
 #endif  // __DXIL_PIPELINE_STATE_VALIDATION__H__

+ 0 - 1
include/dxc/HLSL/DxilSigPoint.h

@@ -11,7 +11,6 @@
 
 
 #pragma once
 #pragma once
 
 
-#include "llvm/ADT/StringRef.h"
 #include "DxilConstants.h"
 #include "DxilConstants.h"
 
 
 namespace hlsl {
 namespace hlsl {

+ 1 - 8
lib/HLSL/DxilSigPoint.cpp → include/dxc/HLSL/DxilSigPoint.inl

@@ -1,19 +1,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 //                                                                           //
 //                                                                           //
-// DxilSigPoint.cpp                                                          //
+// DxilSigPoint.inl                                                          //
 // Copyright (C) Microsoft Corporation. All rights reserved.                 //
 // Copyright (C) Microsoft Corporation. All rights reserved.                 //
 // This file is distributed under the University of Illinois Open Source     //
 // This file is distributed under the University of Illinois Open Source     //
 // License. See LICENSE.TXT for details.                                     //
 // License. See LICENSE.TXT for details.                                     //
 //                                                                           //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
 
-#include "dxc/HLSL/DxilSigPoint.h"
-#include "dxc/Support/Global.h"
-
-#include <string>
-
-using std::string;
-
 /* <py>
 /* <py>
 import hctdb_instrhelp
 import hctdb_instrhelp
 </py> */
 </py> */

+ 1 - 1
include/dxc/HLSL/DxilSignature.h

@@ -46,7 +46,7 @@ public:
   bool IsFullyAllocated() const;
   bool IsFullyAllocated() const;
 
 
   // Returns the number of allocated vectors used to contain signature
   // Returns the number of allocated vectors used to contain signature
-  unsigned NumVectorsUsed() const;
+  unsigned NumVectorsUsed(unsigned streamIndex =  0) const;
 
 
 private:
 private:
   DXIL::SigPointKind m_sigPointKind;
   DXIL::SigPointKind m_sigPointKind;

+ 3 - 1
include/dxc/HLSL/DxilSignatureAllocator.h

@@ -42,12 +42,14 @@ public:
     DXIL::SemanticKind kind;
     DXIL::SemanticKind kind;
     DXIL::InterpolationMode interpolation;
     DXIL::InterpolationMode interpolation;
     DXIL::SemanticInterpretationKind interpretation;
     DXIL::SemanticInterpretationKind interpretation;
+    uint32_t indexFlags;
 
 
   public:
   public:
     DummyElement(uint32_t index = 0) : id(index), rows(1), cols(1), row((uint32_t)-1), col((uint32_t)-1),
     DummyElement(uint32_t index = 0) : id(index), rows(1), cols(1), row((uint32_t)-1), col((uint32_t)-1),
       kind(DXIL::SemanticKind::Arbitrary),
       kind(DXIL::SemanticKind::Arbitrary),
       interpolation(DXIL::InterpolationMode::Undefined),
       interpolation(DXIL::InterpolationMode::Undefined),
-      interpretation(DXIL::SemanticInterpretationKind::Arb)
+      interpretation(DXIL::SemanticInterpretationKind::Arb),
+      indexFlags(0)
     {}
     {}
     __override ~DummyElement() {}
     __override ~DummyElement() {}
     __override uint32_t GetID() const { return id; }
     __override uint32_t GetID() const { return id; }

+ 419 - 0
include/dxc/HLSL/ViewIDPipelineValidation.inl

@@ -0,0 +1,419 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ViewIDPipelineValidation.inl                                              //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// This file implements inter-stage validation for ViewID.                   //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+
+namespace hlsl {
+
+namespace {
+
+typedef std::vector<DxilSignatureAllocator::DummyElement> ElementVec;
+
+struct ComponentMask : public PSVComponentMask {
+  uint32_t Data[4];
+  ComponentMask() : PSVComponentMask(Data, 0) {
+    memset(Data, 0, sizeof(Data));
+  }
+  ComponentMask(const ComponentMask &other) : PSVComponentMask(Data, other.NumVectors) {
+    *this = other;
+  }
+  ComponentMask(const PSVComponentMask &other) : PSVComponentMask(Data, other.NumVectors) {
+    *this = other;
+  }
+  ComponentMask &operator=(const PSVComponentMask &other) {
+    NumVectors = other.NumVectors;
+    if (other.Mask && NumVectors) {
+      memcpy(Data, other.Mask, sizeof(uint32_t) * PSVComputeMaskDwordsFromVectors(NumVectors));
+    }
+    else {
+      memset(Data, 0, sizeof(Data));
+    }
+    return *this;
+  }
+  ComponentMask &operator|=(const PSVComponentMask &other) {
+    NumVectors = std::max(NumVectors, other.NumVectors);
+    PSVComponentMask::operator|=(other);
+    return *this;
+  }
+};
+
+static void InitElement(DxilSignatureAllocator::DummyElement &eOut,
+                        const PSVSignatureElement &eIn,
+                        DXIL::SigPointKind sigPoint) {
+  eOut.rows = eIn.GetRows();
+  eOut.cols = eIn.GetCols();
+  eOut.row = eIn.GetStartRow();
+  eOut.col = eIn.GetStartCol();
+  eOut.kind = (DXIL::SemanticKind)eIn.GetSemanticKind();
+  eOut.interpolation = (DXIL::InterpolationMode)eIn.GetInterpolationMode();
+  eOut.interpretation = SigPoint::GetInterpretation(eOut.kind, sigPoint, 6, 1);
+  eOut.indexFlags = eIn.GetDynamicIndexMask();
+}
+
+static void CopyElements( ElementVec &outElements,
+                          DXIL::SigPointKind sigPoint,
+                          unsigned numElements,
+                          unsigned streamIndex,
+                          std::function<PSVSignatureElement(unsigned)> getElement) {
+  outElements.clear();
+  outElements.reserve(numElements);
+  for (unsigned i = 0; i < numElements; i++) {
+    auto inEl = getElement(i);
+    if (!inEl.IsAllocated() || inEl.GetOutputStream() != streamIndex)
+      continue;
+    outElements.emplace_back(i);
+    DxilSignatureAllocator::DummyElement &el = outElements.back();
+    InitElement(el, inEl, sigPoint);
+  }
+}
+
+static void AddViewIDElements(ElementVec &outElements,
+                              ElementVec &inElements,
+                              PSVComponentMask &mask,
+                              unsigned viewIDCount) {
+  // Compute needed elements
+  for (unsigned adding = 0; adding < 2; adding++) {
+    uint32_t numElements = 0;
+    for (auto &E : inElements) {
+      for (uint32_t row = 0; row < E.rows; row++) {
+        for (uint32_t col = 0; col < E.cols; col++) {
+          bool bDynIndex = E.indexFlags & (1 << col);
+          if (row > 0 && bDynIndex)
+            continue;
+          if (adding) {
+            uint32_t componentIndex = (E.GetStartRow() + row) * 4 + E.GetStartCol() + col;
+            DxilSignatureAllocator::DummyElement NE(numElements);
+            NE.rows = bDynIndex ? E.GetRows() : 1;
+            if (mask.Get(componentIndex)) {
+              NE.rows *= viewIDCount;
+            }
+            NE.kind = E.kind;
+            NE.interpolation = E.interpolation;
+            NE.interpretation = E.interpretation;
+            outElements.push_back(NE);
+          }
+          numElements++;
+        }
+      }
+    }
+    if (!adding)
+      outElements.resize(numElements);
+  }
+}
+
+static bool CheckFit(ElementVec &elements) {
+  std::vector<DxilSignatureAllocator::PackElement*> packElements;
+  packElements.reserve(elements.size());
+  for (auto &E : elements)
+    packElements.push_back(&E);
+  DxilSignatureAllocator alloc(32);
+  alloc.PackOptimized(packElements, 0, 32);
+  for (auto &E : elements) {
+    if (!E.IsAllocated())
+      return false;
+  }
+  return true;
+}
+
+static bool MergeElements(const ElementVec &priorElements,
+                          ElementVec &inputElements,
+                          uint32_t &numVectors,
+                          unsigned &mismatchElementId) {
+  inputElements.reserve(std::max(priorElements.size(), inputElements.size()));
+  unsigned minElements = (unsigned)std::min(priorElements.size(), inputElements.size());
+  for (unsigned i = 0; i < minElements; i++) {
+    const DxilSignatureAllocator::DummyElement &priorEl = priorElements[i];
+    DxilSignatureAllocator::DummyElement &inputEl = inputElements[i];
+    // Verify elements match
+    if (priorEl.rows != inputEl.rows ||
+      priorEl.cols != inputEl.cols ||
+      priorEl.row != inputEl.row ||
+      priorEl.col != inputEl.col ||
+      priorEl.kind != inputEl.kind ||
+      priorEl.interpolation != inputEl.interpolation ||
+      priorEl.interpretation != inputEl.interpretation) {
+      mismatchElementId = inputEl.id;
+      return false;
+    }
+    // OR prior dynamic index flags into input element
+    inputEl.indexFlags |= priorEl.indexFlags;
+  }
+
+  // Add extra incoming elements if there are more
+  for (unsigned i = (unsigned)inputElements.size(); i < (unsigned)priorElements.size(); i++) {
+    inputElements.push_back(priorElements[i]);
+  }
+
+  // Update numVectors to max
+  for (unsigned i = 0; i < inputElements.size(); i++) {
+    DxilSignatureAllocator::DummyElement &inputEl = inputElements[i];
+    numVectors = std::max(numVectors, inputEl.row + inputEl.rows);
+  }
+  return true;
+}
+
+static void PropegateMask(const ComponentMask &priorMask,
+                          ElementVec &inputElements,
+                          ComponentMask &outMask,
+                          std::function<PSVComponentMask(unsigned)> getMask) {
+  // Iterate elements
+  for (auto &E : inputElements) {
+    for (unsigned row = 0; row < E.GetRows(); row++) {
+      for (unsigned col = 0; col < E.GetCols(); col++) {
+        uint32_t componentIndex = (E.GetStartRow() + row) * 4 + E.GetStartCol() + col;
+        // If bit set in priorMask
+        if (priorMask.Get(componentIndex)) {
+          // get mask of outputs affected by inputs and OR into outMask
+          outMask |= getMask(componentIndex);
+        }
+      }
+    }
+  }
+}
+
+class ViewIDValidator_impl : public hlsl::ViewIDValidator {
+  ComponentMask m_PriorOutputMask;
+  ComponentMask m_PriorPCMask;
+  ElementVec m_PriorOutputSignature;
+  ElementVec m_PriorPCSignature;
+  unsigned m_ViewIDCount;
+  unsigned m_GSRastStreamIndex;
+
+public:
+  ViewIDValidator_impl(unsigned viewIDCount, unsigned gsRastStreamIndex)
+    : m_PriorOutputMask(),
+      m_ViewIDCount(viewIDCount),
+      m_GSRastStreamIndex(gsRastStreamIndex)
+  {}
+  virtual ~ViewIDValidator_impl() {}
+  __override Result ValidateStage(const DxilPipelineStateValidation &PSV,
+                                  unsigned &mismatchElementId) {
+    switch (PSV.GetShaderKind()) {
+    case PSVShaderKind::Vertex: {
+      // Initialize mask with direct ViewID dependent outputs
+      ComponentMask mask(PSV.GetViewIDOutputMask(0));
+
+      // capture output signature
+      ElementVec outSig;
+      CopyElements( outSig, DXIL::SigPointKind::VSOut, PSV.GetSigOutputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetOutputElement0(i));
+                    });
+
+      // Copy mask to prior mask
+      m_PriorOutputMask = mask;
+
+      // Capture output signature for next stage
+      m_PriorOutputSignature = std::move(outSig);
+
+      break;
+    }
+    case PSVShaderKind::Hull: {
+      // Initialize mask with direct ViewID dependent outputs
+      ComponentMask outputMask(PSV.GetViewIDOutputMask(0));
+      ComponentMask pcMask(PSV.GetViewIDPCOutputMask());
+
+      // capture signatures
+      ElementVec inSig, outSig, pcSig;
+      CopyElements( inSig, DXIL::SigPointKind::HSCPIn, PSV.GetSigInputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetInputElement0(i));
+                    });
+      CopyElements( outSig, DXIL::SigPointKind::HSCPOut, PSV.GetSigOutputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetOutputElement0(i));
+                    });
+      CopyElements( pcSig, DXIL::SigPointKind::PCOut, PSV.GetSigPatchConstantElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetPatchConstantElement0(i));
+                    });
+
+      // Merge prior and input signatures, update prior mask size if necessary
+      if (!MergeElements(m_PriorOutputSignature, inSig, m_PriorOutputMask.NumVectors, mismatchElementId))
+        return Result::MismatchedSignatures;
+
+      // Create new version with ViewID elements from merged signature
+      ElementVec viewIDSig;
+      AddViewIDElements(viewIDSig, inSig, m_PriorOutputMask, m_ViewIDCount);
+
+      // Verify fit
+      if (!CheckFit(viewIDSig))
+        return Result::InsufficientSpace;
+
+      // Propegate prior mask through input-output dependencies
+      if (PSV.GetInputToOutputTable(0).IsValid()) {
+        PropegateMask(m_PriorOutputMask, inSig, outputMask,
+                      [&](unsigned i) -> PSVComponentMask { return PSV.GetInputToOutputTable(0).GetMaskForInput(i); });
+      }
+      if (PSV.GetInputToPCOutputTable().IsValid()) {
+        PropegateMask(m_PriorOutputMask, inSig, pcMask,
+                      [&](unsigned i) -> PSVComponentMask { return PSV.GetInputToPCOutputTable().GetMaskForInput(i); });
+      }
+
+      // Copy mask to prior mask
+      m_PriorOutputMask = outputMask;
+      m_PriorPCMask = pcMask;
+
+      // Capture output signature for next stage
+      m_PriorOutputSignature = std::move(outSig);
+      m_PriorPCSignature = std::move(pcSig);
+
+      break;
+    }
+    case PSVShaderKind::Domain: {
+      // Initialize mask with direct ViewID dependent outputs
+      ComponentMask mask(PSV.GetViewIDOutputMask(0));
+
+      // capture signatures
+      ElementVec inSig, pcSig, outSig;
+      CopyElements( inSig, DXIL::SigPointKind::DSCPIn, PSV.GetSigInputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetInputElement0(i));
+                    });
+      CopyElements( pcSig, DXIL::SigPointKind::DSCPIn, PSV.GetSigPatchConstantElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetPatchConstantElement0(i));
+                    });
+      CopyElements( outSig, DXIL::SigPointKind::DSOut, PSV.GetSigOutputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetOutputElement0(i));
+                    });
+
+      // Merge prior and input signatures, update prior mask size if necessary
+      if (!MergeElements(m_PriorOutputSignature, inSig, m_PriorOutputMask.NumVectors, mismatchElementId))
+        return Result::MismatchedSignatures;
+      if (!MergeElements(m_PriorPCSignature, pcSig, m_PriorPCMask.NumVectors, mismatchElementId))
+        return Result::MismatchedPCSignatures;
+
+      {
+        // Create new version with ViewID elements from merged signature
+        ElementVec viewIDSig;
+        AddViewIDElements(viewIDSig, inSig, m_PriorOutputMask, m_ViewIDCount);
+
+        // Verify fit
+        if (!CheckFit(viewIDSig))
+          return Result::InsufficientSpace;
+      }
+
+      {
+        // Create new version with ViewID elements from merged signature
+        ElementVec viewIDSig;
+        AddViewIDElements(viewIDSig, pcSig, m_PriorPCMask, m_ViewIDCount);
+
+        // Verify fit
+        if (!CheckFit(viewIDSig))
+          return Result::InsufficientPCSpace;
+      }
+
+      // Propegate prior mask through input-output dependencies
+      if (PSV.GetInputToOutputTable(0).IsValid()) {
+        PropegateMask(m_PriorOutputMask, inSig, mask,
+                      [&](unsigned i) -> PSVComponentMask { return PSV.GetInputToOutputTable(0).GetMaskForInput(i); });
+      }
+      if (PSV.GetPCInputToOutputTable().IsValid()) {
+        PropegateMask(m_PriorPCMask, pcSig, mask,
+                      [&](unsigned i) -> PSVComponentMask { return PSV.GetPCInputToOutputTable().GetMaskForInput(i); });
+      }
+
+      // Copy mask to prior mask
+      m_PriorOutputMask = mask;
+      m_PriorPCMask = ComponentMask();
+
+      // Capture output signature for next stage
+      m_PriorOutputSignature = std::move(outSig);
+      m_PriorPCSignature.clear();
+
+      break;
+    }
+    case PSVShaderKind::Geometry: {
+      // Initialize mask with direct ViewID dependent outputs
+      ComponentMask mask(PSV.GetViewIDOutputMask(m_GSRastStreamIndex));
+
+      // capture signatures
+      ElementVec inSig, outSig;
+      CopyElements( inSig, DXIL::SigPointKind::GSVIn, PSV.GetSigInputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetInputElement0(i));
+                    });
+      CopyElements( outSig, DXIL::SigPointKind::GSOut, PSV.GetSigOutputElements(), m_GSRastStreamIndex,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetOutputElement0(i));
+                    });
+
+      // Merge prior and input signatures, update prior mask size if necessary
+      if (!MergeElements(m_PriorOutputSignature, inSig, m_PriorOutputMask.NumVectors, mismatchElementId))
+        return Result::MismatchedSignatures;
+
+      // Create new version with ViewID elements from merged signature
+      ElementVec viewIDSig;
+      AddViewIDElements(viewIDSig, inSig, m_PriorOutputMask, m_ViewIDCount);
+
+      // Verify fit
+      if (!CheckFit(viewIDSig))
+        return Result::InsufficientSpace;
+
+      // Propegate prior mask through input-output dependencies
+      if (PSV.GetInputToOutputTable(0).IsValid()) {
+        PropegateMask(m_PriorOutputMask, inSig, mask,
+                      [&](unsigned i) -> PSVComponentMask { return PSV.GetInputToOutputTable(m_GSRastStreamIndex).GetMaskForInput(i); });
+      }
+
+      // Copy mask to prior mask
+      m_PriorOutputMask = mask;
+
+      // Capture output signature for next stage
+      m_PriorOutputSignature = std::move(outSig);
+
+      break;
+    }
+    case PSVShaderKind::Pixel: {
+      // QUESTION: Do we propegate to PS SV_Target output?
+
+      // capture signatures
+      ElementVec inSig;
+      CopyElements( inSig, DXIL::SigPointKind::PSIn, PSV.GetSigInputElements(), 0,
+                    [&](unsigned i) -> PSVSignatureElement {
+                      return PSV.GetSignatureElement(PSV.GetInputElement0(i));
+                    });
+
+      // Merge prior and input signatures, update prior mask size if necessary
+      if (!MergeElements(m_PriorOutputSignature, inSig, m_PriorOutputMask.NumVectors, mismatchElementId))
+        return Result::MismatchedSignatures;
+
+      // Create new version with ViewID elements from merged signature
+      ElementVec viewIDSig;
+      AddViewIDElements(viewIDSig, inSig, m_PriorOutputMask, m_ViewIDCount);
+
+      // Verify fit
+      if (!CheckFit(viewIDSig))
+        return Result::InsufficientSpace;
+
+      // Final stage, so clear output state.
+      m_PriorOutputMask = ComponentMask();
+      m_PriorOutputSignature.clear();
+
+      break;
+    }
+    case PSVShaderKind::Compute:
+    default:
+      return Result::InvalidUsage;
+    }
+
+    return Result::Success;
+  }
+};
+
+} // namespace anonymous
+
+std::unique_ptr<ViewIDValidator> NewViewIDValidator(unsigned viewIDCount, unsigned gsRastStreamIndex) {
+  return std::make_unique<ViewIDValidator_impl>(viewIDCount, gsRastStreamIndex);
+}
+
+} // namespace hlsl

+ 0 - 1
lib/HLSL/CMakeLists.txt

@@ -24,7 +24,6 @@ add_llvm_library(LLVMHLSL
   DxilShaderModel.cpp
   DxilShaderModel.cpp
   DxilSignature.cpp
   DxilSignature.cpp
   DxilSignatureElement.cpp
   DxilSignatureElement.cpp
-  DxilSigPoint.cpp
   DxilTypeSystem.cpp
   DxilTypeSystem.cpp
   DxilValidation.cpp
   DxilValidation.cpp
   DxcOptimizer.cpp
   DxcOptimizer.cpp

+ 1 - 1
lib/HLSL/ComputeViewIdState.cpp

@@ -885,7 +885,7 @@ void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSizeInUINT
   memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned));
   memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned));
 
 
   const ShaderModel *pSM = m_pModule->GetShaderModel();
   const ShaderModel *pSM = m_pModule->GetShaderModel();
-  m_bUsesViewId = m_pModule->m_ShaderFlags.GetUsesViewId();
+  m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
   unsigned ConsumedUINTs = 0;
   unsigned ConsumedUINTs = 0;
 
 
   IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
   IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);

+ 37 - 24
lib/HLSL/DxilContainerAssembler.cpp

@@ -388,31 +388,27 @@ private:
       E.ColsAndStart |= 0x40 | (SE.GetStartCol() << 4);
       E.ColsAndStart |= 0x40 | (SE.GetStartCol() << 4);
       E.StartRow = (uint8_t)SE.GetStartRow();
       E.StartRow = (uint8_t)SE.GetStartRow();
     }
     }
-    E.SemanticKind = (uint8_t)KindToSystemValue(SE.GetKind(), m_Module.GetTessellatorDomain());
+    E.SemanticKind = (uint8_t)SE.GetKind();
     E.ComponentType = (uint8_t)CompTypeToSigCompType(SE.GetCompType());
     E.ComponentType = (uint8_t)CompTypeToSigCompType(SE.GetCompType());
     E.InterpolationMode = (uint8_t)SE.GetInterpolationMode()->GetKind();
     E.InterpolationMode = (uint8_t)SE.GetInterpolationMode()->GetKind();
     DXASSERT_NOMSG(SE.GetOutputStream() < 4);
     DXASSERT_NOMSG(SE.GetOutputStream() < 4);
     E.DynamicMaskAndStream = (uint8_t)((SE.GetOutputStream() & 0x3) << 4);
     E.DynamicMaskAndStream = (uint8_t)((SE.GetOutputStream() & 0x3) << 4);
-
-    // TODO: Fill Dynamic Index Mask in!
     E.DynamicMaskAndStream |= (SE.GetDynIdxCompMask()) & 0xF;
     E.DynamicMaskAndStream |= (SE.GetDynIdxCompMask()) & 0xF;
   }
   }
 
 
-  const uint32_t *CopyViewIDState(const uint32_t *pSrc, const PSVComponentMasks &ViewIDMask, const PSVDependencyTable &IOTable) {
-    uint32_t InputScalars = *(pSrc++);
-    uint32_t OutputScalars = *(pSrc++);
+  const uint32_t *CopyViewIDState(const uint32_t *pSrc, uint32_t InputScalars, uint32_t OutputScalars, PSVComponentMask ViewIDMask, PSVDependencyTable IOTable) {
     unsigned MaskDwords = PSVComputeMaskDwordsFromVectors(PSVALIGN4(OutputScalars) / 4);
     unsigned MaskDwords = PSVComputeMaskDwordsFromVectors(PSVALIGN4(OutputScalars) / 4);
-    if (ViewIDMask.Masks) {
+    if (ViewIDMask.IsValid()) {
       DXASSERT_NOMSG(!IOTable.Table || ViewIDMask.NumVectors == IOTable.OutputVectors);
       DXASSERT_NOMSG(!IOTable.Table || ViewIDMask.NumVectors == IOTable.OutputVectors);
-      memcpy(ViewIDMask.Masks, pSrc, 4 * MaskDwords);
+      memcpy(ViewIDMask.Mask, pSrc, 4 * MaskDwords);
+      pSrc += MaskDwords;
     }
     }
-    pSrc += MaskDwords;
-    if (IOTable.Table && IOTable.InputVectors && IOTable.OutputVectors) {
+    if (IOTable.IsValid() && IOTable.InputVectors && IOTable.OutputVectors) {
       DXASSERT_NOMSG((InputScalars <= IOTable.InputVectors * 4) && (IOTable.InputVectors * 4 - InputScalars < 4));
       DXASSERT_NOMSG((InputScalars <= IOTable.InputVectors * 4) && (IOTable.InputVectors * 4 - InputScalars < 4));
       DXASSERT_NOMSG((OutputScalars <= IOTable.OutputVectors * 4) && (IOTable.OutputVectors * 4 - OutputScalars < 4));
       DXASSERT_NOMSG((OutputScalars <= IOTable.OutputVectors * 4) && (IOTable.OutputVectors * 4 - OutputScalars < 4));
       memcpy(IOTable.Table, pSrc, 4 * MaskDwords * InputScalars);
       memcpy(IOTable.Table, pSrc, 4 * MaskDwords * InputScalars);
+      pSrc += MaskDwords * InputScalars;
     }
     }
-    pSrc += MaskDwords * InputScalars;
     return pSrc;
     return pSrc;
   }
   }
 
 
@@ -427,12 +423,14 @@ public:
     if (m_PSVInitInfo.PSVVersion < 1 && (ValMajor > 1 || (ValMajor == 1 && ValMinor >= 1)))
     if (m_PSVInitInfo.PSVVersion < 1 && (ValMajor > 1 || (ValMajor == 1 && ValMinor >= 1)))
       m_PSVInitInfo.PSVVersion = 1;
       m_PSVInitInfo.PSVVersion = 1;
 
 
+    const ShaderModel *SM = m_Module.GetShaderModel();
     UINT uCBuffers = m_Module.GetCBuffers().size();
     UINT uCBuffers = m_Module.GetCBuffers().size();
     UINT uSamplers = m_Module.GetSamplers().size();
     UINT uSamplers = m_Module.GetSamplers().size();
     UINT uSRVs = m_Module.GetSRVs().size();
     UINT uSRVs = m_Module.GetSRVs().size();
     UINT uUAVs = m_Module.GetUAVs().size();
     UINT uUAVs = m_Module.GetUAVs().size();
     m_PSVInitInfo.ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs;
     m_PSVInitInfo.ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs;
     if (m_PSVInitInfo.PSVVersion > 0) {
     if (m_PSVInitInfo.PSVVersion > 0) {
+      m_PSVInitInfo.ShaderStage = (PSVShaderKind)SM->GetKind();
       // Copy Dxil Signatures
       // Copy Dxil Signatures
       m_StringBuffer.push_back('\0'); // For empty semantic name (system value)
       m_StringBuffer.push_back('\0'); // For empty semantic name (system value)
       m_PSVInitInfo.SigInputElements = m_Module.GetInputSignature().GetElements().size();
       m_PSVInitInfo.SigInputElements = m_Module.GetInputSignature().GetElements().size();
@@ -459,18 +457,22 @@ public:
       m_PSVInitInfo.SemanticIndexTable.Table = m_SemanticIndexBuffer.data();
       m_PSVInitInfo.SemanticIndexTable.Table = m_SemanticIndexBuffer.data();
       m_PSVInitInfo.SemanticIndexTable.Entries = m_SemanticIndexBuffer.size();
       m_PSVInitInfo.SemanticIndexTable.Entries = m_SemanticIndexBuffer.size();
       // Set up ViewID and signature dependency info
       // Set up ViewID and signature dependency info
-      m_PSVInitInfo.UsesViewID = (m_Module.m_ShaderFlags.GetFeatureInfo() & hlsl::ShaderFeatureInfo_ViewID) ? true : false;
-      m_PSVInitInfo.SigInputVectors = m_Module.GetInputSignature().NumVectorsUsed();
-      m_PSVInitInfo.SigOutputVectors = m_Module.GetOutputSignature().NumVectorsUsed();
-      m_PSVInitInfo.SigPCOutputVectors = m_PSVInitInfo.SigPCInputVectors = 0;
-      if (m_Module.GetShaderModel()->IsHS()) {
-        m_PSVInitInfo.SigPCOutputVectors = m_Module.GetPatchConstantSignature().NumVectorsUsed();
+      m_PSVInitInfo.UsesViewID = m_Module.m_ShaderFlags.GetViewID() ? true : false;
+      m_PSVInitInfo.SigInputVectors = m_Module.GetInputSignature().NumVectorsUsed(0);
+      for (unsigned streamIndex = 0; streamIndex < 4; streamIndex++) {
+        m_PSVInitInfo.SigOutputVectors[streamIndex] = m_Module.GetOutputSignature().NumVectorsUsed(streamIndex);
+      }
+      m_PSVInitInfo.SigPatchConstantVectors = m_PSVInitInfo.SigPatchConstantVectors = 0;
+      if (SM->IsHS()) {
+        m_PSVInitInfo.SigPatchConstantVectors = m_Module.GetPatchConstantSignature().NumVectorsUsed(0);
       }
       }
-      if (m_Module.GetShaderModel()->IsDS()) {
-        m_PSVInitInfo.SigPCInputVectors = m_Module.GetPatchConstantSignature().NumVectorsUsed();
+      if (SM->IsDS()) {
+        m_PSVInitInfo.SigPatchConstantVectors = m_Module.GetPatchConstantSignature().NumVectorsUsed(0);
       }
       }
     }
     }
-    m_PSV.InitNew(m_PSVInitInfo, nullptr, &m_PSVBufferSize);
+    if (!m_PSV.InitNew(m_PSVInitInfo, nullptr, &m_PSVBufferSize)) {
+      DXASSERT(false, "PSV InitNew failed computing size!");
+    }
   }
   }
   __override uint32_t size() const {
   __override uint32_t size() const {
     return m_PSVBufferSize;
     return m_PSVBufferSize;
@@ -478,7 +480,9 @@ public:
 
 
   __override void write(AbstractMemoryStream *pStream) {
   __override void write(AbstractMemoryStream *pStream) {
     m_PSVBuffer.resize(m_PSVBufferSize);
     m_PSVBuffer.resize(m_PSVBufferSize);
-    m_PSV.InitNew(m_PSVInitInfo, m_PSVBuffer.data(), &m_PSVBufferSize);
+    if (!m_PSV.InitNew(m_PSVInitInfo, m_PSVBuffer.data(), &m_PSVBufferSize)) {
+      DXASSERT(false, "PSV InitNew failed!");
+    }
     DXASSERT_NOMSG(m_PSVBuffer.size() == m_PSVBufferSize);
     DXASSERT_NOMSG(m_PSVBuffer.size() == m_PSVBufferSize);
 
 
     // Set DxilRuntimInfo
     // Set DxilRuntimInfo
@@ -650,11 +654,20 @@ public:
       auto &viewState = m_Module.GetViewIdState().GetSerialized();
       auto &viewState = m_Module.GetViewIdState().GetSerialized();
       if (!viewState.empty()) {
       if (!viewState.empty()) {
         const uint32_t *pSrc = viewState.data();
         const uint32_t *pSrc = viewState.data();
-        pSrc = CopyViewIDState(pSrc, m_PSV.GetViewIDOutputMasks(), m_PSV.GetInputToOutputTable());
+        const uint32_t InputScalars = *(pSrc++);
+        uint32_t OutputScalars[4];
+        for (unsigned streamIndex = 0; streamIndex < 4; streamIndex++) {
+          OutputScalars[streamIndex] = *(pSrc++);
+          pSrc = CopyViewIDState(pSrc, InputScalars, OutputScalars[streamIndex], m_PSV.GetViewIDOutputMask(streamIndex), m_PSV.GetInputToOutputTable(streamIndex));
+          if (!SM->IsGS())
+            break;
+        }
         if (m_Module.GetShaderModel()->IsHS()) {
         if (m_Module.GetShaderModel()->IsHS()) {
-          pSrc = CopyViewIDState(pSrc, m_PSV.GetViewIDPCOutputMasks(), m_PSV.GetInputToPCOutputTable());
+          const uint32_t PCScalars = *(pSrc++);
+          pSrc = CopyViewIDState(pSrc, InputScalars, PCScalars, m_PSV.GetViewIDPCOutputMask(), m_PSV.GetInputToPCOutputTable());
         } else if (m_Module.GetShaderModel()->IsDS()) {
         } else if (m_Module.GetShaderModel()->IsDS()) {
-          pSrc = CopyViewIDState(pSrc, PSVComponentMasks(), m_PSV.GetPCInputToOutputTable());
+          const uint32_t PCScalars = *(pSrc++);
+          pSrc = CopyViewIDState(pSrc, PCScalars, OutputScalars[0], PSVComponentMask(), m_PSV.GetPCInputToOutputTable());
         }
         }
         DXASSERT_NOMSG(viewState.data() + viewState.size() == pSrc);
         DXASSERT_NOMSG(viewState.data() + viewState.size() == pSrc);
       }
       }

+ 8 - 2
lib/HLSL/DxilModule.cpp

@@ -122,6 +122,7 @@ DxilModule::ShaderFlags::ShaderFlags():
 , m_bWaveOps(false)
 , m_bWaveOps(false)
 , m_bInt64Ops(false)
 , m_bInt64Ops(false)
 , m_bViewID(false)
 , m_bViewID(false)
+, m_bBarycentrics(false)
 , m_align0(0)
 , m_align0(0)
 , m_align1(0)
 , m_align1(0)
 {}
 {}
@@ -253,6 +254,7 @@ uint64_t DxilModule::ShaderFlags::GetFeatureInfo() const {
   Flags |= m_bLevel9ComparisonFiltering ? hlsl::ShaderFeatureInfo_LEVEL9ComparisonFiltering : 0;
   Flags |= m_bLevel9ComparisonFiltering ? hlsl::ShaderFeatureInfo_LEVEL9ComparisonFiltering : 0;
   Flags |= m_bUAVLoadAdditionalFormats ? hlsl::ShaderFeatureInfo_TypedUAVLoadAdditionalFormats : 0;
   Flags |= m_bUAVLoadAdditionalFormats ? hlsl::ShaderFeatureInfo_TypedUAVLoadAdditionalFormats : 0;
   Flags |= m_bViewID ? hlsl::ShaderFeatureInfo_ViewID : 0;
   Flags |= m_bViewID ? hlsl::ShaderFeatureInfo_ViewID : 0;
+  Flags |= m_bBarycentrics ? hlsl::ShaderFeatureInfo_Barycentrics : 0;
 
 
   return Flags;
   return Flags;
 }
 }
@@ -541,6 +543,7 @@ uint64_t DxilModule::ShaderFlags::GetShaderFlagsRawForCollection() {
   Flags.SetEnableRawAndStructuredBuffers(true);
   Flags.SetEnableRawAndStructuredBuffers(true);
   Flags.SetCSRawAndStructuredViaShader4X(true);
   Flags.SetCSRawAndStructuredViaShader4X(true);
   Flags.SetViewID(true);
   Flags.SetViewID(true);
+  Flags.SetBarycentrics(true);
   return Flags.GetShaderFlagsRaw();
   return Flags.GetShaderFlagsRaw();
 }
 }
 
 
@@ -996,11 +999,12 @@ void DxilModule::EmitDxilMetadata() {
   m_pMDHelper->EmitValidatorVersion(m_ValMajor, m_ValMinor);
   m_pMDHelper->EmitValidatorVersion(m_ValMajor, m_ValMinor);
   m_pMDHelper->EmitDxilShaderModel(m_pSM);
   m_pMDHelper->EmitDxilShaderModel(m_pSM);
 
 
+  MDTuple *pMDProperties = EmitDxilShaderProperties();
+
   MDTuple *pMDSignatures = m_pMDHelper->EmitDxilSignatures(*m_InputSignature, 
   MDTuple *pMDSignatures = m_pMDHelper->EmitDxilSignatures(*m_InputSignature, 
                                                            *m_OutputSignature,
                                                            *m_OutputSignature,
                                                            *m_PatchConstantSignature);
                                                            *m_PatchConstantSignature);
   MDTuple *pMDResources = EmitDxilResources();
   MDTuple *pMDResources = EmitDxilResources();
-  MDTuple *pMDProperties = EmitDxilShaderProperties();
   m_pMDHelper->EmitDxilTypeSystem(GetTypeSystem(), m_LLVMUsed);
   m_pMDHelper->EmitDxilTypeSystem(GetTypeSystem(), m_LLVMUsed);
   if (!m_pSM->IsCS() &&
   if (!m_pSM->IsCS() &&
       (m_ValMajor > 1 || (m_ValMajor == 1 && m_ValMinor >= 1))) {
       (m_ValMajor > 1 || (m_ValMajor == 1 && m_ValMinor >= 1))) {
@@ -1040,10 +1044,12 @@ void DxilModule::LoadDxilMetadata() {
   SetEntryFunction(pEntryFunc);
   SetEntryFunction(pEntryFunc);
   SetEntryFunctionName(EntryName);
   SetEntryFunctionName(EntryName);
 
 
+  LoadDxilShaderProperties(*pProperties);
+
   m_pMDHelper->LoadDxilSignatures(*pSignatures, *m_InputSignature,
   m_pMDHelper->LoadDxilSignatures(*pSignatures, *m_InputSignature,
                                   *m_OutputSignature, *m_PatchConstantSignature);
                                   *m_OutputSignature, *m_PatchConstantSignature);
   LoadDxilResources(*pResources);
   LoadDxilResources(*pResources);
-  LoadDxilShaderProperties(*pProperties);
+
   m_pMDHelper->LoadDxilTypeSystem(*m_pTypeSystem.get());
   m_pMDHelper->LoadDxilTypeSystem(*m_pTypeSystem.get());
 
 
   m_pMDHelper->LoadRootSignature(*m_RootSignature.get());
   m_pMDHelper->LoadRootSignature(*m_RootSignature.get());

+ 6 - 2
lib/HLSL/DxilSignature.cpp

@@ -92,10 +92,10 @@ bool DxilSignature::IsFullyAllocated() const {
   return true;
   return true;
 }
 }
 
 
-unsigned DxilSignature::NumVectorsUsed() const {
+unsigned DxilSignature::NumVectorsUsed(unsigned streamIndex) const {
   unsigned NumVectors = 0;
   unsigned NumVectors = 0;
   for (auto &SE : m_Elements) {
   for (auto &SE : m_Elements) {
-    if (SE->IsAllocated())
+    if (SE->IsAllocated() && SE->GetOutputStream() == streamIndex)
       NumVectors = std::max(NumVectors, (unsigned)SE->GetStartRow() + SE->GetRows());
       NumVectors = std::max(NumVectors, (unsigned)SE->GetStartRow() + SE->GetRows());
   }
   }
   return NumVectors;
   return NumVectors;
@@ -203,3 +203,7 @@ unsigned DxilSignature::PackElements(DXIL::PackingStrategy packing) {
 
 
 #include <algorithm>
 #include <algorithm>
 #include "dxc/HLSL/DxilSignatureAllocator.inl"
 #include "dxc/HLSL/DxilSignatureAllocator.inl"
+#include "dxc/HLSL/DxilSigPoint.inl"
+#include "dxc/HLSL/DxilPipelineStateValidation.h"
+#include <functional>
+#include "dxc/HLSL/ViewIDPipelineValidation.inl"

+ 6 - 4
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -1055,10 +1055,12 @@ TEST_F(ValidationTest, StreamIDOutOfBound) {
 
 
 TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
 TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
   RewriteAssemblyCheckMsg(
   RewriteAssemblyCheckMsg(
-      L"..\\CodeGenHLSL\\abs1.hlsl", "ps_6_0",
-      ", i8 0, i32 1, i8 4, i32 0, i8 0, null}",
-      ", i8 0, i32 1, i8 4, i32 0, i8 0, !19}\n!19 = !{i32 0, i32 1}", 
-      "Stream index (1) must between 0 and 0");
+    L"..\\CodeGenHLSL\\abs1.hlsl", "ps_6_0",
+    { ", i8 0, i32 1, i8 4, i32 0, i8 0, null}",
+      "?!dx.viewIdState ="},
+    { ", i8 0, i32 1, i8 4, i32 0, i8 0, !19}\n!19 = !{i32 0, i32 1}",
+      "!1012 =" },
+    "Stream index (1) must between 0 and 0");
 }
 }
 
 
 TEST_F(ValidationTest, TypedUAVStoreFullMask0) {
 TEST_F(ValidationTest, TypedUAVStoreFullMask0) {

+ 1 - 1
utils/hct/hctdb_instrhelp.py

@@ -1015,7 +1015,7 @@ if __name__ == "__main__":
             'tools/clang/lib/Sema/gen_intrin_main_tables_15.h',
             'tools/clang/lib/Sema/gen_intrin_main_tables_15.h',
             'include/dxc/HlslIntrinsicOp.h',
             'include/dxc/HlslIntrinsicOp.h',
             'tools/clang/tools/dxcompiler/dxcompilerobj.cpp',
             'tools/clang/tools/dxcompiler/dxcompilerobj.cpp',
-            'lib/HLSL/DxilSigPoint.cpp',
+            'include/dxc/HLSL/DxilSigPoint.inl',
             ]
             ]
         for relative_file_path in files:
         for relative_file_path in files:
             RunCodeTagUpdate(pj(hlsl_src_dir, relative_file_path))
             RunCodeTagUpdate(pj(hlsl_src_dir, relative_file_path))