Move some functions to common locations for upcoming D3D12 usage.

Some work for shader debugging is identical to setting up the quad
overlay, so I've moved that logic to their own functions.
Some portions of creating a global shader debug state, and the
entirety of the initial shader debug state were agnostic of D3D API,
so they now exist in DXBC code.
This commit is contained in:
Steve Karolewics
2019-11-12 12:33:03 +00:00
committed by Baldur Karlsson
parent b5890155b5
commit 9b141086c0
8 changed files with 354 additions and 296 deletions
-3
View File
@@ -119,9 +119,6 @@ public:
void PixelHistoryCopyPixel(CopyPixelParams &params, uint32_t x, uint32_t y);
ShaderDebug::State CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx,
DXBC::DXBCContainer *dxbc, const ShaderReflection &refl,
bytebuf *cbufData);
void CreateShaderGlobalState(ShaderDebug::GlobalState &global, DXBC::DXBCContainer *dxbc,
uint32_t UAVStartSlot, ID3D11UnorderedAccessView **UAVs,
ID3D11ShaderResourceView **SRVs);
+9 -202
View File
@@ -1416,171 +1416,6 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod
return true;
}
ShaderDebug::State D3D11DebugManager::CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx,
DXBC::DXBCContainer *dxbc,
const ShaderReflection &refl,
bytebuf *cbufData)
{
using namespace DXBCBytecode;
using namespace ShaderDebug;
State initialState = State(quadIdx, &trace, dxbc->GetReflection(), dxbc->GetDXBCByteCode());
// use pixel shader here to get inputs
int32_t maxReg = -1;
for(size_t i = 0; i < dxbc->GetReflection()->InputSig.size(); i++)
maxReg = RDCMAX(maxReg, (int32_t)dxbc->GetReflection()->InputSig[i].regIndex);
bool inputCoverage = false;
for(size_t i = 0; i < dxbc->GetDXBCByteCode()->GetNumDeclarations(); i++)
{
const DXBCBytecode::Declaration &decl = dxbc->GetDXBCByteCode()->GetDeclaration(i);
if(decl.declaration == OPCODE_DCL_INPUT && decl.operand.type == TYPE_INPUT_COVERAGE_MASK)
{
inputCoverage = true;
break;
}
}
if(maxReg >= 0 || inputCoverage)
{
trace.inputs.resize(maxReg + 1 + (inputCoverage ? 1 : 0));
for(size_t i = 0; i < dxbc->GetReflection()->InputSig.size(); i++)
{
const SigParameter &sig = dxbc->GetReflection()->InputSig[i];
ShaderVariable v;
v.name = StringFormat::Fmt("v%d (%s)", sig.regIndex, sig.semanticIdxName.c_str());
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
if(sig.compType == CompType::UInt)
v.type = VarType::UInt;
else if(sig.compType == CompType::SInt)
v.type = VarType::SInt;
if(trace.inputs[sig.regIndex].columns == 0)
trace.inputs[sig.regIndex] = v;
else
trace.inputs[sig.regIndex].columns = RDCMAX(trace.inputs[sig.regIndex].columns, v.columns);
}
if(inputCoverage)
{
trace.inputs[maxReg + 1] = ShaderVariable("vCoverage", 0U, 0U, 0U, 0U);
trace.inputs[maxReg + 1].columns = 1;
}
}
uint32_t specialOutputs = 0;
maxReg = -1;
for(size_t i = 0; i < dxbc->GetReflection()->OutputSig.size(); i++)
{
if(dxbc->GetReflection()->OutputSig[i].regIndex == ~0U)
specialOutputs++;
else
maxReg = RDCMAX(maxReg, (int32_t)dxbc->GetReflection()->OutputSig[i].regIndex);
}
if(maxReg >= 0 || specialOutputs > 0)
{
initialState.outputs.resize(maxReg + 1 + specialOutputs);
for(size_t i = 0; i < dxbc->GetReflection()->OutputSig.size(); i++)
{
const SigParameter &sig = dxbc->GetReflection()->OutputSig[i];
if(sig.regIndex == ~0U)
continue;
ShaderVariable v;
v.name = StringFormat::Fmt("o%d (%s)", sig.regIndex, sig.semanticIdxName.c_str());
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
if(initialState.outputs[sig.regIndex].columns == 0)
initialState.outputs[sig.regIndex] = v;
else
initialState.outputs[sig.regIndex].columns =
RDCMAX(initialState.outputs[sig.regIndex].columns, v.columns);
}
int32_t outIdx = maxReg + 1;
for(size_t i = 0; i < dxbc->GetReflection()->OutputSig.size(); i++)
{
const SigParameter &sig = dxbc->GetReflection()->OutputSig[i];
if(sig.regIndex != ~0U)
continue;
ShaderVariable v;
if(sig.systemValue == ShaderBuiltin::OutputControlPointIndex)
v.name = "vOutputControlPointID";
else if(sig.systemValue == ShaderBuiltin::DepthOutput)
v.name = "oDepth";
else if(sig.systemValue == ShaderBuiltin::DepthOutputLessEqual)
v.name = "oDepthLessEqual";
else if(sig.systemValue == ShaderBuiltin::DepthOutputGreaterEqual)
v.name = "oDepthGreaterEqual";
else if(sig.systemValue == ShaderBuiltin::MSAACoverage)
v.name = "oMask";
else if(sig.systemValue == ShaderBuiltin::StencilReference)
v.name = "oStencilRef";
// if(sig.systemValue == TYPE_OUTPUT_CONTROL_POINT) str = "oOutputControlPoint";
else
{
RDCERR("Unhandled output: %s (%d)", sig.semanticName.c_str(), sig.systemValue);
continue;
}
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
initialState.outputs[outIdx++] = v;
}
}
trace.constantBlocks.resize(dxbc->GetReflection()->CBuffers.size());
for(size_t i = 0; i < dxbc->GetReflection()->CBuffers.size(); i++)
{
rdcarray<ShaderVariable> vars;
// fetch the cbuffer data into vars, which will be 'natural' - structs with members, non merged
// vectors
StandardFillCBufferVariables(refl.constantBlocks[i].variables, vars,
cbufData[dxbc->GetReflection()->CBuffers[i].reg]);
FlattenVariables(refl.constantBlocks[i].variables, vars, trace.constantBlocks[i].members);
for(size_t c = 0; c < trace.constantBlocks[i].members.size(); c++)
trace.constantBlocks[i].members[c].name =
StringFormat::Fmt("cb%u[%u] (%s)", dxbc->GetReflection()->CBuffers[i].reg, (uint32_t)c,
trace.constantBlocks[i].members[c].name.c_str());
}
initialState.Init();
return initialState;
}
void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global,
DXBC::DXBCContainer *dxbc, uint32_t UAVStartSlot,
ID3D11UnorderedAccessView **UAVs,
@@ -1809,17 +1644,7 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global
if(sdesc.Format != DXGI_FORMAT_UNKNOWN)
{
ResourceFormat fmt = MakeResourceFormat(sdesc.Format);
global.srvs[i].format.byteWidth = fmt.compByteWidth;
global.srvs[i].format.numComps = fmt.compCount;
global.srvs[i].format.fmt = fmt.compType;
if(sdesc.Format == DXGI_FORMAT_R11G11B10_FLOAT)
global.srvs[i].format.byteWidth = 11;
if(sdesc.Format == DXGI_FORMAT_R10G10B10A2_UINT ||
sdesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
global.srvs[i].format.byteWidth = 10;
ShaderDebug::FillViewFmt(sdesc.Format, global.srvs[i].format);
}
else
{
@@ -1835,28 +1660,8 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global
global.srvs[i].format.stride = bufdesc.StructureByteStride;
// if we didn't get a type from the SRV description, try to pull it from the declaration
for(const DXBC::ShaderInputBind &bind : dxbc->GetReflection()->SRVs)
{
if(bind.reg == (uint32_t)i && bind.dimension == DXBC::ShaderInputBind::DIM_BUFFER &&
bind.retType < DXBC::RETURN_TYPE_MIXED && bind.retType != DXBC::RETURN_TYPE_UNKNOWN)
{
global.srvs[i].format.byteWidth = 4;
global.srvs[i].format.numComps = bind.numSamples;
if(bind.retType == DXBC::RETURN_TYPE_UNORM)
global.srvs[i].format.fmt = CompType::UNorm;
else if(bind.retType == DXBC::RETURN_TYPE_SNORM)
global.srvs[i].format.fmt = CompType::SNorm;
else if(bind.retType == DXBC::RETURN_TYPE_UINT)
global.srvs[i].format.fmt = CompType::UInt;
else if(bind.retType == DXBC::RETURN_TYPE_SINT)
global.srvs[i].format.fmt = CompType::SInt;
else
global.srvs[i].format.fmt = CompType::Float;
break;
}
}
ShaderDebug::LookupSRVFormatFromShaderReflection(*dxbc->GetReflection(), (uint32_t)i,
global.srvs[i].format);
}
}
@@ -2020,7 +1825,8 @@ ShaderDebugTrace D3D11Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uin
GlobalState global;
GetDebugManager()->CreateShaderGlobalState(global, dxbc, 0, NULL, rs->VS.SRVs);
State initialState = GetDebugManager()->CreateShaderDebugState(ret, -1, dxbc, refl, cbufData);
State initialState;
CreateShaderDebugStateAndTrace(initialState, ret, -1, dxbc, refl, cbufData);
for(size_t i = 0; i < ret.inputs.size(); i++)
{
@@ -3235,8 +3041,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, uint prim
{
DebugHit *hit = winner;
State initialState =
GetDebugManager()->CreateShaderDebugState(traces[destIdx], destIdx, dxbc, refl, cbufData);
State initialState;
CreateShaderDebugStateAndTrace(initialState, traces[destIdx], destIdx, dxbc, refl, cbufData);
rdcarray<ShaderVariable> &ins = traces[destIdx].inputs;
if(!ins.empty() && ins.back().name == "vCoverage")
@@ -3536,7 +3342,8 @@ ShaderDebugTrace D3D11Replay::DebugThread(uint32_t eventId, const uint32_t group
GlobalState global;
GetDebugManager()->CreateShaderGlobalState(global, dxbc, 0, rs->CSUAVs, rs->CS.SRVs);
State initialState = GetDebugManager()->CreateShaderDebugState(ret, -1, dxbc, refl, cbufData);
State initialState;
CreateShaderDebugStateAndTrace(initialState, ret, -1, dxbc, refl, cbufData);
for(int i = 0; i < 3; i++)
{
+107
View File
@@ -1579,3 +1579,110 @@ void D3D12Replay::HistogramMinMax::Release()
SAFE_RELEASE(MinMaxResultBuffer);
SAFE_RELEASE(MinMaxTileBuffer);
}
void MoveRootSignatureElementsToRegisterSpace(D3D12RootSignature &sig, uint32_t registerSpace,
D3D12DescriptorType type,
D3D12_SHADER_VISIBILITY visibility)
{
// This function is used when root signature elements need to be added to a specific register
// space, such as for debug overlays. We can't remove elements from the root signature entirely
// because then then the root signature indices wouldn't match up as expected. Instead move them
// into the specified register space so that another register space (commonly space0) can be used
// for other purposes.
size_t numParams = sig.params.size();
for(size_t i = 0; i < numParams; i++)
{
if(sig.params[i].ShaderVisibility == visibility ||
sig.params[i].ShaderVisibility == D3D12_SHADER_VISIBILITY_ALL)
{
D3D12_ROOT_PARAMETER_TYPE rootType = sig.params[i].ParameterType;
if(rootType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
{
size_t numRanges = sig.params[i].ranges.size();
for(size_t r = 0; r < numRanges; r++)
{
D3D12_DESCRIPTOR_RANGE_TYPE rangeType = sig.params[i].ranges[r].RangeType;
if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_CBV && type == D3D12DescriptorType::CBV)
{
sig.params[i].ranges[r].RegisterSpace = registerSpace;
}
else if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV && type == D3D12DescriptorType::SRV)
{
sig.params[i].ranges[r].RegisterSpace = registerSpace;
}
else if(rangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV && type == D3D12DescriptorType::UAV)
{
sig.params[i].ranges[r].RegisterSpace = registerSpace;
}
}
}
else if(rootType == D3D12_ROOT_PARAMETER_TYPE_CBV && type == D3D12DescriptorType::CBV)
{
sig.params[i].Descriptor.RegisterSpace = registerSpace;
}
else if(rootType == D3D12_ROOT_PARAMETER_TYPE_SRV && type == D3D12DescriptorType::SRV)
{
sig.params[i].Descriptor.RegisterSpace = registerSpace;
}
else if(rootType == D3D12_ROOT_PARAMETER_TYPE_UAV && type == D3D12DescriptorType::UAV)
{
sig.params[i].Descriptor.RegisterSpace = registerSpace;
}
}
}
}
void AddDebugDescriptorToRenderState(WrappedID3D12Device *pDevice, D3D12RenderState &rs,
const PortableHandle &handle,
D3D12_DESCRIPTOR_HEAP_TYPE heapType, uint32_t sigElem,
std::set<ResourceId> &copiedHeaps)
{
if(rs.graphics.sigelems.size() <= sigElem)
rs.graphics.sigelems.resize(sigElem + 1);
PortableHandle newHandle = handle;
// If a CBV_SRV_UAV heap is already set and hasn't had a debug descriptor copied in,
// copy the desired descriptor in and add the heap to the set of heaps that have had
// a debug descriptor set. If there's no available heapOtherwise we can set our own heap.
// It is the responsibility of the caller to keep track of the set of copied heaps to
// avoid overwriting another debug descriptor that may be needed.
for(size_t i = 0; i < rs.heaps.size(); i++)
{
WrappedID3D12DescriptorHeap *h =
pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(rs.heaps[i]);
if(h->GetDesc().Type == heapType)
{
// use the last descriptor
D3D12_CPU_DESCRIPTOR_HANDLE dst = h->GetCPUDescriptorHandleForHeapStart();
dst.ptr += (h->GetDesc().NumDescriptors - 1) * sizeof(D3D12Descriptor);
if(copiedHeaps.find(rs.heaps[i]) == copiedHeaps.end())
{
WrappedID3D12DescriptorHeap *h2 =
pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(handle.heap);
D3D12_CPU_DESCRIPTOR_HANDLE src = h2->GetCPUDescriptorHandleForHeapStart();
src.ptr += handle.index * sizeof(D3D12Descriptor);
// can't do a copy because the src heap is CPU write-only (shader visible). So instead,
// create directly
D3D12Descriptor *srcDesc = (D3D12Descriptor *)src.ptr;
srcDesc->Create(heapType, pDevice, dst);
copiedHeaps.insert(rs.heaps[i]);
}
newHandle = ToPortableHandle(dst);
break;
}
}
if(newHandle.heap == handle.heap)
rs.heaps.push_back(handle.heap);
rs.graphics.sigelems[sigElem] =
D3D12RenderState::SignatureElement(eRootTable, newHandle.heap, newHandle.index);
}
+10 -3
View File
@@ -28,6 +28,7 @@
#include "core/core.h"
#include "replay/replay_driver.h"
#include "d3d12_common.h"
#include "d3d12_state.h"
class WrappedID3D12Device;
class D3D12ResourceManager;
@@ -165,9 +166,6 @@ public:
void CopyTex2DMSToArray(ID3D12Resource *destArray, ID3D12Resource *srcMS);
void CopyArrayToTex2DMS(ID3D12Resource *destMS, ID3D12Resource *srcArray, UINT selectedSlice);
ShaderDebug::State CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx,
DXBC::DXBCContainer *dxbc, const ShaderReflection &refl,
bytebuf *cbufData);
void CreateShaderGlobalState(ShaderDebug::GlobalState &global, DXBC::DXBCContainer *dxbc);
private:
@@ -215,3 +213,12 @@ private:
ID3D12GraphicsCommandListX *m_DebugList = NULL;
ID3D12CommandAllocator *m_DebugAlloc = NULL;
};
void MoveRootSignatureElementsToRegisterSpace(D3D12RootSignature &sig, uint32_t registerSpace,
D3D12DescriptorType type,
D3D12_SHADER_VISIBILITY visibility);
void AddDebugDescriptorToRenderState(WrappedID3D12Device *pDevice, D3D12RenderState &rs,
const PortableHandle &handle,
D3D12_DESCRIPTOR_HEAP_TYPE heapType, uint32_t sigElem,
std::set<ResourceId> &copiedHeaps);
+5 -72
View File
@@ -81,30 +81,9 @@ struct D3D12QuadOverdrawCallback : public D3D12DrawcallCallback
D3D12RootSignature modsig = sig->sig;
// make sure no other UAV tables overlap. We can't remove elements entirely because then the
// root signature indices wouldn't match up as expected.
// Instead move them into an unused space.
for(size_t i = 0; i < modsig.params.size(); i++)
{
if(modsig.params[i].ShaderVisibility == D3D12_SHADER_VISIBILITY_PIXEL ||
modsig.params[i].ShaderVisibility == D3D12_SHADER_VISIBILITY_ALL)
{
// use different register spaces for each just in case
UINT regSpace = modsig.maxSpaceIndex + modsig.params[i].ShaderVisibility;
if(modsig.params[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV)
{
modsig.params[i].Descriptor.RegisterSpace = regSpace;
}
else if(modsig.params[i].ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
{
for(size_t r = 0; r < modsig.params[i].ranges.size(); r++)
{
modsig.params[i].ranges[r].RegisterSpace = regSpace;
}
}
}
}
UINT regSpace = modsig.maxSpaceIndex + 1;
MoveRootSignatureElementsToRegisterSpace(modsig, regSpace, D3D12DescriptorType::UAV,
D3D12_SHADER_VISIBILITY_PIXEL);
D3D12_DESCRIPTOR_RANGE1 range;
range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
@@ -123,11 +102,6 @@ struct D3D12QuadOverdrawCallback : public D3D12DrawcallCallback
cache.sigElem = uint32_t(modsig.params.size() - 1);
std::vector<D3D12_ROOT_PARAMETER1> params;
params.resize(modsig.params.size());
for(size_t i = 0; i < params.size(); i++)
params[i] = modsig.params[i];
ID3DBlob *root = m_pDevice->GetShaderCache()->MakeRootSig(modsig);
hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(),
@@ -171,49 +145,8 @@ struct D3D12QuadOverdrawCallback : public D3D12DrawcallCallback
rs.pipe = GetResID(cache.pipe);
rs.graphics.rootsig = GetResID(cache.sig);
if(rs.graphics.sigelems.size() <= cache.sigElem)
rs.graphics.sigelems.resize(cache.sigElem + 1);
PortableHandle uav = m_UAV;
// if a CBV_SRV_UAV heap is already set, we need to copy our descriptor in
// if we haven't already. Otherwise we can set our own heap.
for(size_t i = 0; i < rs.heaps.size(); i++)
{
WrappedID3D12DescriptorHeap *h =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(rs.heaps[i]);
if(h->GetDesc().Type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
{
// use the last descriptor
D3D12_CPU_DESCRIPTOR_HANDLE dst = h->GetCPUDescriptorHandleForHeapStart();
dst.ptr += (h->GetDesc().NumDescriptors - 1) * sizeof(D3D12Descriptor);
if(m_CopiedHeaps.find(rs.heaps[i]) == m_CopiedHeaps.end())
{
WrappedID3D12DescriptorHeap *h2 =
m_pDevice->GetResourceManager()->GetCurrentAs<WrappedID3D12DescriptorHeap>(m_UAV.heap);
D3D12_CPU_DESCRIPTOR_HANDLE src = h2->GetCPUDescriptorHandleForHeapStart();
src.ptr += m_UAV.index * sizeof(D3D12Descriptor);
// can't do a copy because the src heap is CPU write-only (shader visible). So instead,
// create directly
D3D12Descriptor *srcDesc = (D3D12Descriptor *)src.ptr;
srcDesc->Create(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pDevice, dst);
m_CopiedHeaps.insert(rs.heaps[i]);
}
uav = ToPortableHandle(dst);
break;
}
}
if(uav.heap == m_UAV.heap)
rs.heaps.push_back(m_UAV.heap);
rs.graphics.sigelems[cache.sigElem] =
D3D12RenderState::SignatureElement(eRootTable, uav.heap, uav.index);
AddDebugDescriptorToRenderState(m_pDevice, rs, m_UAV, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cache.sigElem, m_CopiedHeaps);
// as we're changing the root signature, we need to reapply all elements,
// so just apply all state
@@ -117,22 +117,6 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather(
return false;
}
ShaderDebug::State D3D12DebugManager::CreateShaderDebugState(ShaderDebugTrace &trace, int quadIdx,
DXBC::DXBCContainer *dxbc,
const ShaderReflection &refl,
bytebuf *cbufData)
{
RDCUNIMPLEMENTED("CreateShaderDebugState not yet implemented for D3D12");
using namespace DXBCBytecode;
using namespace ShaderDebug;
State initialState = State(quadIdx, &trace, dxbc->GetReflection(), dxbc->GetDXBCByteCode());
initialState.Init();
return initialState;
}
void D3D12DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global,
DXBC::DXBCContainer *dxbc)
{
@@ -25,8 +25,11 @@
#include "dxbc_debug.h"
#include <algorithm>
#include "driver/dxgi/dxgi_common.h"
#include "maths/formatpacking.h"
#include "replay/replay_driver.h"
#include "dxbc_bytecode.h"
#include "dxbc_container.h"
using namespace DXBCBytecode;
@@ -3982,6 +3985,172 @@ State State::GetNext(GlobalState &global, DebugAPIWrapper *apiWrapper, State qua
return s;
}
void CreateShaderDebugStateAndTrace(ShaderDebug::State &initialState, ShaderDebugTrace &trace,
int quadIdx, DXBC::DXBCContainer *dxbc,
const ShaderReflection &refl, bytebuf *cbufData)
{
initialState = ShaderDebug::State(quadIdx, &trace, dxbc->GetReflection(), dxbc->GetDXBCByteCode());
size_t numInputs = dxbc->GetReflection()->InputSig.size();
size_t numOutputs = dxbc->GetReflection()->OutputSig.size();
int32_t maxReg = -1;
for(size_t i = 0; i < numInputs; i++)
maxReg = RDCMAX(maxReg, (int32_t)dxbc->GetReflection()->InputSig[i].regIndex);
bool inputCoverage = false;
// Check if the shader uses the coverage mask
for(size_t i = 0; i < dxbc->GetDXBCByteCode()->GetNumDeclarations(); i++)
{
const Declaration &decl = dxbc->GetDXBCByteCode()->GetDeclaration(i);
if(decl.declaration == OPCODE_DCL_INPUT && decl.operand.type == TYPE_INPUT_COVERAGE_MASK)
{
inputCoverage = true;
break;
}
}
// Add inputs to the shader trace
if(maxReg >= 0 || inputCoverage)
{
trace.inputs.resize(maxReg + 1 + (inputCoverage ? 1 : 0));
for(size_t i = 0; i < numInputs; i++)
{
const SigParameter &sig = dxbc->GetReflection()->InputSig[i];
ShaderVariable v;
v.name = StringFormat::Fmt("v%d (%s)", sig.regIndex, sig.semanticIdxName.c_str());
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
if(sig.compType == CompType::UInt)
v.type = VarType::UInt;
else if(sig.compType == CompType::SInt)
v.type = VarType::SInt;
if(trace.inputs[sig.regIndex].columns == 0)
trace.inputs[sig.regIndex] = v;
else
trace.inputs[sig.regIndex].columns = RDCMAX(trace.inputs[sig.regIndex].columns, v.columns);
}
// Put the coverage mask at the end
if(inputCoverage)
{
trace.inputs[maxReg + 1] = ShaderVariable("vCoverage", 0U, 0U, 0U, 0U);
trace.inputs[maxReg + 1].columns = 1;
}
}
// Add outputs to the shader state
uint32_t specialOutputs = 0;
maxReg = -1;
for(size_t i = 0; i < numOutputs; i++)
{
if(dxbc->GetReflection()->OutputSig[i].regIndex == ~0U)
specialOutputs++;
else
maxReg = RDCMAX(maxReg, (int32_t)dxbc->GetReflection()->OutputSig[i].regIndex);
}
if(maxReg >= 0 || specialOutputs > 0)
{
initialState.outputs.resize(maxReg + 1 + specialOutputs);
for(size_t i = 0; i < numOutputs; i++)
{
const SigParameter &sig = dxbc->GetReflection()->OutputSig[i];
if(sig.regIndex == ~0U)
continue;
ShaderVariable v;
v.name = StringFormat::Fmt("o%d (%s)", sig.regIndex, sig.semanticIdxName.c_str());
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
if(initialState.outputs[sig.regIndex].columns == 0)
initialState.outputs[sig.regIndex] = v;
else
initialState.outputs[sig.regIndex].columns =
RDCMAX(initialState.outputs[sig.regIndex].columns, v.columns);
}
int32_t outIdx = maxReg + 1;
for(size_t i = 0; i < numOutputs; i++)
{
const SigParameter &sig = dxbc->GetReflection()->OutputSig[i];
if(sig.regIndex != ~0U)
continue;
ShaderVariable v;
if(sig.systemValue == ShaderBuiltin::OutputControlPointIndex)
v.name = "vOutputControlPointID";
else if(sig.systemValue == ShaderBuiltin::DepthOutput)
v.name = "oDepth";
else if(sig.systemValue == ShaderBuiltin::DepthOutputLessEqual)
v.name = "oDepthLessEqual";
else if(sig.systemValue == ShaderBuiltin::DepthOutputGreaterEqual)
v.name = "oDepthGreaterEqual";
else if(sig.systemValue == ShaderBuiltin::MSAACoverage)
v.name = "oMask";
else if(sig.systemValue == ShaderBuiltin::StencilReference)
v.name = "oStencilRef";
else
{
RDCERR("Unhandled output: %s (%d)", sig.semanticName.c_str(), sig.systemValue);
continue;
}
v.rows = 1;
v.columns = sig.regChannelMask & 0x8 ? 4 : sig.regChannelMask & 0x4
? 3
: sig.regChannelMask & 0x2
? 2
: sig.regChannelMask & 0x1 ? 1 : 0;
initialState.outputs[outIdx++] = v;
}
}
// Fill constant buffers and add them to the trace
size_t numCBuffers = dxbc->GetReflection()->CBuffers.size();
trace.constantBlocks.resize(numCBuffers);
for(size_t i = 0; i < numCBuffers; i++)
{
rdcarray<ShaderVariable> vars;
// Fetch cbuffers into vars, which will be 'natural': structs with members, non merged vectors
StandardFillCBufferVariables(refl.constantBlocks[i].variables, vars,
cbufData[dxbc->GetReflection()->CBuffers[i].reg]);
FlattenVariables(refl.constantBlocks[i].variables, vars, trace.constantBlocks[i].members);
for(size_t c = 0; c < trace.constantBlocks[i].members.size(); c++)
{
trace.constantBlocks[i].members[c].name =
StringFormat::Fmt("cb%u[%u] (%s)", dxbc->GetReflection()->CBuffers[i].reg, (uint32_t)c,
trace.constantBlocks[i].members[c].name.c_str());
}
}
initialState.Init();
}
bool PromptDebugTimeout(uint32_t cycleCounter)
{
std::string msg = StringFormat::Fmt(
@@ -4288,6 +4457,50 @@ void FlattenVariables(const rdcarray<ShaderConstant> &constants,
FlattenVariables(constants, invars, outvars, "", 0);
}
void FillViewFmt(DXGI_FORMAT format, GlobalState::ViewFmt &viewFmt)
{
if(format != DXGI_FORMAT_UNKNOWN)
{
ResourceFormat fmt = MakeResourceFormat(format);
viewFmt.byteWidth = fmt.compByteWidth;
viewFmt.numComps = fmt.compCount;
viewFmt.fmt = fmt.compType;
if(format == DXGI_FORMAT_R11G11B10_FLOAT)
viewFmt.byteWidth = 11;
else if(format == DXGI_FORMAT_R10G10B10A2_UINT || format == DXGI_FORMAT_R10G10B10A2_UNORM)
viewFmt.byteWidth = 10;
}
}
void LookupSRVFormatFromShaderReflection(const DXBC::Reflection &reflection,
uint32_t shaderRegister, GlobalState::ViewFmt &viewFmt)
{
for(const DXBC::ShaderInputBind &bind : reflection.SRVs)
{
if(bind.reg == shaderRegister && bind.dimension == DXBC::ShaderInputBind::DIM_BUFFER &&
bind.retType < DXBC::RETURN_TYPE_MIXED && bind.retType != DXBC::RETURN_TYPE_UNKNOWN)
{
viewFmt.byteWidth = 4;
viewFmt.numComps = bind.numSamples;
if(bind.retType == DXBC::RETURN_TYPE_UNORM)
viewFmt.fmt = CompType::UNorm;
else if(bind.retType == DXBC::RETURN_TYPE_SNORM)
viewFmt.fmt = CompType::SNorm;
else if(bind.retType == DXBC::RETURN_TYPE_UINT)
viewFmt.fmt = CompType::UInt;
else if(bind.retType == DXBC::RETURN_TYPE_SINT)
viewFmt.fmt = CompType::SInt;
else
viewFmt.fmt = CompType::Float;
break;
}
}
}
}; // namespace ShaderDebug
#if ENABLED(ENABLE_UNIT_TESTS)
@@ -37,6 +37,7 @@ struct CBufferVariable;
}
class WrappedID3D11Device;
enum DXGI_FORMAT;
namespace ShaderDebug
{
@@ -185,6 +186,11 @@ void FlattenVariables(const rdcarray<ShaderConstant> &constants,
void FlattenVariables(const rdcarray<ShaderConstant> &constants,
const rdcarray<ShaderVariable> &invars, rdcarray<ShaderVariable> &outvars);
void FillViewFmt(DXGI_FORMAT format, GlobalState::ViewFmt &viewFmt);
void LookupSRVFormatFromShaderReflection(const DXBC::Reflection &reflection,
uint32_t shaderRegister, GlobalState::ViewFmt &viewFmt);
struct SampleGatherResourceData
{
DXBCBytecode::ResourceDimension dim;
@@ -317,4 +323,8 @@ private:
const ShaderDebugTrace *trace;
};
void CreateShaderDebugStateAndTrace(ShaderDebug::State &initialState, ShaderDebugTrace &trace,
int quadIdx, DXBC::DXBCContainer *dxbc,
const ShaderReflection &refl, bytebuf *cbufData);
}; // namespace ShaderDebug