| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // ComputeViewIdState.cpp // |
| // 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/ComputeViewIdState.h" |
| #include "dxc/DXIL/DxilInstructions.h" |
| #include "dxc/DXIL/DxilModule.h" |
| #include "dxc/DXIL/DxilOperations.h" |
| #include "dxc/Support/Global.h" |
| |
| #include "llvm/Analysis/CallGraph.h" |
| #include "llvm/IR/CFG.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/LegacyPassManager.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/IR/Operator.h" |
| #include "llvm/Pass.h" |
| #include "llvm/Support/Debug.h" |
| |
| #include <algorithm> |
| |
| using namespace llvm; |
| using namespace llvm::legacy; |
| using namespace hlsl; |
| using llvm::legacy::FunctionPassManager; |
| using llvm::legacy::PassManager; |
| using std::unordered_map; |
| using std::unordered_set; |
| using std::vector; |
| |
| #define DEBUG_TYPE "viewid" |
| |
| DxilViewIdState::DxilViewIdState(DxilModule *pDxilModule) |
| : m_pModule(pDxilModule) {} |
| unsigned DxilViewIdState::getNumInputSigScalars() const { |
| return m_NumInputSigScalars; |
| } |
| unsigned DxilViewIdState::getNumOutputSigScalars(unsigned StreamId) const { |
| return m_NumOutputSigScalars[StreamId]; |
| } |
| unsigned DxilViewIdState::getNumPCSigScalars() const { |
| return m_NumPCOrPrimSigScalars; |
| } |
| const DxilViewIdState::OutputsDependentOnViewIdType & |
| DxilViewIdState::getOutputsDependentOnViewId(unsigned StreamId) const { |
| return m_OutputsDependentOnViewId[StreamId]; |
| } |
| const DxilViewIdState::OutputsDependentOnViewIdType & |
| DxilViewIdState::getPCOutputsDependentOnViewId() const { |
| return m_PCOrPrimOutputsDependentOnViewId; |
| } |
| const DxilViewIdState::InputsContributingToOutputType & |
| DxilViewIdState::getInputsContributingToOutputs(unsigned StreamId) const { |
| return m_InputsContributingToOutputs[StreamId]; |
| } |
| const DxilViewIdState::InputsContributingToOutputType & |
| DxilViewIdState::getInputsContributingToPCOutputs() const { |
| return m_InputsContributingToPCOrPrimOutputs; |
| } |
| const DxilViewIdState::InputsContributingToOutputType & |
| DxilViewIdState::getPCInputsContributingToOutputs() const { |
| return m_PCInputsContributingToOutputs; |
| } |
| |
| namespace { |
| |
| void PrintOutputsDependentOnViewId( |
| llvm::raw_ostream &OS, llvm::StringRef SetName, unsigned NumOutputs, |
| const DxilViewIdState::OutputsDependentOnViewIdType |
| &OutputsDependentOnViewId) { |
| OS << SetName << " dependent on ViewId: { "; |
| bool bFirst = true; |
| for (unsigned i = 0; i < NumOutputs; i++) { |
| if (OutputsDependentOnViewId[i]) { |
| if (!bFirst) |
| OS << ", "; |
| OS << i; |
| bFirst = false; |
| } |
| } |
| OS << " }\n"; |
| } |
| |
| void PrintInputsContributingToOutputs( |
| llvm::raw_ostream &OS, llvm::StringRef InputSetName, |
| llvm::StringRef OutputSetName, |
| const DxilViewIdState::InputsContributingToOutputType |
| &InputsContributingToOutputs) { |
| OS << InputSetName << " contributing to computation of " << OutputSetName |
| << ":\n"; |
| for (auto &it : InputsContributingToOutputs) { |
| unsigned outIdx = it.first; |
| auto &Inputs = it.second; |
| OS << "output " << outIdx << " depends on inputs: { "; |
| bool bFirst = true; |
| for (unsigned i : Inputs) { |
| if (!bFirst) |
| OS << ", "; |
| OS << i; |
| bFirst = false; |
| } |
| OS << " }\n"; |
| } |
| } |
| } // namespace |
| |
| void DxilViewIdState::PrintSets(llvm::raw_ostream &OS) { |
| const ShaderModel *pSM = m_pModule->GetShaderModel(); |
| OS << "ViewId state: \n"; |
| |
| if (pSM->IsGS()) { |
| OS << "Number of inputs: " << m_NumInputSigScalars << ", outputs: { " |
| << m_NumOutputSigScalars[0] << ", " << m_NumOutputSigScalars[1] << ", " |
| << m_NumOutputSigScalars[2] << ", " << m_NumOutputSigScalars[3] << " }" |
| << ", patchconst: " << m_NumPCOrPrimSigScalars << "\n"; |
| } else if (pSM->IsMS()) { |
| OS << "Number of inputs: " << m_NumInputSigScalars |
| << ", vertex outputs: " << m_NumOutputSigScalars[0] |
| << ", primitive outputs: " << m_NumPCOrPrimSigScalars << "\n"; |
| } else { |
| OS << "Number of inputs: " << m_NumInputSigScalars |
| << ", outputs: " << m_NumOutputSigScalars[0] |
| << ", patchconst: " << m_NumPCOrPrimSigScalars << "\n"; |
| } |
| |
| if (pSM->IsGS()) { |
| 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]); |
| } else if (pSM->IsMS()) { |
| PrintOutputsDependentOnViewId(OS, "Vertex Outputs", |
| m_NumOutputSigScalars[0], |
| m_OutputsDependentOnViewId[0]); |
| } else { |
| PrintOutputsDependentOnViewId(OS, "Outputs", m_NumOutputSigScalars[0], |
| m_OutputsDependentOnViewId[0]); |
| } |
| |
| if (pSM->IsHS()) { |
| PrintOutputsDependentOnViewId(OS, "PCOutputs", m_NumPCOrPrimSigScalars, |
| m_PCOrPrimOutputsDependentOnViewId); |
| } else if (pSM->IsMS()) { |
| PrintOutputsDependentOnViewId(OS, "Primitive Outputs", |
| m_NumPCOrPrimSigScalars, |
| m_PCOrPrimOutputsDependentOnViewId); |
| } |
| |
| if (pSM->IsGS()) { |
| 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]); |
| } else if (pSM->IsMS()) { |
| PrintInputsContributingToOutputs(OS, "Inputs", "Vertex Outputs", |
| m_InputsContributingToOutputs[0]); |
| } else { |
| PrintInputsContributingToOutputs(OS, "Inputs", "Outputs", |
| m_InputsContributingToOutputs[0]); |
| } |
| if (pSM->IsHS()) { |
| PrintInputsContributingToOutputs(OS, "Inputs", "PCOutputs", |
| m_InputsContributingToPCOrPrimOutputs); |
| } else if (pSM->IsMS()) { |
| PrintInputsContributingToOutputs(OS, "Inputs", "Primitive Outputs", |
| m_InputsContributingToPCOrPrimOutputs); |
| } else if (pSM->IsDS()) { |
| PrintInputsContributingToOutputs(OS, "PCInputs", "Outputs", |
| m_PCInputsContributingToOutputs); |
| } |
| OS << "\n"; |
| } |
| |
| void DxilViewIdState::Clear() { |
| m_NumInputSigScalars = 0; |
| for (unsigned i = 0; i < kNumStreams; i++) { |
| m_NumOutputSigScalars[i] = 0; |
| m_OutputsDependentOnViewId[i].reset(); |
| m_InputsContributingToOutputs[i].clear(); |
| } |
| m_NumPCOrPrimSigScalars = 0; |
| m_PCOrPrimOutputsDependentOnViewId.reset(); |
| m_InputsContributingToPCOrPrimOutputs.clear(); |
| m_PCInputsContributingToOutputs.clear(); |
| m_SerializedState.clear(); |
| } |
| |
| namespace { |
| |
| unsigned RoundUpToUINT(unsigned x) { return (x + 31) / 32; } |
| |
| void SerializeOutputsDependentOnViewId( |
| unsigned NumOutputs, |
| const DxilViewIdState::OutputsDependentOnViewIdType |
| &OutputsDependentOnViewId, |
| unsigned *&pData) { |
| unsigned NumOutUINTs = RoundUpToUINT(NumOutputs); |
| |
| // Serialize output dependence on ViewId. |
| for (unsigned i = 0; i < NumOutUINTs; i++) { |
| unsigned x = 0; |
| for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u * i); j++) { |
| if (OutputsDependentOnViewId[i * 32 + j]) { |
| x |= (1u << j); |
| } |
| } |
| *pData++ = x; |
| } |
| } |
| |
| void SerializeInputsContributingToOutput( |
| unsigned NumInputs, unsigned NumOutputs, |
| const DxilViewIdState::InputsContributingToOutputType |
| &InputsContributingToOutputs, |
| unsigned *&pData) { |
| unsigned NumOutUINTs = RoundUpToUINT(NumOutputs); |
| |
| // Serialize output dependence on inputs. |
| for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) { |
| auto it = InputsContributingToOutputs.find(outputIdx); |
| if (it != InputsContributingToOutputs.end()) { |
| for (unsigned inputIdx : it->second) { |
| unsigned w = outputIdx / 32; |
| unsigned b = outputIdx % 32; |
| pData[inputIdx * NumOutUINTs + w] |= (1u << b); |
| } |
| } |
| } |
| |
| pData += NumInputs * NumOutUINTs; |
| } |
| } // namespace |
| |
| void DxilViewIdState::Serialize() { |
| const ShaderModel *pSM = m_pModule->GetShaderModel(); |
| 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() || pSM->IsMS()) { |
| Size += 1; // #PatchConstant. |
| unsigned NumPCs = getNumPCSigScalars(); |
| unsigned NumPCUINTs = RoundUpToUINT(NumPCs); |
| if (pSM->IsHS() || pSM->IsMS()) { |
| if (m_bUsesViewId) { |
| Size += NumPCUINTs; // m_PCOrPrimOutputsDependentOnViewId |
| } |
| Size += NumInputs * NumPCUINTs; // m_InputsContributingToPCOrPrimOutputs |
| } else { |
| unsigned NumOutputs = getNumOutputSigScalars(0); |
| unsigned NumOutUINTs = RoundUpToUINT(NumOutputs); |
| Size += NumPCs * NumOutUINTs; // m_PCInputsContributingToOutputs |
| } |
| } |
| |
| m_SerializedState.resize(Size); |
| std::fill(m_SerializedState.begin(), m_SerializedState.end(), 0u); |
| |
| // Serialize ViewId state. |
| unsigned *pData = &m_SerializedState[0]; |
| *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() || pSM->IsMS()) { |
| unsigned NumPCs = getNumPCSigScalars(); |
| *pData++ = NumPCs; |
| if (pSM->IsHS() || pSM->IsMS()) { |
| if (m_bUsesViewId) { |
| SerializeOutputsDependentOnViewId( |
| NumPCs, m_PCOrPrimOutputsDependentOnViewId, pData); |
| } |
| SerializeInputsContributingToOutput( |
| NumInputs, NumPCs, m_InputsContributingToPCOrPrimOutputs, 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; |
| } |
| |
| namespace { |
| unsigned DeserializeOutputsDependentOnViewId( |
| unsigned NumOutputs, |
| DxilViewIdState::OutputsDependentOnViewIdType &OutputsDependentOnViewId, |
| const unsigned *pData, unsigned DataSize) { |
| unsigned NumOutUINTs = RoundUpToUINT(NumOutputs); |
| IFTBOOL(NumOutUINTs <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR); |
| |
| // Deserialize output dependence on ViewId. |
| for (unsigned i = 0; i < NumOutUINTs; i++) { |
| unsigned x = *pData++; |
| for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u * i); j++) { |
| if (x & (1u << j)) { |
| OutputsDependentOnViewId[i * 32 + j] = true; |
| } |
| } |
| } |
| |
| return NumOutUINTs; |
| } |
| |
| unsigned DeserializeInputsContributingToOutput( |
| unsigned NumInputs, unsigned NumOutputs, |
| DxilViewIdState::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 (pData[inputIdx * NumOutUINTs + w] & (1u << b)) { |
| InputsContributingToOutputs[outputIdx].insert(inputIdx); |
| } |
| } |
| } |
| |
| return Size; |
| } |
| } // namespace |
| |
| void DxilViewIdState::Deserialize(const unsigned *pData, |
| unsigned DataSizeInUINTs) { |
| Clear(); |
| m_SerializedState.resize(DataSizeInUINTs); |
| memcpy(m_SerializedState.data(), pData, DataSizeInUINTs * sizeof(unsigned)); |
| |
| const ShaderModel *pSM = m_pModule->GetShaderModel(); |
| 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 (pSM->IsHS() || pSM->IsDS() || pSM->IsMS()) { |
| IFTBOOL(DataSizeInUINTs - ConsumedUINTs >= 1, DXC_E_GENERAL_INTERNAL_ERROR); |
| unsigned NumPCs = pData[ConsumedUINTs++]; |
| m_NumPCOrPrimSigScalars = NumPCs; |
| if (pSM->IsHS() || pSM->IsMS()) { |
| if (m_bUsesViewId) { |
| ConsumedUINTs += DeserializeOutputsDependentOnViewId( |
| NumPCs, m_PCOrPrimOutputsDependentOnViewId, &pData[ConsumedUINTs], |
| DataSizeInUINTs - ConsumedUINTs); |
| } |
| ConsumedUINTs += DeserializeInputsContributingToOutput( |
| NumInputs, NumPCs, m_InputsContributingToPCOrPrimOutputs, |
| &pData[ConsumedUINTs], DataSizeInUINTs - ConsumedUINTs); |
| } else { |
| unsigned NumOutputs = getNumOutputSigScalars(0); |
| ConsumedUINTs += DeserializeInputsContributingToOutput( |
| NumPCs, NumOutputs, m_PCInputsContributingToOutputs, |
| &pData[ConsumedUINTs], DataSizeInUINTs - ConsumedUINTs); |
| } |
| } |
| |
| DXASSERT_NOMSG(ConsumedUINTs == DataSizeInUINTs); |
| } |