Ver Fonte

Merge pull request #312 from tex3d/psv-work

Update ViewID for multiple streams and implement ViewID pipeline validation
Tex Riddell há 8 anos atrás
pai
commit
3e446c89d7

+ 27 - 18
include/dxc/HLSL/ComputeViewIdState.h

@@ -54,11 +54,11 @@ public:
   DxilViewIdState(DxilModule *pDxilModule);
 
   unsigned getNumInputSigScalars() const;
-  unsigned getNumOutputSigScalars() const;
+  unsigned getNumOutputSigScalars(unsigned StreamId) const;
   unsigned getNumPCSigScalars() const;
-  const OutputsDependentOnViewIdType &getOutputsDependentOnViewId() const;
+  const OutputsDependentOnViewIdType &getOutputsDependentOnViewId(unsigned StreamId) const;
   const OutputsDependentOnViewIdType &getPCOutputsDependentOnViewId() const;
-  const InputsContributingToOutputType &getInputsContributingToOutputs() const;
+  const InputsContributingToOutputType &getInputsContributingToOutputs(unsigned StreamId) const;
   const InputsContributingToOutputType &getInputsContributingToPCOutputs() const;
   const InputsContributingToOutputType &getPCInputsContributingToOutputs() const;
 
@@ -66,14 +66,18 @@ public:
   void Serialize();
   const std::vector<unsigned> &GetSerialized();
   const std::vector<unsigned> &GetSerialized() const;   // returns previously serialized data
-  void Deserialize(const unsigned *pData, unsigned DataSize);
+  void Deserialize(const unsigned *pData, unsigned DataSizeInUINTs);
   void PrintSets(llvm::raw_ostream &OS);
 
 private:
+  static const unsigned kNumStreams = 4;
+
   DxilModule *m_pModule;
 
+  bool m_bUsesViewId = false;
+
   unsigned m_NumInputSigScalars  = 0;
-  unsigned m_NumOutputSigScalars = 0;
+  unsigned m_NumOutputSigScalars[kNumStreams] = {0,0,0,0};
   unsigned m_NumPCSigScalars     = 0;
 
   // Dynamically indexed components of signature elements.
@@ -83,11 +87,11 @@ private:
   DynamicallyIndexedElemsType m_PCSigDynIdxElems;
 
   // Set of scalar outputs dependent on ViewID.
-  OutputsDependentOnViewIdType m_OutputsDependentOnViewId;
+  OutputsDependentOnViewIdType m_OutputsDependentOnViewId[kNumStreams];
   OutputsDependentOnViewIdType m_PCOutputsDependentOnViewId;
 
   // Set of scalar inputs contributing to computation of scalar outputs.
-  InputsContributingToOutputType m_InputsContributingToOutputs;
+  InputsContributingToOutputType m_InputsContributingToOutputs[kNumStreams];
   InputsContributingToOutputType m_InputsContributingToPCOutputs; // HS PC only.
   InputsContributingToOutputType m_PCInputsContributingToOutputs; // DS only.
 
@@ -101,7 +105,7 @@ private:
     // Outputs to analyze.
     InstructionSetType Outputs;
     // Contributing instructions per output.
-    std::unordered_map<unsigned, InstructionSetType> ContributingInstructions;
+    std::unordered_map<unsigned, InstructionSetType> ContributingInstructions[kNumStreams];
 
     void Clear();
   };
@@ -130,7 +134,7 @@ private:
   std::vector<unsigned> m_SerializedState;
 
   void Clear();
-  void DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned &MaxSigLoc);
+  void DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned *pMaxSigLoc, unsigned NumStreams);
   void ComputeReachableFunctionsRec(llvm::CallGraph &CG, llvm::CallGraphNode *pNode, FunctionSetType &FuncSet);
   void AnalyzeFunctions(EntryInfo &Entry);
   void CollectValuesContributingToOutputs(EntryInfo &Entry);
@@ -145,18 +149,23 @@ private:
   const ValueSetType &CollectStores(llvm::Value *pValue);
   void CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited);
   void UpdateDynamicIndexUsageState() const;
-  void CreateViewIdSets(EntryInfo &Entry, OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+  void CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions,
+                        OutputsDependentOnViewIdType &OutputsDependentOnViewId,
                         InputsContributingToOutputType &InputsContributingToOutputs, bool bPC);
 
   void UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig, const DynamicallyIndexedElemsType &DynIdxElems) const;
-  void Serialize1(unsigned NumInputs, unsigned NumOutputs,
-                  const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
-                  const InputsContributingToOutputType &InputsContributingToOutputs,
-                  unsigned *&pData);
-  unsigned Deserialize1(const unsigned *pData, unsigned DataSize,
-                        unsigned &NumInputs, unsigned &NumOutputs,
-                        OutputsDependentOnViewIdType &OutputsDependentOnViewId,
-                        InputsContributingToOutputType &InputsContributingToOutputs);
+  void SerializeOutputsDependentOnViewId(unsigned NumOutputs, 
+                                         const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                         unsigned *&pData);
+  void SerializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
+                                           const InputsContributingToOutputType &InputsContributingToOutputs,
+                                           unsigned *&pData);
+  unsigned DeserializeOutputsDependentOnViewId(unsigned NumOutputs, 
+                                               OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                               const unsigned *pData, unsigned DataSize);
+  unsigned DeserializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
+                                                 InputsContributingToOutputType &InputsContributingToOutputs,
+                                                 const unsigned *pData, unsigned DataSize);
   unsigned GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const;
 
   void PrintOutputsDependentOnViewId(llvm::raw_ostream &OS,

+ 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_Int64Ops = 0x8000;
 static const uint64_t ShaderFeatureInfo_ViewID = 0x10000;
+static const uint64_t ShaderFeatureInfo_Barycentrics = 0x20000;
 
 static const unsigned ShaderFeatureInfoCount = 16;
 

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

@@ -168,6 +168,8 @@ public:
 
     uint64_t GetFeatureInfo() const;
     bool GetWaveOps() const { return m_bWaveOps; }
+    bool GetViewID() const { return m_bViewID; }
+    bool GetBarycentrics() const { return m_bBarycentrics; }
     void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
     void SetROVs(bool flag) { m_bROVS = flag; }
     void SetWaveOps(bool flag) { m_bWaveOps = flag; }
@@ -181,6 +183,7 @@ public:
     void Set64UAVs(bool flag) { m_b64UAVs = flag; }
     void SetUAVsAtEveryStage(bool flag) { m_UAVsAtEveryStage = 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)
     uint64_t GetShaderFlagsRaw() const;
@@ -215,8 +218,9 @@ public:
     unsigned m_bWaveOps :1;           // SHADER_FEATURE_WAVE_OPS
     unsigned m_bInt64Ops :1;          // SHADER_FEATURE_INT64_OPS
     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.
   };
 

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

@@ -14,6 +14,7 @@
 
 #include <stdint.h>
 #include <string.h>
+#include <memory>
 
 // 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; }
@@ -55,8 +56,21 @@ struct PSVRuntimeInfo0
   uint32_t MinimumExpectedWaveLaneCount;  // minimum lane count required, 0 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
 {
+  uint8_t ShaderStage;              // PSVShaderKind
   uint8_t UsesViewID;
 
   // PSVSignatureElement counts
@@ -66,9 +80,9 @@ struct PSVRuntimeInfo1 : public PSVRuntimeInfo0
 
   // Number of packed vectors per signature
   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
@@ -99,33 +113,36 @@ struct PSVResourceBindInfo0
 // PSVResourceBindInfo1 would derive and extend
 
 // Helpers for output dependencies (ViewID and Input-Output tables)
-struct PSVComponentMasks {
-  uint32_t *Masks;
+struct PSVComponentMask {
+  uint32_t *Mask;
   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)
   {}
-  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) {
-      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) {
-    _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) {
-    _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 {
@@ -133,16 +150,18 @@ struct PSVDependencyTable {
   uint32_t InputVectors;
   uint32_t OutputVectors;
   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)
   : Table(pTable),
     InputVectors(inputVectors),
     OutputVectors(outputVectors)
   {}
-  PSVComponentMasks GetMasksForInput(uint32_t inputComponentIndex) {
+  PSVComponentMask GetMaskForInput(uint32_t inputComponentIndex) {
     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
@@ -181,6 +200,40 @@ struct PSVSemanticIndexes {
   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
 {
   uint32_t SemanticName;          // Offset into PSVStringTable
@@ -188,7 +241,7 @@ struct PSVSignatureElement0
   uint8_t Rows;                   // Number of rows this element occupies
   uint8_t StartRow;               // Starting row of packing location if 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 InterpolationMode;      // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
   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); }
   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); }
-  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 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; }
@@ -224,6 +277,7 @@ struct PSVInitInfo
   PSVInitInfo(uint32_t psvVersion)
     : PSVVersion(psvVersion),
     ResourceCount(0),
+    ShaderStage(PSVShaderKind::Invalid),
     StringTable(),
     SemanticIndexTable(),
     UsesViewID(0),
@@ -231,12 +285,11 @@ struct PSVInitInfo
     SigOutputElements(0),
     SigPatchConstantElements(0),
     SigInputVectors(0),
-    SigOutputVectors(0),
-    SigPCOutputVectors(0),
-    SigPCInputVectors(0)
+    SigPatchConstantVectors(0)
   {}
   uint32_t PSVVersion;
   uint32_t ResourceCount;
+  PSVShaderKind ShaderStage;
   PSVStringTable StringTable;
   PSVSemanticIndexTable SemanticIndexTable;
   uint8_t UsesViewID;
@@ -244,9 +297,8 @@ struct PSVInitInfo
   uint8_t SigOutputElements;
   uint8_t SigPatchConstantElements;
   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
@@ -263,8 +315,8 @@ class DxilPipelineStateValidation
   void* m_pSigInputElements;
   void* m_pSigOutputElements;
   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_pInputToPCOutputTable;
   uint32_t* m_pPCInputToOutputTable;
@@ -283,8 +335,8 @@ public:
     m_pSigInputElements(nullptr),
     m_pSigOutputElements(nullptr),
     m_pSigPatchConstantElements(nullptr),
-    m_pViewIDOutputMasks(nullptr),
-    m_pViewIDPCOutputMasks(nullptr),
+    m_pViewIDOutputMask(nullptr),
+    m_pViewIDPCOutputMask(nullptr),
     m_pInputToOutputTable(nullptr),
     m_pInputToPCOutputTable(nullptr),
     m_pPCInputToOutputTable(nullptr)
@@ -310,20 +362,23 @@ public:
   //      { PSVSignatureElementN structure } * SigInputElements
   //      { PSVSignatureElementN structure } * SigOutputElements
   //      { 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
-  //    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
   // returns true if no errors occurred.
   bool InitFromPSV0(const void* pBits, uint32_t size) {
@@ -399,38 +454,46 @@ public:
 
       // ViewID dependencies
       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;
-          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
-      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;
         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;
         m_pPCInputToOutputTable = (uint32_t*)pCurBits;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
       }
     }
     return true;
@@ -475,20 +538,26 @@ public:
       size += m_uPSVSignatureElementSize * initInfo.SigPatchConstantElements;
 
       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
     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->SigPatchConstantElements = initInfo.SigPatchConstantElements;
       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
       m_StringTable.Size = PSVALIGN4(initInfo.StringTable.Size);
@@ -568,39 +637,47 @@ public:
 
       // ViewID dependencies
       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
-      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;
-        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;
-        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPCInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors);
+        pCurBits += PSVComputeInputOutputTableSize(m_pPSVRuntimeInfo1->SigPatchConstantVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
       }
     }
 
     return true;
   }
 
-  PSVRuntimeInfo0* GetPSVRuntimeInfo0() {
+  PSVRuntimeInfo0* GetPSVRuntimeInfo0() const {
     return m_pPSVRuntimeInfo0;
   }
 
-  PSVRuntimeInfo1* GetPSVRuntimeInfo1() {
+  PSVRuntimeInfo1* GetPSVRuntimeInfo1() const {
     return m_pPSVRuntimeInfo1;
   }
 
@@ -608,7 +685,7 @@ public:
     return m_uResourceCount;
   }
 
-  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) {
+  PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) const {
     if (index < m_uResourceCount && m_pPSVResourceBindInfo &&
         sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize) {
       return (PSVResourceBindInfo0*)((uint8_t*)m_pPSVResourceBindInfo +
@@ -617,8 +694,8 @@ public:
     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
   uint32_t GetSigInputElements() const {
@@ -636,7 +713,7 @@ public:
       return m_pPSVRuntimeInfo1->SigPatchConstantElements;
     return 0;
   }
-  PSVSignatureElement0* GetInputElement0(uint32_t index) {
+  PSVSignatureElement0* GetInputElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigInputElements &&
         index < m_pPSVRuntimeInfo1->SigInputElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -645,7 +722,7 @@ public:
     }
     return nullptr;
   }
-  PSVSignatureElement0* GetOutputElement0(uint32_t index) {
+  PSVSignatureElement0* GetOutputElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigOutputElements &&
         index < m_pPSVRuntimeInfo1->SigOutputElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -654,7 +731,7 @@ public:
     }
     return nullptr;
   }
-  PSVSignatureElement0* GetPatchConstantElement0(uint32_t index) {
+  PSVSignatureElement0* GetPatchConstantElement0(uint32_t index) const {
     if (m_pPSVRuntimeInfo1 && m_pSigPatchConstantElements &&
         index < m_pPSVRuntimeInfo1->SigPatchConstantElements &&
         sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize) {
@@ -664,42 +741,76 @@ public:
     return nullptr;
   }
   // More convenient wrapper:
-  PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) {
+  PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) const {
     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
-  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
-  PSVDependencyTable GetInputToOutputTable() {
+  PSVDependencyTable GetInputToOutputTable(unsigned streamIndex = 0) const {
     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();
   }
-  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();
   }
-  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();
   }
 };
 
+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__

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

@@ -11,7 +11,6 @@
 
 #pragma once
 
-#include "llvm/ADT/StringRef.h"
 #include "DxilConstants.h"
 
 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.                 //
 // This file is distributed under the University of Illinois Open Source     //
 // License. See LICENSE.TXT for details.                                     //
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "dxc/HLSL/DxilSigPoint.h"
-#include "dxc/Support/Global.h"
-
-#include <string>
-
-using std::string;
-
 /* <py>
 import hctdb_instrhelp
 </py> */

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

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

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

@@ -42,12 +42,14 @@ public:
     DXIL::SemanticKind kind;
     DXIL::InterpolationMode interpolation;
     DXIL::SemanticInterpretationKind interpretation;
+    uint32_t indexFlags;
 
   public:
     DummyElement(uint32_t index = 0) : id(index), rows(1), cols(1), row((uint32_t)-1), col((uint32_t)-1),
       kind(DXIL::SemanticKind::Arbitrary),
       interpolation(DXIL::InterpolationMode::Undefined),
-      interpretation(DXIL::SemanticInterpretationKind::Arb)
+      interpretation(DXIL::SemanticInterpretationKind::Arb),
+      indexFlags(0)
     {}
     __override ~DummyElement() {}
     __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
   DxilSignature.cpp
   DxilSignatureElement.cpp
-  DxilSigPoint.cpp
   DxilTypeSystem.cpp
   DxilValidation.cpp
   DxcOptimizer.cpp

+ 213 - 106
lib/HLSL/ComputeViewIdState.cpp

@@ -40,22 +40,24 @@ using std::unordered_map;
 
 
 DxilViewIdState::DxilViewIdState(DxilModule *pDxilModule) : m_pModule(pDxilModule) {}
-unsigned DxilViewIdState::getNumInputSigScalars() const   { return m_NumInputSigScalars; }
-unsigned DxilViewIdState::getNumOutputSigScalars() const  { return m_NumOutputSigScalars; }
-unsigned DxilViewIdState::getNumPCSigScalars() const      { return m_NumPCSigScalars; }
-const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getOutputsDependentOnViewId() const      { return m_OutputsDependentOnViewId; }
-const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getPCOutputsDependentOnViewId() const    { return m_PCOutputsDependentOnViewId; }
-const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToOutputs() const   { return m_InputsContributingToOutputs; }
-const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToPCOutputs() const { return m_InputsContributingToPCOutputs; }
-const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getPCInputsContributingToOutputs() const { return m_PCInputsContributingToOutputs; }
+unsigned DxilViewIdState::getNumInputSigScalars() const                   { return m_NumInputSigScalars; }
+unsigned DxilViewIdState::getNumOutputSigScalars(unsigned StreamId) const { return m_NumOutputSigScalars[StreamId]; }
+unsigned DxilViewIdState::getNumPCSigScalars() const                      { return m_NumPCSigScalars; }
+const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getOutputsDependentOnViewId(unsigned StreamId) const    { return m_OutputsDependentOnViewId[StreamId]; }
+const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getPCOutputsDependentOnViewId() const                   { return m_PCOutputsDependentOnViewId; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToOutputs(unsigned StreamId) const { return m_InputsContributingToOutputs[StreamId]; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToPCOutputs() const                { return m_InputsContributingToPCOutputs; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getPCInputsContributingToOutputs() const                { return m_PCInputsContributingToOutputs; }
 
 void DxilViewIdState::Compute() {
   Clear();
 
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+
   // 1. Traverse signature MD to determine max packed location.
-  DetermineMaxPackedLocation(m_pModule->GetInputSignature(), m_NumInputSigScalars);
-  DetermineMaxPackedLocation(m_pModule->GetOutputSignature(), m_NumOutputSigScalars);
-  DetermineMaxPackedLocation(m_pModule->GetPatchConstantSignature(), m_NumPCSigScalars);
+  DetermineMaxPackedLocation(m_pModule->GetInputSignature(), &m_NumInputSigScalars, 1);
+  DetermineMaxPackedLocation(m_pModule->GetOutputSignature(), &m_NumOutputSigScalars[0], pSM->IsGS() ? kNumStreams : 1);
+  DetermineMaxPackedLocation(m_pModule->GetPatchConstantSignature(), &m_NumPCSigScalars, 1);
 
   // 2. Collect sets of functions reachable from main and pc entries.
   CallGraphAnalysis CGA;
@@ -76,12 +78,19 @@ void DxilViewIdState::Compute() {
   CollectValuesContributingToOutputs(m_PCEntry);
 
   // 5. Construct dependency sets.
-  const ShaderModel *pSM = m_pModule->GetShaderModel();
-  CreateViewIdSets(m_Entry, m_OutputsDependentOnViewId, m_InputsContributingToOutputs, false);
+  for (unsigned StreamId = 0; StreamId < kNumStreams; StreamId++) {
+    CreateViewIdSets(m_Entry.ContributingInstructions[StreamId],
+                     m_OutputsDependentOnViewId[StreamId],
+                     m_InputsContributingToOutputs[StreamId], false);
+  }
   if (pSM->IsHS()) {
-    CreateViewIdSets(m_PCEntry, m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs, true);
+    CreateViewIdSets(m_PCEntry.ContributingInstructions[0],
+                     m_PCOutputsDependentOnViewId,
+                     m_InputsContributingToPCOutputs, true);
   } else if (pSM->IsDS()) {
-    CreateViewIdSets(m_PCEntry, m_OutputsDependentOnViewId, m_PCInputsContributingToOutputs, true);
+    CreateViewIdSets(m_PCEntry.ContributingInstructions[0],
+                     m_OutputsDependentOnViewId[0],
+                     m_PCInputsContributingToOutputs, true);
   }
 
   // 6. Update dynamically indexed input/output component masks.
@@ -95,15 +104,38 @@ void DxilViewIdState::Compute() {
 void DxilViewIdState::PrintSets(llvm::raw_ostream &OS) {
   const ShaderModel *pSM = m_pModule->GetShaderModel();
   OS << "ViewId state: \n";
-  OS << "Number of inputs: " << m_NumInputSigScalars  << 
-               ", outputs: " << m_NumOutputSigScalars << 
-            ", patchconst: " << m_NumPCSigScalars     << "\n";
-  PrintOutputsDependentOnViewId(OS, "Outputs", m_NumOutputSigScalars, m_OutputsDependentOnViewId);
+
+  if (!pSM->IsGS()) {
+    OS << "Number of inputs: " << m_NumInputSigScalars     << 
+                 ", outputs: " << m_NumOutputSigScalars[0] << 
+              ", patchconst: " << m_NumPCSigScalars        << "\n";
+  } else {
+    OS << "Number of inputs: "   << m_NumInputSigScalars     << 
+                 ", outputs: { " << m_NumOutputSigScalars[0] << ", " << m_NumOutputSigScalars[1] << ", " <<
+                                    m_NumOutputSigScalars[2] << ", " << m_NumOutputSigScalars[3] << " }" <<
+              ", patchconst: "   << m_NumPCSigScalars        << "\n";
+  }
+
+  if (!pSM->IsGS()) {
+    PrintOutputsDependentOnViewId(OS, "Outputs", m_NumOutputSigScalars[0], m_OutputsDependentOnViewId[0]);
+  } else {
+    PrintOutputsDependentOnViewId(OS, "Outputs for Stream0", m_NumOutputSigScalars[0], m_OutputsDependentOnViewId[0]);
+    PrintOutputsDependentOnViewId(OS, "Outputs for Stream1", m_NumOutputSigScalars[1], m_OutputsDependentOnViewId[1]);
+    PrintOutputsDependentOnViewId(OS, "Outputs for Stream2", m_NumOutputSigScalars[2], m_OutputsDependentOnViewId[2]);
+    PrintOutputsDependentOnViewId(OS, "Outputs for Stream3", m_NumOutputSigScalars[3], m_OutputsDependentOnViewId[3]);
+  }
   if (pSM->IsHS()) {
     PrintOutputsDependentOnViewId(OS, "PCOutputs", m_NumPCSigScalars, m_PCOutputsDependentOnViewId);
   }
 
-  PrintInputsContributingToOutputs(OS, "Inputs", "Outputs", m_InputsContributingToOutputs);
+  if (!pSM->IsGS()) {
+    PrintInputsContributingToOutputs(OS, "Inputs", "Outputs", m_InputsContributingToOutputs[0]);
+  } else {
+    PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream0", m_InputsContributingToOutputs[0]);
+    PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream1", m_InputsContributingToOutputs[1]);
+    PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream2", m_InputsContributingToOutputs[2]);
+    PrintInputsContributingToOutputs(OS, "Inputs", "Outputs for Stream3", m_InputsContributingToOutputs[3]);
+  }
   if (pSM->IsHS()) {
     PrintInputsContributingToOutputs(OS, "Inputs", "PCOutputs", m_InputsContributingToPCOutputs);
   } else if (pSM->IsDS()) {
@@ -148,15 +180,18 @@ void DxilViewIdState::PrintInputsContributingToOutputs(llvm::raw_ostream &OS,
 }
 
 void DxilViewIdState::Clear() {
+  m_bUsesViewId = false;
   m_NumInputSigScalars  = 0;
-  m_NumOutputSigScalars = 0;
+  for (unsigned i = 0; i < kNumStreams; i++) {
+    m_NumOutputSigScalars[i] = 0;
+    m_OutputsDependentOnViewId[i].reset();
+    m_InputsContributingToOutputs[i].clear();
+  }
   m_NumPCSigScalars     = 0;
   m_InpSigDynIdxElems.clear();
   m_OutSigDynIdxElems.clear();
   m_PCSigDynIdxElems.clear();
-  m_OutputsDependentOnViewId.reset();
   m_PCOutputsDependentOnViewId.reset();
-  m_InputsContributingToOutputs.clear();
   m_InputsContributingToPCOutputs.clear();
   m_PCInputsContributingToOutputs.clear();
   m_Entry.Clear();
@@ -170,7 +205,8 @@ void DxilViewIdState::EntryInfo::Clear() {
   pEntryFunc = nullptr;
   Functions.clear();
   Outputs.clear();
-  ContributingInstructions.clear();
+  for (unsigned i = 0; i < kNumStreams; i++)
+    ContributingInstructions[i].clear();
 }
 
 void DxilViewIdState::FuncInfo::Clear() {
@@ -179,15 +215,22 @@ void DxilViewIdState::FuncInfo::Clear() {
   pDomTree.reset();
 }
 
-void DxilViewIdState::DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned &MaxSigLoc) {
+void DxilViewIdState::DetermineMaxPackedLocation(DxilSignature &DxilSig,
+                                                 unsigned *pMaxSigLoc,
+                                                 unsigned NumStreams) {
   if (&DxilSig == nullptr) return;
+  DXASSERT_NOMSG(NumStreams == 1 || NumStreams == kNumStreams);
+
+  for (unsigned i = 0; i < NumStreams; i++) {
+    pMaxSigLoc[i] = 0;
+  }
 
-  MaxSigLoc = 0;
   for (auto &E : DxilSig.GetElements()) {
     if (E->GetStartRow() == Semantic::kUndefinedRow) continue;
 
+    unsigned StreamId = E->GetOutputStream();
     unsigned endLoc = GetLinearIndex(*E, E->GetRows() - 1, E->GetCols() - 1);
-    MaxSigLoc = std::max(MaxSigLoc, endLoc + 1);
+    pMaxSigLoc[StreamId] = std::max(pMaxSigLoc[StreamId], endLoc + 1);
     E->GetCols();
   }
 }
@@ -338,6 +381,8 @@ void DxilViewIdState::CollectValuesContributingToOutputs(EntryInfo &Entry) {
     if (!SigElem.IsAllocated())
       continue;
 
+    unsigned StreamId = SigElem.GetOutputStream();
+
     if (startRow != Semantic::kUndefinedRow) {
       endRow = startRow;
     } else {
@@ -350,7 +395,7 @@ void DxilViewIdState::CollectValuesContributingToOutputs(EntryInfo &Entry) {
     if (startRow == endRow) {
       // Scalar or indexable with known index.
       unsigned index = GetLinearIndex(SigElem, startRow, col);
-      InstructionSetType &ContributingInstructions = Entry.ContributingInstructions[index];
+      InstructionSetType &ContributingInstructions = Entry.ContributingInstructions[StreamId][index];
       CollectValuesContributingToOutputRec(Entry, pContributingValue, ContributingInstructions);
     } else {
       // Dynamically indexed output.
@@ -359,7 +404,7 @@ void DxilViewIdState::CollectValuesContributingToOutputs(EntryInfo &Entry) {
 
       for (int row = startRow; row <= endRow; row++) {
         unsigned index = GetLinearIndex(SigElem, row, col);
-        Entry.ContributingInstructions[index].insert(ContributingInstructions.begin(), ContributingInstructions.end());
+        Entry.ContributingInstructions[StreamId][index].insert(ContributingInstructions.begin(), ContributingInstructions.end());
       }
     }
   }
@@ -609,18 +654,18 @@ void DxilViewIdState::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores
   }
 }
 
-void DxilViewIdState::CreateViewIdSets(EntryInfo &Entry, 
+void DxilViewIdState::CreateViewIdSets(const std::unordered_map<unsigned, InstructionSetType> &ContributingInstructions, 
                                        OutputsDependentOnViewIdType &OutputsDependentOnViewId,
                                        InputsContributingToOutputType &InputsContributingToOutputs,
                                        bool bPC) {
   const ShaderModel *pSM = m_pModule->GetShaderModel();
 
-  for (auto &itOut : Entry.ContributingInstructions) {
+  for (auto &itOut : ContributingInstructions) {
     unsigned outIdx = itOut.first;
-    InstructionSetType &ContributingInstrunction = itOut.second;
-    for (Instruction *pInst : ContributingInstrunction) {
+    for (Instruction *pInst : itOut.second) {
       // Set output dependence on ViewId.
       if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
+        m_bUsesViewId = true;
         OutputsDependentOnViewId[outIdx] = true;
         continue;
       }
@@ -681,10 +726,10 @@ void DxilViewIdState::CreateViewIdSets(EntryInfo &Entry,
             // that is the output value of the HS main (control-point) function.
             // Transitively update this (patch-constant) output dependence on main (control-point) output.
             DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOutputsDependentOnViewId);
-            OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[index];
+            OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[0][index];
 
-            const auto it = m_InputsContributingToOutputs.find(index);
-            if (it != m_InputsContributingToOutputs.end()) {
+            const auto it = m_InputsContributingToOutputs[0].find(index);
+            if (it != m_InputsContributingToOutputs[0].end()) {
               const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
               ContributingInputs.insert(LoadOutputCPInputsContributingToOutputs.begin(),
                                         LoadOutputCPInputsContributingToOutputs.end());
@@ -699,6 +744,7 @@ void DxilViewIdState::CreateViewIdSets(EntryInfo &Entry,
 unsigned DxilViewIdState::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
   DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
   unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
+  DXASSERT_NOMSG(idx < kMaxSigScalars);
   return idx;
 }
 
@@ -723,57 +769,84 @@ static unsigned RoundUpToUINT(unsigned x) {
 }
 
 void DxilViewIdState::Serialize() {
-  if (!m_SerializedState.empty())
-    return;
-
   const ShaderModel *pSM = m_pModule->GetShaderModel();
-  unsigned NumOutUINTs = RoundUpToUINT(m_NumOutputSigScalars);
-  unsigned NumPCUINTs = RoundUpToUINT(m_NumPCSigScalars);
-  unsigned Size1 = 2 + NumOutUINTs * (1 + m_NumInputSigScalars);
-  unsigned Size2 = 0;
-  if (pSM->IsHS()) {
-    Size2 = 2 + NumPCUINTs * (1 + m_NumInputSigScalars);
-  } else if (pSM->IsDS()) {
-    Size2 = 2 + NumOutUINTs * (1 + m_NumPCSigScalars);
+  m_SerializedState.clear();
+
+  // Compute serialized state size in UINTs.
+  unsigned NumInputs = getNumInputSigScalars();
+  unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
+  unsigned Size = 0;
+  Size += 1;  // #Inputs.
+  for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
+    Size += 1;  // #Outputs for stream StreamId.
+    unsigned NumOutputs = getNumOutputSigScalars(StreamId);
+    unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
+    if (m_bUsesViewId) {
+      Size += NumOutUINTs;  // m_OutputsDependentOnViewId[StreamId]
+    }
+    Size += NumInputs * NumOutUINTs;  // m_InputsContributingToOutputs[StreamId]
+  }
+  if (pSM->IsHS() || pSM->IsDS()) {
+    Size += 1;  // #PatchConstant.
+    unsigned NumPCs = getNumPCSigScalars();
+    unsigned NumPCUINTs = RoundUpToUINT(NumPCs);
+    if (pSM->IsHS()) {
+      if (m_bUsesViewId) {
+        Size += NumPCUINTs;  // m_PCOutputsDependentOnViewId
+      }
+      Size += NumInputs * NumPCUINTs; // m_InputsContributingToPCOutputs
+    } else {
+      unsigned NumOutputs = getNumOutputSigScalars(0);
+      unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
+      Size += NumPCs * NumOutUINTs;   // m_PCInputsContributingToOutputs
+    }
   }
-  unsigned Size = Size1 + Size2;
 
   m_SerializedState.resize(Size);
   std::fill(m_SerializedState.begin(), m_SerializedState.end(), 0u);
 
+  // Serialize ViewId state.
   unsigned *pData = &m_SerializedState[0];
-  Serialize1(m_NumInputSigScalars, m_NumOutputSigScalars,
-             m_OutputsDependentOnViewId, m_InputsContributingToOutputs, pData);
-  DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size1));
-
-  if (pSM->IsHS()) {
-    Serialize1(m_NumInputSigScalars, m_NumPCSigScalars,
-               m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs, pData);
-  } else if (pSM->IsDS()) {
-    Serialize1(m_NumPCSigScalars, m_NumOutputSigScalars,
-               m_OutputsDependentOnViewId, m_PCInputsContributingToOutputs, pData);
+  *pData++ = NumInputs;
+  for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
+    unsigned NumOutputs = getNumOutputSigScalars(StreamId);
+    *pData++ = NumOutputs;
+    if (m_bUsesViewId) {
+      SerializeOutputsDependentOnViewId(NumOutputs, m_OutputsDependentOnViewId[StreamId], pData);
+    }
+    SerializeInputsContributingToOutput(NumInputs, NumOutputs, m_InputsContributingToOutputs[StreamId], pData);
+  }
+  if (pSM->IsHS() || pSM->IsDS()) {
+    unsigned NumPCs = getNumPCSigScalars();
+    *pData++ = NumPCs;
+    if (pSM->IsHS()) {
+      if (m_bUsesViewId) {
+        SerializeOutputsDependentOnViewId(NumPCs, m_PCOutputsDependentOnViewId, pData);
+      }
+      SerializeInputsContributingToOutput(NumInputs, NumPCs, m_InputsContributingToPCOutputs, pData);
+    } else {
+      unsigned NumOutputs = getNumOutputSigScalars(0);
+      SerializeInputsContributingToOutput(NumPCs, NumOutputs, m_PCInputsContributingToOutputs, pData);
+    }
   }
   DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size));
 }
+
 const vector<unsigned> &DxilViewIdState::GetSerialized() {
   if (m_SerializedState.empty())
     Serialize();
   return m_SerializedState;
 }
+
 const vector<unsigned> &DxilViewIdState::GetSerialized() const {
   return m_SerializedState;
 }
 
-void DxilViewIdState::Serialize1(unsigned NumInputs, unsigned NumOutputs,
-                                 const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
-                                 const InputsContributingToOutputType &InputsContributingToOutputs,
-                                 unsigned *&pData) {
+void DxilViewIdState::SerializeOutputsDependentOnViewId(unsigned NumOutputs, 
+                                                        const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                                        unsigned *&pData) {
   unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
 
-  unsigned *p = pData;
-  *p++ = NumInputs;
-  *p++ = NumOutputs;
-
   // Serialize output dependence on ViewId.
   for (unsigned i = 0; i < NumOutUINTs; i++) {
     unsigned x = 0;
@@ -782,8 +855,14 @@ void DxilViewIdState::Serialize1(unsigned NumInputs, unsigned NumOutputs,
         x |= (1u << j);
       }
     }
-    *p++ = x;
+    *pData++ = x;
   }
+}
+
+void DxilViewIdState::SerializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
+                                                          const InputsContributingToOutputType &InputsContributingToOutputs,
+                                                          unsigned *&pData) {
+  unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
 
   // Serialize output dependence on inputs.
   for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
@@ -792,62 +871,81 @@ void DxilViewIdState::Serialize1(unsigned NumInputs, unsigned NumOutputs,
       for (unsigned inputIdx : it->second) {
         unsigned w = outputIdx / 32;
         unsigned b = outputIdx % 32;
-        p[inputIdx*NumOutUINTs + w] |= (1u << b);
+        pData[inputIdx*NumOutUINTs + w] |= (1u << b);
       }
     }
   }
-  p += NumInputs * NumOutUINTs;
 
-  pData = p;
+  pData += NumInputs * NumOutUINTs;
 }
 
-void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSize) {
+void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSizeInUINTs) {
   Clear();
-  m_SerializedState.resize(DataSize);
-  memcpy(m_SerializedState.data(), pData, DataSize * 4);
+  m_SerializedState.resize(DataSizeInUINTs);
+  memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned));
 
   const ShaderModel *pSM = m_pModule->GetShaderModel();
-  unsigned ConsumedUINTs;
-  ConsumedUINTs = Deserialize1(pData, DataSize, m_NumInputSigScalars, m_NumOutputSigScalars,
-                               m_OutputsDependentOnViewId, m_InputsContributingToOutputs);
+  m_bUsesViewId = m_pModule->m_ShaderFlags.GetViewID();
+  unsigned ConsumedUINTs = 0;
+
+  IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
+  unsigned NumInputs = pData[ConsumedUINTs++];
+  m_NumInputSigScalars = NumInputs;
+
+  unsigned NumStreams = pSM->IsGS()? kNumStreams : 1;
+  for (unsigned StreamId = 0; StreamId < NumStreams; StreamId++) {
+    IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
+    unsigned NumOutputs = pData[ConsumedUINTs++];
+    m_NumOutputSigScalars[StreamId] = NumOutputs;
+
+    if (m_bUsesViewId) {
+      ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumOutputs, 
+                                                           m_OutputsDependentOnViewId[StreamId],
+                                                           &pData[ConsumedUINTs],
+                                                           DataSizeInUINTs-ConsumedUINTs);
+    }
+    ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumOutputs,
+                                                           m_InputsContributingToOutputs[StreamId],
+                                                           &pData[ConsumedUINTs],
+                                                           DataSizeInUINTs-ConsumedUINTs);
+  }
 
-  if (ConsumedUINTs < DataSize) {
-    unsigned t = 0;
+  if (pSM->IsHS() || pSM->IsDS()) {
+    IFTBOOL(DataSizeInUINTs-ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR);
+    unsigned NumPCs = pData[ConsumedUINTs++];
+    m_NumPCSigScalars = NumPCs;
     if (pSM->IsHS()) {
-      unsigned NumInputs;
-      t = Deserialize1(&pData[ConsumedUINTs], DataSize-ConsumedUINTs, NumInputs, m_NumPCSigScalars,
-                       m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs);
-      DXASSERT_NOMSG(NumInputs == m_NumInputSigScalars);
-    } else if (pSM->IsDS()) {
-      unsigned NumOutputs;
-      OutputsDependentOnViewIdType OutputsDependentOnViewId;
-      t = Deserialize1(&pData[ConsumedUINTs], DataSize-ConsumedUINTs,
-                       m_NumPCSigScalars, NumOutputs,
-                       OutputsDependentOnViewId, m_PCInputsContributingToOutputs);
-      DXASSERT_NOMSG(NumOutputs == m_NumOutputSigScalars);
-      DXASSERT_NOMSG(OutputsDependentOnViewId == m_OutputsDependentOnViewId);
+      if (m_bUsesViewId) {
+        ConsumedUINTs += DeserializeOutputsDependentOnViewId(NumPCs, 
+                                                             m_PCOutputsDependentOnViewId,
+                                                             &pData[ConsumedUINTs],
+                                                             DataSizeInUINTs-ConsumedUINTs);
+      }
+      ConsumedUINTs += DeserializeInputsContributingToOutput(NumInputs, NumPCs,
+                                                             m_InputsContributingToPCOutputs,
+                                                             &pData[ConsumedUINTs],
+                                                             DataSizeInUINTs-ConsumedUINTs);
+    } else {
+      unsigned NumOutputs = getNumOutputSigScalars(0);
+      ConsumedUINTs += DeserializeInputsContributingToOutput(NumPCs, NumOutputs,
+                                                             m_PCInputsContributingToOutputs,
+                                                             &pData[ConsumedUINTs],
+                                                             DataSizeInUINTs-ConsumedUINTs);
     }
-    ConsumedUINTs += t;
   }
-  DXASSERT_NOMSG(ConsumedUINTs == DataSize);
+
+  DXASSERT_NOMSG(ConsumedUINTs == DataSizeInUINTs);
 }
 
-unsigned DxilViewIdState::Deserialize1(const unsigned *pData, unsigned DataSize,
-                                       unsigned &NumInputs, unsigned &NumOutputs,
-                                       OutputsDependentOnViewIdType &OutputsDependentOnViewId,
-                                       InputsContributingToOutputType &InputsContributingToOutputs) {
-  IFTBOOL(DataSize >= 2, DXC_E_GENERAL_INTERNAL_ERROR);
-  const unsigned *p = pData;
-  NumInputs  = *p++;
-  NumOutputs = *p++;
+unsigned DxilViewIdState::DeserializeOutputsDependentOnViewId(unsigned NumOutputs, 
+                                                              OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                                              const unsigned *pData, unsigned DataSize) {
   unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
-
-  unsigned Size = 2 + NumOutUINTs * (1 +  NumInputs);
-  IFTBOOL(Size <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
+  IFTBOOL(NumOutUINTs <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
 
   // Deserialize output dependence on ViewId.
   for (unsigned i = 0; i < NumOutUINTs; i++) {
-    unsigned x = *p++;
+    unsigned x = *pData++;
     for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
       if (x & (1u << j)) {
         OutputsDependentOnViewId[i*32 + j] = true;
@@ -855,12 +953,22 @@ unsigned DxilViewIdState::Deserialize1(const unsigned *pData, unsigned DataSize,
     }
   }
 
+  return NumOutUINTs;
+}
+
+unsigned DxilViewIdState::DeserializeInputsContributingToOutput(unsigned NumInputs, unsigned NumOutputs,
+                                                                InputsContributingToOutputType &InputsContributingToOutputs,
+                                                                const unsigned *pData, unsigned DataSize) {
+  unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
+  unsigned Size = NumInputs * NumOutUINTs;
+  IFTBOOL(Size <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
+
   // Deserialize output dependence on inputs.
   for (unsigned inputIdx = 0; inputIdx < NumInputs; inputIdx++) {
     for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
       unsigned w = outputIdx / 32;
       unsigned b = outputIdx % 32;
-      if (p[inputIdx*NumOutUINTs + w] & (1u << b)) {
+      if (pData[inputIdx*NumOutUINTs + w] & (1u << b)) {
         InputsContributingToOutputs[outputIdx].insert(inputIdx);
       }
     }
@@ -869,7 +977,6 @@ unsigned DxilViewIdState::Deserialize1(const unsigned *pData, unsigned DataSize,
   return Size;
 }
 
-
 char ComputeViewIdState::ID = 0;
 
 INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid-state",

+ 37 - 24
lib/HLSL/DxilContainerAssembler.cpp

@@ -388,31 +388,27 @@ private:
       E.ColsAndStart |= 0x40 | (SE.GetStartCol() << 4);
       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.InterpolationMode = (uint8_t)SE.GetInterpolationMode()->GetKind();
     DXASSERT_NOMSG(SE.GetOutputStream() < 4);
     E.DynamicMaskAndStream = (uint8_t)((SE.GetOutputStream() & 0x3) << 4);
-
-    // TODO: Fill Dynamic Index Mask in!
     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);
-    if (ViewIDMask.Masks) {
+    if (ViewIDMask.IsValid()) {
       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((OutputScalars <= IOTable.OutputVectors * 4) && (IOTable.OutputVectors * 4 - OutputScalars < 4));
       memcpy(IOTable.Table, pSrc, 4 * MaskDwords * InputScalars);
+      pSrc += MaskDwords * InputScalars;
     }
-    pSrc += MaskDwords * InputScalars;
     return pSrc;
   }
 
@@ -427,12 +423,14 @@ public:
     if (m_PSVInitInfo.PSVVersion < 1 && (ValMajor > 1 || (ValMajor == 1 && ValMinor >= 1)))
       m_PSVInitInfo.PSVVersion = 1;
 
+    const ShaderModel *SM = m_Module.GetShaderModel();
     UINT uCBuffers = m_Module.GetCBuffers().size();
     UINT uSamplers = m_Module.GetSamplers().size();
     UINT uSRVs = m_Module.GetSRVs().size();
     UINT uUAVs = m_Module.GetUAVs().size();
     m_PSVInitInfo.ResourceCount = uCBuffers + uSamplers + uSRVs + uUAVs;
     if (m_PSVInitInfo.PSVVersion > 0) {
+      m_PSVInitInfo.ShaderStage = (PSVShaderKind)SM->GetKind();
       // Copy Dxil Signatures
       m_StringBuffer.push_back('\0'); // For empty semantic name (system value)
       m_PSVInitInfo.SigInputElements = m_Module.GetInputSignature().GetElements().size();
@@ -459,18 +457,22 @@ public:
       m_PSVInitInfo.SemanticIndexTable.Table = m_SemanticIndexBuffer.data();
       m_PSVInitInfo.SemanticIndexTable.Entries = m_SemanticIndexBuffer.size();
       // 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 {
     return m_PSVBufferSize;
@@ -478,7 +480,9 @@ public:
 
   __override void write(AbstractMemoryStream *pStream) {
     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);
 
     // Set DxilRuntimInfo
@@ -650,11 +654,20 @@ public:
       auto &viewState = m_Module.GetViewIdState().GetSerialized();
       if (!viewState.empty()) {
         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()) {
-          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()) {
-          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);
       }

+ 8 - 2
lib/HLSL/DxilModule.cpp

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

+ 6 - 2
lib/HLSL/DxilSignature.cpp

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

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid01.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 4, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 4, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 1 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid02.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 8, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 8, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 0, 3 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 4, 7 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid03.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 8, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 8, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 0 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 5, 7 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid04.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 8, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 8, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 0 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 1, 5, 6, 7 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid05.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 12, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 12, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 0 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 5, 11 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid06.hlsl

@@ -5,7 +5,7 @@
 // CHECK: AAA                      0                 linear
 // CHECK: BBB                      0        nointerpolation     yw
 
-// CHECK: Number of inputs: 12, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 12, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 0 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 5, 7, 9, 11 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid07.hlsl

@@ -1,6 +1,6 @@
 // RUN: %dxc -E main -T ps_6_1 %s | FileCheck %s
 
-// CHECK: Number of inputs: 4, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 4, outputs: 4
 // CHECK: Outputs dependent on ViewId: { 2 }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 1 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid08.hlsl

@@ -4,7 +4,7 @@
 // CHECK: -------------------- ----- ---------------------- ------
 // CHECK: AAA                      0                 linear      y
 
-// CHECK: Number of inputs: 12, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 12, outputs: 4
 // CHECK: Outputs dependent on ViewId: {  }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 1, 2, 3, 5, 8, 9 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid09.hlsl

@@ -4,7 +4,7 @@
 // CHECK: -------------------- ----- ---------------------- ------
 // CHECK: AAA                      0                 linear      y
 
-// CHECK: Number of inputs: 12, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 12, outputs: 4
 // CHECK: Outputs dependent on ViewId: {  }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 1, 2, 3, 5, 6, 8, 9 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid10.hlsl

@@ -4,7 +4,7 @@
 // CHECK: -------------------- ----- ---------------------- ------
 // CHECK: AAA                      0                 linear      y
 
-// CHECK: Number of inputs: 8, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 8, outputs: 4
 // CHECK: Outputs dependent on ViewId: {  }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 1, 5 }

+ 1 - 1
tools/clang/test/CodeGenHLSL/viewid/viewid11.hlsl

@@ -4,7 +4,7 @@
 // CHECK: -------------------- ----- ---------------------- ------
 // CHECK: AAA                      0                 linear     yz
 
-// CHECK: Number of inputs: 12, outputs: 4, patchconst: 0
+// CHECK: Number of inputs: 12, outputs: 4
 // CHECK: Outputs dependent on ViewId: {  }
 // CHECK: Inputs contributing to computation of Outputs:
 // CHECK:   output 0 depends on inputs: { 0, 1, 5, 7, 9 }

+ 35 - 5
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -106,6 +106,7 @@
 using namespace llvm;
 using namespace clang;
 using namespace hlsl;
+using std::string;
 
 // This declaration is used for the locally-linked validator.
 HRESULT CreateDxcValidator(_In_ REFIID riid, _Out_ LPVOID *ppv);
@@ -1267,15 +1268,44 @@ static void PrintViewIdState(DxilModule &M, raw_string_ostream &OS, StringRef co
   OS << comment << "\n";
   OS << comment << " ViewId state:\n";
   OS << comment << "\n";
-  OS << comment << " Number of inputs: " << VID.getNumInputSigScalars()  << 
-                           ", outputs: " << VID.getNumOutputSigScalars() << 
-                        ", patchconst: " << VID.getNumPCSigScalars()     << "\n";
-  PrintOutputsDependentOnViewId(OS, comment, "Outputs", VID.getNumOutputSigScalars(), VID.getOutputsDependentOnViewId());
+  OS << comment << " Number of inputs: " << VID.getNumInputSigScalars();
+  if (!pSM->IsGS()) {
+    OS << ", outputs: " << VID.getNumOutputSigScalars(0);
+  } else {
+    OS << ", outputs per stream: { " << VID.getNumOutputSigScalars(0) << ", " <<
+                                        VID.getNumOutputSigScalars(1) << ", " <<
+                                        VID.getNumOutputSigScalars(2) << ", " <<
+                                        VID.getNumOutputSigScalars(3) << " }";
+  }
+  if (pSM->IsHS() || pSM->IsDS()) {
+    OS << ", patchconst: " << VID.getNumPCSigScalars();
+  }
+  OS << "\n";
+
+  if (!pSM->IsGS()) {
+    PrintOutputsDependentOnViewId(OS, comment, "Outputs", VID.getNumOutputSigScalars(0), VID.getOutputsDependentOnViewId(0));
+  } else {
+    for (unsigned i = 0; i < 4; i++) {
+      if (VID.getNumOutputSigScalars(i) > 0) {
+        string OutputsName = string("Outputs for Stream ") + std::to_string(i);
+        PrintOutputsDependentOnViewId(OS, comment, OutputsName, VID.getNumOutputSigScalars(i), VID.getOutputsDependentOnViewId(i));
+      }
+    }
+  }
   if (pSM->IsHS()) {
     PrintOutputsDependentOnViewId(OS, comment, "PCOutputs", VID.getNumPCSigScalars(), VID.getPCOutputsDependentOnViewId());
   }
 
-  PrintInputsContributingToOutputs(OS, comment, "Inputs", "Outputs", VID.getInputsContributingToOutputs());
+  if (!pSM->IsGS()) {
+    PrintInputsContributingToOutputs(OS, comment, "Inputs", "Outputs", VID.getInputsContributingToOutputs(0));
+  } else {
+    for (unsigned i = 0; i < 4; i++) {
+      if (VID.getNumOutputSigScalars(i) > 0) {
+        string OutputsName = string("Outputs for Stream ") + std::to_string(i);
+        PrintInputsContributingToOutputs(OS, comment, "Inputs", OutputsName, VID.getInputsContributingToOutputs(i));
+      }
+    }
+  }
   if (pSM->IsHS()) {
     PrintInputsContributingToOutputs(OS, comment, "Inputs", "PCOutputs", VID.getInputsContributingToPCOutputs());
   } else if (pSM->IsDS()) {

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

@@ -1055,10 +1055,12 @@ TEST_F(ValidationTest, StreamIDOutOfBound) {
 
 TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
   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) {

+ 1 - 1
utils/hct/hctdb_instrhelp.py

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