From 9b141086c05ba5fc0b085cefd8eb912bcabe3a68 Mon Sep 17 00:00:00 2001 From: Steve Karolewics Date: Sat, 9 Nov 2019 17:19:58 -0800 Subject: [PATCH] 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. --- renderdoc/driver/d3d11/d3d11_debug.h | 3 - renderdoc/driver/d3d11/d3d11_shaderdebug.cpp | 211 +----------------- renderdoc/driver/d3d12/d3d12_debug.cpp | 107 ++++++++++ renderdoc/driver/d3d12/d3d12_debug.h | 13 +- renderdoc/driver/d3d12/d3d12_overlay.cpp | 77 +------ renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 16 -- renderdoc/driver/shaders/dxbc/dxbc_debug.cpp | 213 +++++++++++++++++++ renderdoc/driver/shaders/dxbc/dxbc_debug.h | 10 + 8 files changed, 354 insertions(+), 296 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 83456f6f0..428ed1c68 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -119,9 +119,6 @@ public: void PixelHistoryCopyPixel(CopyPixelParams ¶ms, 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); diff --git a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp index 9667ef91a..7ff50d2bc 100644 --- a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp +++ b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp @@ -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 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 &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++) { diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index cd363dd09..469e9b218 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -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 &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(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(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); +} diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 4612a4bab..afae80454 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -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 &copiedHeaps); diff --git a/renderdoc/driver/d3d12/d3d12_overlay.cpp b/renderdoc/driver/d3d12/d3d12_overlay.cpp index 48240b36a..8df7c5602 100644 --- a/renderdoc/driver/d3d12/d3d12_overlay.cpp +++ b/renderdoc/driver/d3d12/d3d12_overlay.cpp @@ -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 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(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(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 diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index b4dee758d..39ddcac82 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -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) { diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index 52743cc9f..9f0a2d0c4 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -25,8 +25,11 @@ #include "dxbc_debug.h" #include +#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 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 &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) diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.h b/renderdoc/driver/shaders/dxbc/dxbc_debug.h index 7dc8d7da5..bf1dbd46f 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.h @@ -37,6 +37,7 @@ struct CBufferVariable; } class WrappedID3D11Device; +enum DXGI_FORMAT; namespace ShaderDebug { @@ -185,6 +186,11 @@ void FlattenVariables(const rdcarray &constants, void FlattenVariables(const rdcarray &constants, const rdcarray &invars, rdcarray &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