From 99b578e5a34718c3e29337d1126d7302b98faf46 Mon Sep 17 00:00:00 2001 From: Steve Karolewics Date: Mon, 16 Dec 2019 22:33:05 -0800 Subject: [PATCH] Implement func to compute math intrinsics for D3D12 shader debugging --- renderdoc/driver/d3d12/d3d12_debug.cpp | 152 +++++++++++++++++++ renderdoc/driver/d3d12/d3d12_debug.h | 10 ++ renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 59 ++++++- 3 files changed, 219 insertions(+), 2 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index dd65731d0..0966f9dca 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -27,6 +27,7 @@ #include "data/resource.h" #include "driver/dx/official/d3dcompiler.h" #include "driver/dxgi/dxgi_common.h" +#include "driver/shaders/dxbc/dxbc_bytecode.h" #include "maths/formatpacking.h" #include "maths/matrix.h" #include "maths/vec.h" @@ -255,6 +256,14 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) rm->SetInternalResource(m_MeshRootSig); } + if(!CreateMathIntrinsicsResources()) + { + RDCERR("Failed to create resources for shader debugging math intrinsics"); + SAFE_RELEASE(m_MathIntrinsicsRootSig); + SAFE_RELEASE(m_MathIntrinsicsPso); + SAFE_RELEASE(m_MathIntrinsicsResultBuffer); + } + { rdcstr meshhlsl = GetEmbeddedResource(mesh_hlsl); @@ -372,6 +381,10 @@ D3D12DebugManager::~D3D12DebugManager() SAFE_RELEASE(m_MeshPS); SAFE_RELEASE(m_MeshRootSig); + SAFE_RELEASE(m_MathIntrinsicsRootSig); + SAFE_RELEASE(m_MathIntrinsicsPso); + SAFE_RELEASE(m_MathIntrinsicsResultBuffer); + SAFE_RELEASE(m_ArrayMSAARootSig); SAFE_RELEASE(m_FullscreenVS); @@ -396,6 +409,145 @@ D3D12DebugManager::~D3D12DebugManager() RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this); } +bool D3D12DebugManager::CreateMathIntrinsicsResources() +{ + rdcstr csProgram = + "RWStructuredBuffer outval : register(u0);\n" + "cbuffer srcOper : register(b0) { float4 inval; };\n" + "cbuffer srcInstr : register(b1) { uint operation; };\n"; + + // Assign constants to each supported instruction + csProgram += StringFormat::Fmt("static const uint OPCODE_RCP = %u;\n", DXBCBytecode::OPCODE_RCP); + csProgram += StringFormat::Fmt("static const uint OPCODE_RSQ = %u;\n", DXBCBytecode::OPCODE_RSQ); + csProgram += StringFormat::Fmt("static const uint OPCODE_EXP = %u;\n", DXBCBytecode::OPCODE_EXP); + csProgram += StringFormat::Fmt("static const uint OPCODE_LOG = %u;\n", DXBCBytecode::OPCODE_LOG); + csProgram += + StringFormat::Fmt("static const uint OPCODE_SINCOS = %u;\n", DXBCBytecode::OPCODE_SINCOS); + + csProgram += + "[numthreads(1, 1, 1)]\n" + "void main(){\n" + " switch(operation){\n" + " case OPCODE_RCP: outval[0] = rcp(inval); break;\n" + " case OPCODE_RSQ: outval[0] = rsqrt(inval); break;\n" + " case OPCODE_EXP: outval[0] = exp2(inval); break;\n" + " case OPCODE_LOG: outval[0] = log2(inval); break;\n" + " case OPCODE_SINCOS: sincos(inval, outval[0], outval[1]); break;\n" + " }\n}\n"; + + ID3DBlob *csBlob = NULL; + UINT flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS | D3DCOMPILE_DEBUG_NAME_FOR_SOURCE; + if(m_pDevice->GetShaderCache()->GetShaderBlob(csProgram.c_str(), "main", flags, "cs_5_0", + &csBlob) != "") + { + RDCERR("Failed to create shader to calculate math intrinsic"); + return false; + } + + D3D12RootSignature rootSig; + + // Constants param for the operation inputs + D3D12RootSignatureParameter constantParam; + constantParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + constantParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + constantParam.Constants.Num32BitValues = 4; // Input is 4 floats + constantParam.Constants.ShaderRegister = 0; + constantParam.Constants.RegisterSpace = 0; + rootSig.Parameters.push_back(constantParam); + + // Constants param for the opcode + constantParam.Constants.Num32BitValues = 1; + constantParam.Constants.ShaderRegister = 1; + constantParam.Constants.RegisterSpace = 0; + rootSig.Parameters.push_back(constantParam); + + // UAV param for the output + D3D12RootSignatureParameter uavParam; + uavParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; + uavParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + uavParam.Descriptor.ShaderRegister = 0; + uavParam.Descriptor.RegisterSpace = 0; + uavParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE; + rootSig.Parameters.push_back(uavParam); + + ID3DBlob *root = m_pDevice->GetShaderCache()->MakeRootSig(rootSig); + if(root == NULL) + { + RDCERR("Failed to create root signature for shader debugging"); + SAFE_RELEASE(csBlob); + return false; + } + HRESULT hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), + __uuidof(ID3D12RootSignature), + (void **)&m_MathIntrinsicsRootSig); + m_pDevice->InternalRef(); + SAFE_RELEASE(root); + if(FAILED(hr)) + { + RDCERR("Failed to create root signature for shader debugging HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(csBlob); + return false; + } + m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsRootSig); + + D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc; + psoDesc.pRootSignature = m_MathIntrinsicsRootSig; + psoDesc.CS.BytecodeLength = csBlob->GetBufferSize(); + psoDesc.CS.pShaderBytecode = csBlob->GetBufferPointer(); + psoDesc.NodeMask = 0; + psoDesc.CachedPSO.pCachedBlob = NULL; + psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + + hr = m_pDevice->CreateComputePipelineState(&psoDesc, __uuidof(ID3D12PipelineState), + (void **)&m_MathIntrinsicsPso); + m_pDevice->InternalRef(); + SAFE_RELEASE(csBlob); + if(FAILED(hr)) + { + RDCERR("Failed to create PSO for shader debugging HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(m_MathIntrinsicsRootSig); + return false; + } + m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsPso); + + // Create buffer to store computed result + D3D12_RESOURCE_DESC rdesc; + ZeroMemory(&rdesc, sizeof(D3D12_RESOURCE_DESC)); + rdesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + rdesc.Width = sizeof(float) * 8; // Output buffer is 2x float4 + rdesc.Height = 1; + rdesc.DepthOrArraySize = 1; + rdesc.MipLevels = 1; + rdesc.Format = DXGI_FORMAT_UNKNOWN; + rdesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + rdesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + rdesc.SampleDesc.Count = 1; + rdesc.SampleDesc.Quality = 0; + + D3D12_HEAP_PROPERTIES heapProps; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 1; + heapProps.VisibleNodeMask = 1; + + hr = m_pDevice->CreateCommittedResource( + &heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, + __uuidof(ID3D12Resource), (void **)&m_MathIntrinsicsResultBuffer); + m_pDevice->InternalRef(); + if(FAILED(hr)) + { + RDCERR("Failed to create buffer for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(m_MathIntrinsicsRootSig); + SAFE_RELEASE(m_MathIntrinsicsPso); + return false; + } + m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsResultBuffer); + + return true; +} + ID3D12Resource *D3D12DebugManager::MakeCBuffer(UINT64 size) { ID3D12Resource *ret; diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 589b311f1..f6bd76aba 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -141,6 +141,9 @@ public: D3D12_GPU_VIRTUAL_ADDRESS UploadConstants(const void *data, size_t size); ID3D12RootSignature *GetMeshRootSig() { return m_MeshRootSig; } + ID3D12RootSignature *GetMathIntrinsicsRootSig() { return m_MathIntrinsicsRootSig; } + ID3D12PipelineState *GetMathIntrinsicsPso() { return m_MathIntrinsicsPso; } + ID3D12Resource *GetMathIntrinsicsResultBuffer() { return m_MathIntrinsicsResultBuffer; } ID3D12GraphicsCommandListX *ResetDebugList(); void ResetDebugAlloc(); @@ -171,6 +174,8 @@ public: void CreateShaderGlobalState(ShaderDebug::GlobalState &global, DXBC::DXBCContainer *dxbc); private: + bool CreateMathIntrinsicsResources(); + WrappedID3D12Device *m_pDevice = NULL; // heaps @@ -194,6 +199,11 @@ private: ID3D12RootSignature *m_MeshRootSig = NULL; std::map m_CachedMeshPipelines; + // Shader debugging resources + ID3D12RootSignature *m_MathIntrinsicsRootSig = NULL; + ID3D12PipelineState *m_MathIntrinsicsPso = NULL; + ID3D12Resource *m_MathIntrinsicsResultBuffer = NULL; + // GetBufferData static const uint64_t m_ReadbackSize = 16 * 1024 * 1024; diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index ad94bca92..b5d900db6 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -96,8 +96,61 @@ bool D3D12DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod const ShaderVariable &input, ShaderVariable &output1, ShaderVariable &output2) { - RDCUNIMPLEMENTED("CalculateMathIntrinsic not yet implemented for D3D12"); - return false; + D3D12MarkerRegion region(m_pDevice->GetQueue()->GetReal(), "CalculateMathIntrinsic"); + + if(opcode != DXBCBytecode::OPCODE_RCP && opcode != DXBCBytecode::OPCODE_RSQ && + opcode != DXBCBytecode::OPCODE_EXP && opcode != DXBCBytecode::OPCODE_LOG && + opcode != DXBCBytecode::OPCODE_SINCOS) + { + // To support a new instruction, the shader created in + // D3D12DebugManager::CreateMathIntrinsicsResources will need updated + RDCERR("Unsupported instruction for CalculateMathIntrinsic: %u", opcode); + return false; + } + + // Create UAV to store the computed results + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; + ZeroMemory(&uavDesc, sizeof(D3D12_UNORDERED_ACCESS_VIEW_DESC)); + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.NumElements = 2; + uavDesc.Buffer.StructureByteStride = sizeof(float) * 4; + + ID3D12Resource *pResultBuffer = m_pDevice->GetDebugManager()->GetMathIntrinsicsResultBuffer(); + D3D12_CPU_DESCRIPTOR_HANDLE uav = m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV); + m_pDevice->CreateUnorderedAccessView(pResultBuffer, NULL, &uavDesc, uav); + + // Set root signature & sig params on command list, then execute the shader + ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); + m_pDevice->GetDebugManager()->SetDescriptorHeaps(cmdList, true, false); + cmdList->SetPipelineState(m_pDevice->GetDebugManager()->GetMathIntrinsicsPso()); + cmdList->SetComputeRootSignature(m_pDevice->GetDebugManager()->GetMathIntrinsicsRootSig()); + cmdList->SetComputeRoot32BitConstants(0, 4, &input.value.uv[0], 0); + cmdList->SetComputeRoot32BitConstants(1, 1, &opcode, 0); + cmdList->SetComputeRootUnorderedAccessView(2, pResultBuffer->GetGPUVirtualAddress()); + cmdList->Dispatch(1, 1, 1); + + HRESULT hr = cmdList->Close(); + if(FAILED(hr)) + { + RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); + return false; + } + + { + ID3D12CommandList *l = cmdList; + m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); + m_pDevice->GPUSync(); + } + + bytebuf results; + m_pDevice->GetDebugManager()->GetBufferData(pResultBuffer, 0, 0, results); + RDCASSERT(results.size() >= sizeof(uint32_t) * 8); + + memcpy(output1.value.uv, results.data(), sizeof(uint32_t) * 4); + memcpy(output2.value.uv, results.data() + 4, sizeof(uint32_t) * 4); + + return true; } ShaderVariable D3D12DebugAPIWrapper::GetSampleInfo(DXBCBytecode::OperandType type, @@ -647,6 +700,8 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( m_pDevice->GPUSync(); } + rs = prevState; + bytebuf sampleResult; m_pDevice->GetReplay()->GetTextureData(GetResID(pSampleResult), Subresource(), GetTextureDataParams(), sampleResult);