blob: 718ddcc2fe2db8bfc1e55f548c6bedcb73371e13 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// 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);
}