Browse Source

Support ViewID state for GS multiple streams

New serialization/deserialization for ViewID state
Yuri Dotsenko 8 years ago
parent
commit
ff86b6b211

+ 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/DxilModule.h

@@ -168,6 +168,7 @@ public:
 
     uint64_t GetFeatureInfo() const;
     bool GetWaveOps() const { return m_bWaveOps; }
+    bool GetUsesViewId() const { return m_bViewID != 0; }
     void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
     void SetROVs(bool flag) { m_bROVS = flag; }
     void SetWaveOps(bool flag) { m_bWaveOps = flag; }

+ 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.GetUsesViewId();
+  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",

+ 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()) {