diff --git a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp index 4f33760e6..6e39e0c88 100644 --- a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp @@ -134,7 +134,7 @@ static bool IsShaderParameterVisible(DXBC::ShaderType shaderType, return false; } -static void FillViewFmtFromResourceFormat(DXGI_FORMAT format, GlobalState::ViewFmt &viewFmt) +static void FillViewFmtFromResourceFormat(DXGI_FORMAT format, ViewFmt &viewFmt) { RDCASSERT(format != DXGI_FORMAT_UNKNOWN); ResourceFormat fmt = MakeResourceFormat(format); @@ -190,315 +190,6 @@ static uint32_t GetSRVBufferStrideFromShaderMetadata(const DXIL::EntryPointInter return 0; } -static void FlattenSingleVariable(const rdcstr &cbufferName, uint32_t byteOffset, - const rdcstr &basename, const ShaderVariable &v, - rdcarray &outvars, - rdcarray &sourcevars) -{ - size_t outIdx = byteOffset / 16; - size_t outComp = (byteOffset % 16) / 4; - - if(v.RowMajor()) - outvars.resize(RDCMAX(outIdx + v.rows, outvars.size())); - else - outvars.resize(RDCMAX(outIdx + v.columns, outvars.size())); - - if(outvars[outIdx].columns > 0) - { - // if we already have a variable in this slot, just copy the data for this variable and add - // the source mapping. We should not overlap into the next register as that's not allowed. - memcpy(&outvars[outIdx].value.u32v[outComp], &v.value.u32v[0], sizeof(uint32_t) * v.columns); - uint32_t oldColumns = outvars[outIdx].columns; - uint32_t newColumns = (uint32_t)(outComp + v.columns); - uint32_t numColumns = RDCMAX(oldColumns, newColumns); - numColumns = RDCMIN(4U, numColumns); - outvars[outIdx].columns = (uint8_t)numColumns; - - SourceVariableMapping mapping; - mapping.name = basename; - mapping.type = v.type; - mapping.rows = v.rows; - mapping.columns = v.columns; - mapping.offset = byteOffset; - mapping.variables.resize(v.columns); - - for(int i = 0; i < v.columns; i++) - { - mapping.variables[i].type = DebugVariableType::Constant; - mapping.variables[i].name = StringFormat::Fmt("%s[%u]", cbufferName.c_str(), outIdx); - mapping.variables[i].component = uint16_t(outComp + i); - } - - sourcevars.push_back(mapping); - } - else - { - const uint32_t numRegisters = v.RowMajor() ? v.rows : v.columns; - for(uint32_t reg = 0; reg < numRegisters; reg++) - { - outvars[outIdx + reg].rows = 1; - outvars[outIdx + reg].type = v.type; - outvars[outIdx + reg].columns = v.columns + (uint8_t)outComp; - outvars[outIdx + reg].flags = v.flags; - } - - if(v.RowMajor()) - { - for(size_t ri = 0; ri < v.rows; ri++) - memcpy(&outvars[outIdx + ri].value.u32v[outComp], &v.value.u32v[ri * v.columns], - sizeof(uint32_t) * v.columns); - } - else - { - // if we have a matrix stored in column major order, we need to transpose it back so we can - // unroll it into vectors. - for(size_t ci = 0; ci < v.columns; ci++) - for(size_t ri = 0; ri < v.rows; ri++) - outvars[outIdx + ci].value.u32v[ri] = v.value.u32v[ri * v.columns + ci]; - } - - SourceVariableMapping mapping; - mapping.name = basename; - mapping.type = v.type; - mapping.rows = v.rows; - mapping.columns = v.columns; - mapping.offset = byteOffset; - mapping.variables.resize(v.rows * v.columns); - - RDCASSERT(outComp == 0 || v.rows == 1, outComp, v.rows); - - size_t i = 0; - for(uint8_t r = 0; r < v.rows; r++) - { - for(uint8_t c = 0; c < v.columns; c++) - { - size_t regIndex = outIdx + (v.RowMajor() ? r : c); - size_t compIndex = outComp + (v.RowMajor() ? c : r); - - mapping.variables[i].type = DebugVariableType::Constant; - mapping.variables[i].name = StringFormat::Fmt("%s[%zu]", cbufferName.c_str(), regIndex); - mapping.variables[i].component = uint16_t(compIndex); - i++; - } - } - - sourcevars.push_back(mapping); - } -} - -static void FlattenVariables(const rdcstr &cbufferName, const rdcarray &constants, - const rdcarray &invars, - rdcarray &outvars, const rdcstr &prefix, - uint32_t baseOffset, rdcarray &sourceVars) -{ - RDCASSERTEQUAL(constants.size(), invars.size()); - - for(size_t i = 0; i < constants.size(); i++) - { - const ShaderConstant &c = constants[i]; - const ShaderVariable &v = invars[i]; - - uint32_t byteOffset = baseOffset + c.byteOffset; - - rdcstr basename = prefix + rdcstr(v.name); - - if(v.type == VarType::Struct) - { - // check if this is an array of structs or not - if(c.type.elements == 1) - { - FlattenVariables(cbufferName, c.type.members, v.members, outvars, basename + ".", - byteOffset, sourceVars); - } - else - { - for(int m = 0; m < v.members.count(); m++) - { - FlattenVariables(cbufferName, c.type.members, v.members[m].members, outvars, - StringFormat::Fmt("%s[%zu].", basename.c_str(), m), - byteOffset + m * c.type.arrayByteStride, sourceVars); - } - } - } - else if(c.type.elements > 1 || (v.rows == 0 && v.columns == 0) || !v.members.empty()) - { - for(int m = 0; m < v.members.count(); m++) - { - FlattenSingleVariable(cbufferName, byteOffset + m * c.type.arrayByteStride, - StringFormat::Fmt("%s[%zu]", basename.c_str(), m), v.members[m], - outvars, sourceVars); - } - } - else - { - FlattenSingleVariable(cbufferName, byteOffset, basename, v, outvars, sourceVars); - } - } -} -static void AddCBufferToGlobalState(const DXIL::Program *program, GlobalState &global, - rdcarray &sourceVars, - const ShaderReflection &refl, const BindingSlot &slot, - bytebuf &cbufData) -{ - // Find the identifier - size_t numCBs = refl.constantBlocks.size(); - for(size_t i = 0; i < numCBs; ++i) - { - const ConstantBlock &cb = refl.constantBlocks[i]; - if(slot.registerSpace == (uint32_t)cb.fixedBindSetOrSpace && - slot.shaderRegister >= (uint32_t)cb.fixedBindNumber && - slot.shaderRegister < (uint32_t)(cb.fixedBindNumber + cb.bindArraySize)) - { - uint32_t arrayIndex = slot.shaderRegister - cb.fixedBindNumber; - - rdcarray &targetVars = - cb.bindArraySize > 1 ? global.constantBlocks[i].members[arrayIndex].members - : global.constantBlocks[i].members; - RDCASSERTMSG("Reassigning previously filled cbuffer", targetVars.empty()); - - ConstantBlockReference constantBlockRef = {i, arrayIndex}; - global.constantBlocksDatas[constantBlockRef] = cbufData; - rdcstr resName = Debugger::GetResourceReferenceName(program, ResourceClass::CBuffer, slot); - global.constantBlocks[i].name = resName; - - SourceVariableMapping cbSourceMapping; - cbSourceMapping.name = refl.constantBlocks[i].name; - cbSourceMapping.variables.push_back( - DebugVariableReference(DebugVariableType::Constant, global.constantBlocks[i].name)); - sourceVars.push_back(cbSourceMapping); - - rdcstr identifierPrefix = global.constantBlocks[i].name; - rdcstr variablePrefix = refl.constantBlocks[i].name; - if(cb.bindArraySize > 1) - { - identifierPrefix = - StringFormat::Fmt("%s[%u]", global.constantBlocks[i].name.c_str(), arrayIndex); - variablePrefix = StringFormat::Fmt("%s[%u]", refl.constantBlocks[i].name.c_str(), arrayIndex); - - // The above sourceVar is for the logical identifier, and FlattenVariables adds the - // individual elements of the constant buffer. For CB arrays, add an extra source - // var for the CB array index - SourceVariableMapping cbArrayMapping; - global.constantBlocks[i].members[arrayIndex].name = StringFormat::Fmt("[%u]", arrayIndex); - cbArrayMapping.name = variablePrefix; - cbArrayMapping.variables.push_back( - DebugVariableReference(DebugVariableType::Constant, identifierPrefix)); - sourceVars.push_back(cbArrayMapping); - } - const rdcarray &constants = - (cb.bindArraySize > 1) ? refl.constantBlocks[i].variables[0].type.members - : refl.constantBlocks[i].variables; - - rdcarray vars; - StandardFillCBufferVariables(refl.resourceId, constants, vars, cbufData); - FlattenVariables(identifierPrefix, constants, vars, targetVars, variablePrefix + ".", 0, - sourceVars); - for(size_t c = 0; c < targetVars.size(); c++) - targetVars[c].name = StringFormat::Fmt("[%u]", (uint32_t)c); - - return; - } - } -} - -void FetchConstantBufferData(WrappedID3D12Device *device, const DXIL::Program *program, - const D3D12RenderState::RootSignature &rootsig, - const ShaderReflection &refl, GlobalState &global, - rdcarray &sourceVars) -{ - WrappedID3D12RootSignature *pD3D12RootSig = - device->GetResourceManager()->GetCurrentAs(rootsig.rootsig); - const DXBC::ShaderType shaderType = program->GetShaderType(); - - size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), rootsig.sigelems.size()); - for(size_t i = 0; i < numParams; i++) - { - const D3D12RootSignatureParameter &rootSigParam = pD3D12RootSig->sig.Parameters[i]; - const D3D12RenderState::SignatureElement &element = rootsig.sigelems[i]; - if(IsShaderParameterVisible(shaderType, rootSigParam.ShaderVisibility)) - { - if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS && - element.type == eRootConst) - { - BindingSlot slot(rootSigParam.Constants.ShaderRegister, rootSigParam.Constants.RegisterSpace); - UINT sizeBytes = sizeof(uint32_t) * RDCMIN(rootSigParam.Constants.Num32BitValues, - (UINT)element.constants.size()); - bytebuf cbufData((const byte *)element.constants.data(), sizeBytes); - AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData); - } - else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV && element.type == eRootCBV) - { - BindingSlot slot(rootSigParam.Descriptor.ShaderRegister, - rootSigParam.Descriptor.RegisterSpace); - ID3D12Resource *cbv = device->GetResourceManager()->GetCurrentAs(element.id); - bytebuf cbufData; - device->GetDebugManager()->GetBufferData(cbv, element.offset, 0, cbufData); - AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData); - } - else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && - element.type == eRootTable) - { - UINT prevTableOffset = 0; - WrappedID3D12DescriptorHeap *heap = - device->GetResourceManager()->GetCurrentAs(element.id); - - size_t numRanges = rootSigParam.ranges.size(); - for(size_t r = 0; r < numRanges; r++) - { - // For this traversal we only care about CBV descriptor ranges, but we still need to - // calculate the table offsets in case a descriptor table has a combination of - // different range types - const D3D12_DESCRIPTOR_RANGE1 &range = rootSigParam.ranges[r]; - - UINT offset = range.OffsetInDescriptorsFromTableStart; - if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) - offset = prevTableOffset; - - D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; - desc += element.offset; - desc += offset; - - UINT numDescriptors = range.NumDescriptors; - if(numDescriptors == UINT_MAX) - { - // Find out how many descriptors are left after - numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset; - - // TODO: Look up the bind point in the D3D12 state to try to get - // a better guess at the number of descriptors - } - - prevTableOffset = offset + numDescriptors; - - if(range.RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_CBV) - continue; - - BindingSlot slot(range.BaseShaderRegister, range.RegisterSpace); - - bytebuf cbufData; - for(UINT n = 0; n < numDescriptors; ++n, ++slot.shaderRegister) - { - const D3D12_CONSTANT_BUFFER_VIEW_DESC &cbv = desc->GetCBV(); - ResourceId resId; - uint64_t byteOffset = 0; - WrappedID3D12Resource::GetResIDFromAddr(cbv.BufferLocation, resId, byteOffset); - ID3D12Resource *pCbvResource = - device->GetResourceManager()->GetCurrentAs(resId); - cbufData.clear(); - - if(cbv.SizeInBytes > 0) - device->GetDebugManager()->GetBufferData(pCbvResource, byteOffset, cbv.SizeInBytes, - cbufData); - AddCBufferToGlobalState(program, global, sourceVars, refl, slot, cbufData); - - desc++; - } - } - } - } - } -} - InterpolationMode GetInterpolationModeForInputParam(const SigParameter &sig, const rdcarray &stageInputSig, const DXIL::Program *program) @@ -568,34 +259,458 @@ void GetInterpolationModeForInputParams(const rdcarray &inputSig, } } -D3D12APIWrapper::D3D12APIWrapper(WrappedID3D12Device *device, const DXIL::Program &dxilProgram, - GlobalState &globalState, uint32_t eventId) +D3D12APIWrapper::D3D12APIWrapper(WrappedID3D12Device *device, const DXIL::Program *dxilProgram, + const ShaderReflection &refl, uint32_t eventId, + const rdcarray &inputSig) : m_Device(device), - m_EntryPointInterface(dxilProgram.GetEntryPointInterface()), - m_GlobalState(globalState), - m_ShaderType(dxilProgram.GetShaderType()), - m_EventId(eventId) + m_EntryPointInterface(dxilProgram->GetEntryPointInterface()), + m_ShaderType(dxilProgram->GetShaderType()), + m_EventId(eventId), + m_Program(dxilProgram), + m_Reflection(refl) { + // Create the storage layout for the constant buffers + // The constant buffer data and details are filled in outside of this method + size_t count = refl.constantBlocks.size(); + m_ConstantBlocks.resize(count); + for(uint32_t i = 0; i < count; i++) + { + m_ConstantBlocks[i].type = VarType::ConstantBlock; + const ConstantBlock &cb = m_Reflection.constantBlocks[i]; + uint32_t bindCount = cb.bindArraySize; + if(bindCount > 1) + { + // Create nested structure for constant buffer array + m_ConstantBlocks[i].members.resize(bindCount); + } + } + + // Add inputs to the shader trace + const rdcarray &inputs = m_EntryPointInterface->inputs; + + const uint32_t countInParams = (uint32_t)inputs.size(); + if(countInParams) + { + // Make fake ShaderVariable struct to hold all the inputs + ShaderVariable &inStruct = m_InputPlaceholder; + inStruct.name = DXIL_FAKE_INPUT_STRUCT_NAME; + inStruct.rows = 0; + inStruct.columns = 0; + inStruct.type = VarType::Struct; + inStruct.members.resize(countInParams); + + for(uint32_t i = 0; i < countInParams; ++i) + { + const EntryPointInterface::Signature &sig = inputs[i]; + + ShaderVariable &v = inStruct.members[i]; + + // Get the name from the DXBC reflection + SigParameter sigParam; + if(FindSigParameter(inputSig, sig, sigParam)) + { + v.name = sigParam.semanticIdxName; + } + else + { + v.name = sig.name; + } + v.rows = (uint8_t)sig.rows; + v.columns = (uint8_t)sig.cols; + v.type = VarTypeForComponentType(sig.type); + if(v.rows <= 1) + { + v.rows = 1; + } + else + { + v.members.resize(v.rows); + for(uint32_t r = 0; r < v.rows; r++) + { + v.members[r].rows = 1; + v.members[r].columns = (uint8_t)sig.cols; + v.members[r].type = v.type; + v.members[r].name = StringFormat::Fmt("[%u]", r); + } + } + + SourceVariableMapping inputMapping; + inputMapping.name = v.name; + inputMapping.type = v.type; + inputMapping.rows = sig.rows; + inputMapping.columns = sig.cols; + inputMapping.variables.reserve(sig.cols); + inputMapping.signatureIndex = i; + if(v.rows <= 1) + { + inputMapping.variables.reserve(sig.cols); + for(uint32_t c = 0; c < sig.cols; ++c) + { + DebugVariableReference ref; + ref.type = DebugVariableType::Input; + ref.name = inStruct.name + "." + v.name; + ref.component = c; + inputMapping.variables.push_back(ref); + } + } + else + { + DebugVariableReference ref; + ref.type = DebugVariableType::Input; + ref.name = inStruct.name + "." + v.name; + inputMapping.variables.push_back(ref); + } + m_SourceVars.push_back(inputMapping); + } + + // Make a single source variable mapping for the whole input struct + SourceVariableMapping inputMapping; + inputMapping.name = inStruct.name; + inputMapping.type = VarType::Struct; + inputMapping.rows = 0; + inputMapping.columns = 0; + inputMapping.variables.resize(1); + inputMapping.variables.push_back(DebugVariableReference(DebugVariableType::Input, inStruct.name)); + m_SourceVars.push_back(inputMapping); + } } D3D12APIWrapper::~D3D12APIWrapper() { - // if we replayed to before the action for fetching some UAVs - // replay back to after the action to keep the state consistent. - if(m_DidReplay) + ResetReplay(); +} + +void D3D12APIWrapper::ResetReplay() +{ + if(!m_ResourcesDirty) { - D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "ResetReplay"); // replay the action to get back to 'normal' state for this event + D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "ResetReplay"); m_Device->ReplayLog(0, m_EventId, eReplay_OnlyDraw); + m_ResourcesDirty = true; } } -void D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) +void D3D12APIWrapper::PrepareReplayForResources() { + // if the resources are dirty, replay back to right before it. + if(m_ResourcesDirty) + { + D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "un-dirtying resources"); + m_Device->ReplayLog(0, m_EventId, eReplay_WithoutDraw); + m_ResourcesDirty = false; + } +} + +void D3D12APIWrapper::FlattenSingleVariable(const rdcstr &cbufferName, uint32_t byteOffset, + const rdcstr &basename, const ShaderVariable &v, + rdcarray &outvars) +{ + size_t outIdx = byteOffset / 16; + size_t outComp = (byteOffset % 16) / 4; + + if(v.RowMajor()) + outvars.resize(RDCMAX(outIdx + v.rows, outvars.size())); + else + outvars.resize(RDCMAX(outIdx + v.columns, outvars.size())); + + if(outvars[outIdx].columns > 0) + { + // if we already have a variable in this slot, just copy the data for this variable and add + // the source mapping. We should not overlap into the next register as that's not allowed. + memcpy(&outvars[outIdx].value.u32v[outComp], &v.value.u32v[0], sizeof(uint32_t) * v.columns); + uint32_t oldColumns = outvars[outIdx].columns; + uint32_t newColumns = (uint32_t)(outComp + v.columns); + uint32_t numColumns = RDCMAX(oldColumns, newColumns); + numColumns = RDCMIN(4U, numColumns); + outvars[outIdx].columns = (uint8_t)numColumns; + + SourceVariableMapping mapping; + mapping.name = basename; + mapping.type = v.type; + mapping.rows = v.rows; + mapping.columns = v.columns; + mapping.offset = byteOffset; + mapping.variables.resize(v.columns); + + for(int i = 0; i < v.columns; i++) + { + mapping.variables[i].type = DebugVariableType::Constant; + mapping.variables[i].name = StringFormat::Fmt("%s[%u]", cbufferName.c_str(), outIdx); + mapping.variables[i].component = uint16_t(outComp + i); + } + + m_SourceVars.push_back(mapping); + } + else + { + const uint32_t numRegisters = v.RowMajor() ? v.rows : v.columns; + for(uint32_t reg = 0; reg < numRegisters; reg++) + { + outvars[outIdx + reg].rows = 1; + outvars[outIdx + reg].type = v.type; + outvars[outIdx + reg].columns = v.columns + (uint8_t)outComp; + outvars[outIdx + reg].flags = v.flags; + } + + if(v.RowMajor()) + { + for(size_t ri = 0; ri < v.rows; ri++) + memcpy(&outvars[outIdx + ri].value.u32v[outComp], &v.value.u32v[ri * v.columns], + sizeof(uint32_t) * v.columns); + } + else + { + // if we have a matrix stored in column major order, we need to transpose it back so we + // can unroll it into vectors. + for(size_t ci = 0; ci < v.columns; ci++) + for(size_t ri = 0; ri < v.rows; ri++) + outvars[outIdx + ci].value.u32v[ri] = v.value.u32v[ri * v.columns + ci]; + } + + SourceVariableMapping mapping; + mapping.name = basename; + mapping.type = v.type; + mapping.rows = v.rows; + mapping.columns = v.columns; + mapping.offset = byteOffset; + mapping.variables.resize(v.rows * v.columns); + + RDCASSERT(outComp == 0 || v.rows == 1, outComp, v.rows); + + size_t i = 0; + for(uint8_t r = 0; r < v.rows; r++) + { + for(uint8_t c = 0; c < v.columns; c++) + { + size_t regIndex = outIdx + (v.RowMajor() ? r : c); + size_t compIndex = outComp + (v.RowMajor() ? c : r); + + mapping.variables[i].type = DebugVariableType::Constant; + mapping.variables[i].name = StringFormat::Fmt("%s[%zu]", cbufferName.c_str(), regIndex); + mapping.variables[i].component = uint16_t(compIndex); + i++; + } + } + + m_SourceVars.push_back(mapping); + } +} + +void D3D12APIWrapper::FlattenVariables(const rdcstr &cbufferName, + const rdcarray &constants, + const rdcarray &invars, + rdcarray &outvars, const rdcstr &prefix, + uint32_t baseOffset) +{ + RDCASSERTEQUAL(constants.size(), invars.size()); + + for(size_t i = 0; i < constants.size(); i++) + { + const ShaderConstant &c = constants[i]; + const ShaderVariable &v = invars[i]; + + uint32_t byteOffset = baseOffset + c.byteOffset; + + rdcstr basename = prefix + rdcstr(v.name); + + if(v.type == VarType::Struct) + { + // check if this is an array of structs or not + if(c.type.elements == 1) + { + FlattenVariables(cbufferName, c.type.members, v.members, outvars, basename + ".", byteOffset); + } + else + { + for(int m = 0; m < v.members.count(); m++) + { + FlattenVariables(cbufferName, c.type.members, v.members[m].members, outvars, + StringFormat::Fmt("%s[%zu].", basename.c_str(), m), + byteOffset + m * c.type.arrayByteStride); + } + } + } + else if(c.type.elements > 1 || (v.rows == 0 && v.columns == 0) || !v.members.empty()) + { + for(int m = 0; m < v.members.count(); m++) + { + FlattenSingleVariable(cbufferName, byteOffset + m * c.type.arrayByteStride, + StringFormat::Fmt("%s[%zu]", basename.c_str(), m), v.members[m], + outvars); + } + } + else + { + FlattenSingleVariable(cbufferName, byteOffset, basename, v, outvars); + } + } +} + +void D3D12APIWrapper::FetchConstantBufferData(const D3D12RenderState::RootSignature &rootsig) +{ + WrappedID3D12RootSignature *pD3D12RootSig = + m_Device->GetResourceManager()->GetCurrentAs(rootsig.rootsig); + const DXBC::ShaderType shaderType = m_Program->GetShaderType(); + + size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), rootsig.sigelems.size()); + for(size_t i = 0; i < numParams; i++) + { + const D3D12RootSignatureParameter &rootSigParam = pD3D12RootSig->sig.Parameters[i]; + const D3D12RenderState::SignatureElement &element = rootsig.sigelems[i]; + if(IsShaderParameterVisible(shaderType, rootSigParam.ShaderVisibility)) + { + if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS && + element.type == eRootConst) + { + BindingSlot slot(rootSigParam.Constants.ShaderRegister, rootSigParam.Constants.RegisterSpace); + UINT sizeBytes = sizeof(uint32_t) * RDCMIN(rootSigParam.Constants.Num32BitValues, + (UINT)element.constants.size()); + bytebuf cbufData((const byte *)element.constants.data(), sizeBytes); + AddCBufferToGlobalState(slot, cbufData); + } + else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_CBV && element.type == eRootCBV) + { + BindingSlot slot(rootSigParam.Descriptor.ShaderRegister, + rootSigParam.Descriptor.RegisterSpace); + ID3D12Resource *cbv = + m_Device->GetResourceManager()->GetCurrentAs(element.id); + bytebuf cbufData; + m_Device->GetDebugManager()->GetBufferData(cbv, element.offset, 0, cbufData); + AddCBufferToGlobalState(slot, cbufData); + } + else if(rootSigParam.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && + element.type == eRootTable) + { + UINT prevTableOffset = 0; + WrappedID3D12DescriptorHeap *heap = + m_Device->GetResourceManager()->GetCurrentAs(element.id); + + size_t numRanges = rootSigParam.ranges.size(); + for(size_t r = 0; r < numRanges; r++) + { + // For this traversal we only care about CBV descriptor ranges, but we still need to + // calculate the table offsets in case a descriptor table has a combination of + // different range types + const D3D12_DESCRIPTOR_RANGE1 &range = rootSigParam.ranges[r]; + + UINT offset = range.OffsetInDescriptorsFromTableStart; + if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + offset = prevTableOffset; + + D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; + desc += element.offset; + desc += offset; + + UINT numDescriptors = range.NumDescriptors; + if(numDescriptors == UINT_MAX) + { + // Find out how many descriptors are left after + numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset; + + // TODO: Look up the bind point in the D3D12 state to try to get + // a better guess at the number of descriptors + } + + prevTableOffset = offset + numDescriptors; + + if(range.RangeType != D3D12_DESCRIPTOR_RANGE_TYPE_CBV) + continue; + + BindingSlot slot(range.BaseShaderRegister, range.RegisterSpace); + + bytebuf cbufData; + for(UINT n = 0; n < numDescriptors; ++n, ++slot.shaderRegister) + { + const D3D12_CONSTANT_BUFFER_VIEW_DESC &cbv = desc->GetCBV(); + ResourceId resId; + uint64_t byteOffset = 0; + WrappedID3D12Resource::GetResIDFromAddr(cbv.BufferLocation, resId, byteOffset); + ID3D12Resource *pCbvResource = + m_Device->GetResourceManager()->GetCurrentAs(resId); + cbufData.clear(); + + if(cbv.SizeInBytes > 0) + m_Device->GetDebugManager()->GetBufferData(pCbvResource, byteOffset, cbv.SizeInBytes, + cbufData); + AddCBufferToGlobalState(slot, cbufData); + + desc++; + } + } + } + } + } +} + +void D3D12APIWrapper::AddCBufferToGlobalState(const BindingSlot &slot, bytebuf &cbufData) +{ + // Find the identifier + size_t numCBs = m_Reflection.constantBlocks.size(); + for(size_t i = 0; i < numCBs; ++i) + { + const ConstantBlock &cb = m_Reflection.constantBlocks[i]; + if(slot.registerSpace == (uint32_t)cb.fixedBindSetOrSpace && + slot.shaderRegister >= (uint32_t)cb.fixedBindNumber && + slot.shaderRegister < (uint32_t)(cb.fixedBindNumber + cb.bindArraySize)) + { + uint32_t arrayIndex = slot.shaderRegister - cb.fixedBindNumber; + + rdcarray &targetVars = cb.bindArraySize > 1 + ? m_ConstantBlocks[i].members[arrayIndex].members + : m_ConstantBlocks[i].members; + RDCASSERTMSG("Reassigning previously filled cbuffer", targetVars.empty()); + + ConstantBlockReference constantBlockRef = {i, arrayIndex}; + m_ConstantBlocksDatas[constantBlockRef] = cbufData; + rdcstr resName = Debugger::GetResourceReferenceName(m_Program, ResourceClass::CBuffer, slot); + m_ConstantBlocks[i].name = resName; + + SourceVariableMapping cbSourceMapping; + cbSourceMapping.name = m_Reflection.constantBlocks[i].name; + cbSourceMapping.variables.push_back( + DebugVariableReference(DebugVariableType::Constant, m_ConstantBlocks[i].name)); + m_SourceVars.push_back(cbSourceMapping); + + rdcstr identifierPrefix = m_ConstantBlocks[i].name; + rdcstr variablePrefix = m_Reflection.constantBlocks[i].name; + if(cb.bindArraySize > 1) + { + identifierPrefix = StringFormat::Fmt("%s[%u]", m_ConstantBlocks[i].name.c_str(), arrayIndex); + variablePrefix = + StringFormat::Fmt("%s[%u]", m_Reflection.constantBlocks[i].name.c_str(), arrayIndex); + + // The above sourceVar is for the logical identifier, and FlattenVariables adds the + // individual elements of the constant buffer. For CB arrays, add an extra source + // var for the CB array index + SourceVariableMapping cbArrayMapping; + m_ConstantBlocks[i].members[arrayIndex].name = StringFormat::Fmt("[%u]", arrayIndex); + cbArrayMapping.name = variablePrefix; + cbArrayMapping.variables.push_back( + DebugVariableReference(DebugVariableType::Constant, identifierPrefix)); + m_SourceVars.push_back(cbArrayMapping); + } + const rdcarray &constants = + (cb.bindArraySize > 1) ? m_Reflection.constantBlocks[i].variables[0].type.members + : m_Reflection.constantBlocks[i].variables; + + rdcarray vars; + StandardFillCBufferVariables(m_Reflection.resourceId, constants, vars, cbufData); + FlattenVariables(identifierPrefix, constants, vars, targetVars, variablePrefix + ".", 0); + for(size_t c = 0; c < targetVars.size(); c++) + targetVars[c].name = StringFormat::Fmt("[%u]", (uint32_t)c); + + return; + } + } +} + +SRVData &D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) +{ + SRVData &srvData = m_SRVs[slot]; if(resDescriptor) { D3D12ResourceManager *rm = m_Device->GetResourceManager(); - DXILDebug::GlobalState::SRVData &srvData = m_GlobalState.srvs[slot]; ResourceId srvId = resDescriptor->GetResResourceId(); ID3D12Resource *pResource = rm->GetCurrentAs(srvId); if(pResource) @@ -632,10 +747,14 @@ void D3D12APIWrapper::FetchSRV(const D3D12Descriptor *resDescriptor, const Bindi // Textures are sampled via a pixel shader, so there's no need to copy their data } } + return srvData; } -void D3D12APIWrapper::FetchSRV(const BindingSlot &slot) +SRVData &D3D12APIWrapper::FetchSRV(const BindingSlot &slot) { + // the resources might be dirty from side-effects, replay back to right before it. + PrepareReplayForResources(); + // Direct access resource if(slot.heapType != DXDebug::HeapDescriptorType::NoHeap) { @@ -680,11 +799,11 @@ void D3D12APIWrapper::FetchSRV(const BindingSlot &slot) if(param.Descriptor.ShaderRegister == slot.shaderRegister && param.Descriptor.RegisterSpace == slot.registerSpace) { + SRVData &srvData = m_SRVs[slot]; // Found the requested SRV ID3D12Resource *pResource = rm->GetCurrentAs(element.id); if(pResource) { - DXILDebug::GlobalState::SRVData &srvData = m_GlobalState.srvs[slot]; D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); // DXC allows root buffers to have a stride of up to 16 bytes in the shader, which @@ -713,7 +832,7 @@ void D3D12APIWrapper::FetchSRV(const BindingSlot &slot) srvData.data); } } - return; + return srvData; } } else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && @@ -767,19 +886,20 @@ void D3D12APIWrapper::FetchSRV(const BindingSlot &slot) RDCERR("Couldn't find root signature parameter corresponding to SRV %u in space %u", slot.shaderRegister, slot.registerSpace); - return; + return m_SRVs[slot]; } RDCERR("No root signature bound, couldn't identify SRV %u in space %u", slot.shaderRegister, slot.registerSpace); + return m_SRVs[slot]; } -void D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) +UAVData &D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot) { + UAVData &uavData = m_UAVs[slot]; if(resDescriptor) { D3D12ResourceManager *rm = m_Device->GetResourceManager(); - DXILDebug::GlobalState::UAVData &uavData = m_GlobalState.uavs[slot]; ResourceId uavId = resDescriptor->GetResResourceId(); ID3D12Resource *pResource = rm->GetCurrentAs(uavId); @@ -825,18 +945,13 @@ void D3D12APIWrapper::FetchUAV(const D3D12Descriptor *resDescriptor, const Bindi } } } + return uavData; } -void D3D12APIWrapper::FetchUAV(const BindingSlot &slot) +UAVData &D3D12APIWrapper::FetchUAV(const BindingSlot &slot) { - // if the UAV might be dirty from side-effects from the action, replay back to right - // before it. - if(!m_DidReplay) - { - D3D12MarkerRegion region(m_Device->GetQueue()->GetReal(), "un-dirtying resources"); - m_Device->ReplayLog(0, m_EventId, eReplay_WithoutDraw); - m_DidReplay = true; - } + // the resources might be dirty from side-effects, replay back to right before it. + PrepareReplayForResources(); // Direct access resource if(slot.heapType != DXDebug::HeapDescriptorType::NoHeap) @@ -884,10 +999,10 @@ void D3D12APIWrapper::FetchUAV(const BindingSlot &slot) { // Found the requested UAV ID3D12Resource *pResource = rm->GetCurrentAs(element.id); + UAVData &uavData = m_UAVs[slot]; if(pResource) { - DXILDebug::GlobalState::UAVData &uavData = m_GlobalState.uavs[slot]; D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); // DXC allows root buffers to have a stride of up to 16 bytes in the shader, which // means encoding the byte offset into the first element here is wrong without @@ -918,7 +1033,7 @@ void D3D12APIWrapper::FetchUAV(const BindingSlot &slot) } } - return; + return uavData; } } else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && @@ -972,11 +1087,54 @@ void D3D12APIWrapper::FetchUAV(const BindingSlot &slot) RDCERR("Couldn't find root signature parameter corresponding to UAV %u in space %u", slot.shaderRegister, slot.registerSpace); - return; + return m_UAVs[slot]; } RDCERR("No root signature bound, couldn't identify UAV %u in space %u", slot.shaderRegister, slot.registerSpace); + return m_UAVs[slot]; +} + +bool D3D12APIWrapper::IsSRVCached(const BindingSlot &slot) +{ + SCOPED_READLOCK(m_SRVsLock); + return m_SRVs.find(slot) != m_SRVs.end(); +} + +const SRVData &D3D12APIWrapper::GetSRVData(const BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_SRVsLock); + auto it = m_SRVs.find(slot); + if(it != m_SRVs.end()) + return it->second; + } + + { + SCOPED_WRITELOCK(m_SRVsLock); + return FetchSRV(slot); + } +} + +bool D3D12APIWrapper::IsUAVCached(const BindingSlot &slot) +{ + SCOPED_READLOCK(m_UAVsLock); + return m_UAVs.find(slot) != m_UAVs.end(); +} + +const UAVData &D3D12APIWrapper::GetUAVData(const BindingSlot &slot) +{ + { + SCOPED_READLOCK(m_UAVsLock); + auto it = m_UAVs.find(slot); + if(it != m_UAVs.end()) + return it->second; + } + + { + SCOPED_WRITELOCK(m_UAVsLock); + return FetchUAV(slot); + } } bool D3D12APIWrapper::CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, @@ -1051,7 +1209,7 @@ bool D3D12APIWrapper::CalculateSampleGather( ShaderVariable D3D12APIWrapper::GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, uint32_t mipLevel, - const DXBC::ShaderType shaderType, int &dim) + const DXBC::ShaderType shaderType, int &dim) const { D3D12_DESCRIPTOR_RANGE_TYPE descType; switch(resClass) @@ -1069,7 +1227,8 @@ ShaderVariable D3D12APIWrapper::GetResourceInfo(DXIL::ResourceClass resClass, ShaderVariable D3D12APIWrapper::GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - const DXBC::ShaderType shaderType, const char *opString) + const DXBC::ShaderType shaderType, + const char *opString) const { D3D12_DESCRIPTOR_RANGE_TYPE descType; switch(resClass) @@ -1086,12 +1245,12 @@ ShaderVariable D3D12APIWrapper::GetSampleInfo(DXIL::ResourceClass resClass, } ShaderVariable D3D12APIWrapper::GetRenderTargetSampleInfo(const DXBC::ShaderType shaderType, - const char *opString) + const char *opString) const { return D3D12ShaderDebug::GetRenderTargetSampleInfo(m_Device, shaderType, opString); } -ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) +ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const { const HeapDescriptorType heapType = slot.heapType; RDCASSERT(heapType != HeapDescriptorType::NoHeap); @@ -1124,7 +1283,7 @@ ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::B if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) srvDesc = MakeSRVDesc(pResource->GetDesc()); - GlobalState::ViewFmt viewFmt; + ViewFmt viewFmt; if(srvDesc.Format != DXGI_FORMAT_UNKNOWN) { resRefInfo.srvData.dim = @@ -1189,7 +1348,7 @@ ResourceReferenceInfo D3D12APIWrapper::GetResourceReferenceInfo(const DXDebug::B } ShaderDirectAccess D3D12APIWrapper::GetShaderDirectAccess(DescriptorType type, - const DXDebug::BindingSlot &slot) + const DXDebug::BindingSlot &slot) const { const HeapDescriptorType heapType = slot.heapType; RDCASSERT(heapType != HeapDescriptorType::NoHeap); diff --git a/renderdoc/driver/d3d12/d3d12_dxil_debug.h b/renderdoc/driver/d3d12/d3d12_dxil_debug.h index 280eb8e0a..326559a82 100644 --- a/renderdoc/driver/d3d12/d3d12_dxil_debug.h +++ b/renderdoc/driver/d3d12/d3d12_dxil_debug.h @@ -33,46 +33,124 @@ namespace DXILDebug { class Debugger; -void FetchConstantBufferData(WrappedID3D12Device *device, const DXIL::Program *program, - const D3D12RenderState::RootSignature &rootsig, - const ShaderReflection &refl, DXILDebug::GlobalState &global, - rdcarray &sourceVars); - class D3D12APIWrapper : public DebugAPIWrapper { public: - D3D12APIWrapper(WrappedID3D12Device *device, const DXIL::Program &dxilProgram, - GlobalState &globalState, uint32_t eventId); + D3D12APIWrapper(WrappedID3D12Device *device, const DXIL::Program *dxilProgram, + const ShaderReflection &refl, uint32_t eventId, + const rdcarray &inputSig); ~D3D12APIWrapper(); - void FetchSRV(const BindingSlot &slot); - void FetchUAV(const BindingSlot &slot); - bool CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, ShaderVariable &output); + void FetchConstantBufferData(const D3D12RenderState::RootSignature &rootsig); + + const UAVData &GetUAVData(const BindingSlot &slot) override; + const SRVData &GetSRVData(const BindingSlot &slot) override; + + bool CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, + ShaderVariable &output) override; bool CalculateSampleGather(DXIL::DXOp dxOp, SampleGatherResourceData resourceData, SampleGatherSamplerData samplerData, const ShaderVariable &uv, const ShaderVariable &ddxCalc, const ShaderVariable &ddyCalc, const int8_t texelOffsets[3], int multisampleIndex, float lodValue, float compareValue, const uint8_t swizzle[4], GatherChannel gatherChannel, DXBC::ShaderType shaderType, - uint32_t instructionIdx, const char *opString, ShaderVariable &output); + uint32_t instructionIdx, const char *opString, + ShaderVariable &output) override; + ShaderVariable GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - uint32_t mipLevel, const DXBC::ShaderType shaderType, int &dim); + uint32_t mipLevel, const DXBC::ShaderType shaderType, + int &dim) const override; ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - const DXBC::ShaderType shaderType, const char *opString); - ShaderVariable GetRenderTargetSampleInfo(const DXBC::ShaderType shaderType, const char *opString); - ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot); - ShaderDirectAccess GetShaderDirectAccess(DescriptorType type, const DXDebug::BindingSlot &slot); + const DXBC::ShaderType shaderType, + const char *opString) const override; + ShaderVariable GetRenderTargetSampleInfo(const DXBC::ShaderType shaderType, + const char *opString) const override; + ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const override; + ShaderDirectAccess GetShaderDirectAccess(DescriptorType type, + const DXDebug::BindingSlot &slot) const override; + + bool IsSRVCached(const DXDebug::BindingSlot &slot) override; + bool IsUAVCached(const DXDebug::BindingSlot &slot) override; + + void ResetReplay(); + + void SetBuiltins(const BuiltinInputs &builtins) { m_Builtins = builtins; } + void SetWorkgroupProperties(const rdcarray &workgroupProperties) + { + m_WorkgroupProperties = workgroupProperties; + } + void SetThreadsInputs(const rdcarray &threadsInputs) + { + m_ThreadsInputs = threadsInputs; + } + void SetThreadsBuiltins(rdcarray> &threadsBuiltins) + { + m_ThreadsBuiltins = threadsBuiltins; + } + void SetSubgroupSize(uint32_t subgroupSize) { m_SubgroupSize = subgroupSize; } + + const rdcarray &GetDXILEntryPointInputs(void) const + { + return m_EntryPointInterface->inputs; + } + + const rdcarray &GetWorkgroupProperties() const override + { + return m_WorkgroupProperties; + } + const rdcarray &GetConstantBlocks() const override { return m_ConstantBlocks; } + const std::map &GetConstantBlocksDatas() const override + { + return m_ConstantBlocksDatas; + } + + const BuiltinInputs &GetBuiltins() const override { return m_Builtins; } + uint32_t GetSubgroupSize() const override { return m_SubgroupSize; } + const rdcarray> &GetThreadsBuiltins() const override + { + return m_ThreadsBuiltins; + } + const rdcarray &GetThreadsInputs() const override { return m_ThreadsInputs; } + const rdcarray &GetSourceVars() const override { return m_SourceVars; } + const ShaderVariable &GetInputPlaceholder() const override { return m_InputPlaceholder; } private: - void FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); - void FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + void PrepareReplayForResources(); + void AddCBufferToGlobalState(const BindingSlot &slot, bytebuf &cbufData); + void FlattenSingleVariable(const rdcstr &cbufferName, uint32_t byteOffset, const rdcstr &basename, + const ShaderVariable &v, rdcarray &outvars); + void FlattenVariables(const rdcstr &cbufferName, const rdcarray &constants, + const rdcarray &invars, rdcarray &outvars, + const rdcstr &prefix, uint32_t baseOffset); - WrappedID3D12Device *m_Device; - const DXIL::EntryPointInterface *m_EntryPointInterface; - GlobalState &m_GlobalState; - DXBC::ShaderType m_ShaderType; + SRVData &FetchSRV(const BindingSlot &slot); + SRVData &FetchSRV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + + UAVData &FetchUAV(const BindingSlot &slot); + UAVData &FetchUAV(const D3D12Descriptor *resDescriptor, const BindingSlot &slot); + + BuiltinInputs m_Builtins; + rdcarray m_WorkgroupProperties; + rdcarray m_ThreadsInputs; + rdcarray> m_ThreadsBuiltins; + rdcarray m_SourceVars; + rdcarray m_ConstantBlocks; + std::map m_ConstantBlocksDatas; + ShaderVariable m_InputPlaceholder; + uint32_t m_SubgroupSize = 1; + + Threading::RWLock m_UAVsLock; + std::map m_UAVs; + Threading::RWLock m_SRVsLock; + std::map m_SRVs; + + const ShaderReflection &m_Reflection; + WrappedID3D12Device *m_Device = NULL; + const DXIL::Program *m_Program = NULL; + const DXIL::EntryPointInterface *m_EntryPointInterface = NULL; + const DXBC::ShaderType m_ShaderType; const uint32_t m_EventId; - bool m_DidReplay = false; + bool m_ResourcesDirty = true; }; }; diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index f2ebb436a..e49442764 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -2351,22 +2351,29 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui if(buf[0].numHits > 1) RDCLOG("Unexpected number of vertex hits: %u!", buf[0].numHits); - DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); - ret = debugger->BeginDebug(eventId, dxbc, refl, buf->laneIndex, buf->subgroupSize); + DXILDebug::D3D12APIWrapper *apiWrapper = new DXILDebug::D3D12APIWrapper( + m_pDevice, dxbc->GetDXILByteCode(), refl, eventId, dxbc->GetReflection()->InputSig); - DXILDebug::GlobalState &globalState = debugger->GetGlobalState(); + const uint32_t numThreads = buf->subgroupSize; rdcarray workgroupProperties; - workgroupProperties.resize(buf->subgroupSize); - const rdcarray &dxilInputs = - debugger->GetDXILEntryPointInputs(); - globalState.subgroupSize = buf->subgroupSize; - for(uint32_t t = 0; t < buf->subgroupSize; t++) + rdcarray> threadsBuiltins; + rdcarray threadsInputs; + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + threadsInputs.resize(numThreads); + + apiWrapper->SetSubgroupSize(buf->subgroupSize); + + const rdcarray &dxilInputs = + apiWrapper->GetDXILEntryPointInputs(); + + for(uint32_t t = 0; t < numThreads; t++) { + threadsInputs[t] = apiWrapper->GetInputPlaceholder(); DXDebug::VSLaneData *lane = (DXDebug::VSLaneData *)(initialData.data() + laneDataOffset + t * fetcher.laneDataBufferStride); - DXILDebug::ThreadState &state = debugger->GetLane(t); - rdcarray &ins = state.m_Input.members; + rdcarray &ins = threadsInputs[t].members; byte *data = (byte *)(lane + 1); @@ -2409,7 +2416,8 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui data += inputElement.numwords * sizeof(uint32_t); } - state.m_Builtins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), t, 0U, 0U, 0U); + rdcflatmap &threadBuiltins = threadsBuiltins[t]; + threadBuiltins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), t, 0U, 0U, 0U); for(const DXILDebug::InputData &input : inputDatas) { @@ -2437,35 +2445,45 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui } if(input.sysattribute != ShaderBuiltin::Undefined) - state.m_Builtins[input.sysattribute] = invar; + threadBuiltins[input.sysattribute] = invar; } } + apiWrapper->SetWorkgroupProperties(workgroupProperties); + apiWrapper->SetThreadsInputs(threadsInputs); + apiWrapper->SetThreadsBuiltins(threadsBuiltins); + // Fetch constant buffer data from root signature - DXILDebug::FetchConstantBufferData(m_pDevice, dxbc->GetDXILByteCode(), rs.graphics, refl, - globalState, ret->sourceVars); + apiWrapper->FetchConstantBufferData(rs.graphics); - debugger->InitialiseWorkgroup(workgroupProperties); + DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); + ret = debugger->BeginDebug(apiWrapper, eventId, dxbc, refl, buf->laneIndex, buf->subgroupSize); - ret->inputs = {debugger->GetActiveLane().m_Input}; - ret->constantBlocks = globalState.constantBlocks; + apiWrapper->ResetReplay(); } else { - DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); - ret = debugger->BeginDebug(eventId, dxbc, refl, 0, 1); + const uint32_t activeLaneIndex = 0; + const uint32_t numThreads = 1; + DXILDebug::D3D12APIWrapper *apiWrapper = new DXILDebug::D3D12APIWrapper( + m_pDevice, dxbc->GetDXILByteCode(), refl, eventId, dxbc->GetReflection()->InputSig); - DXILDebug::GlobalState &globalState = debugger->GetGlobalState(); - DXILDebug::ThreadState &activeState = debugger->GetActiveLane(); - rdcarray &inputs = activeState.m_Input.members; rdcarray workgroupProperties; - workgroupProperties.resize(1); + rdcarray> threadsBuiltins; + rdcarray threadsInputs; + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + threadsInputs.resize(numThreads); + threadsInputs[activeLaneIndex] = apiWrapper->GetInputPlaceholder(); - workgroupProperties[0][DXILDebug::ThreadProperty::Active] = 1; + workgroupProperties[activeLaneIndex][DXILDebug::ThreadProperty::Active] = 1; + + rdcarray &inputs = threadsInputs[activeLaneIndex].members; + + rdcflatmap &threadBuiltins = threadsBuiltins[activeLaneIndex]; // Fetch constant buffer data from root signature - DXILDebug::FetchConstantBufferData(m_pDevice, dxbc->GetDXILByteCode(), rs.graphics, refl, - globalState, ret->sourceVars); + apiWrapper->FetchConstantBufferData(rs.graphics); // Set input values for(size_t i = 0; i < inputs.size(); i++) @@ -2712,14 +2730,18 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui if(sigParam.systemValue != ShaderBuiltin::Undefined) { - activeState.m_Builtins[sigParam.systemValue] = inputs[i]; + threadBuiltins[sigParam.systemValue] = inputs[i]; } } - debugger->InitialiseWorkgroup(workgroupProperties); + apiWrapper->SetWorkgroupProperties(workgroupProperties); + apiWrapper->SetThreadsInputs(threadsInputs); + apiWrapper->SetThreadsBuiltins(threadsBuiltins); - ret->inputs = {activeState.m_Input}; - ret->constantBlocks = globalState.constantBlocks; + DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); + ret = debugger->BeginDebug(apiWrapper, eventId, dxbc, refl, activeLaneIndex, 1); + + apiWrapper->ResetReplay(); } if(ret) @@ -3155,26 +3177,30 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t } else { - DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); - ret = debugger->BeginDebug(eventId, dxbc, refl, hit->laneIndex, hit->subgroupSize); + uint32_t numThreads = hit->subgroupSize; + DXILDebug::D3D12APIWrapper *apiWrapper = new DXILDebug::D3D12APIWrapper( + m_pDevice, dxbc->GetDXILByteCode(), refl, eventId, dxbc->GetReflection()->InputSig); - DXILDebug::GlobalState &globalState = debugger->GetGlobalState(); rdcarray workgroupProperties; - workgroupProperties.resize(hit->subgroupSize); - const rdcarray &dxilInputs = - debugger->GetDXILEntryPointInputs(); + rdcarray> threadsBuiltins; + rdcarray threadsInputs; + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + threadsInputs.resize(numThreads); // Fetch constant buffer data from root signature - DXILDebug::FetchConstantBufferData(m_pDevice, dxbc->GetDXILByteCode(), rs.graphics, refl, - globalState, ret->sourceVars); + apiWrapper->FetchConstantBufferData(rs.graphics); + const rdcarray &dxilInputs = + apiWrapper->GetDXILEntryPointInputs(); - globalState.subgroupSize = hit->subgroupSize; + apiWrapper->SetSubgroupSize(hit->subgroupSize); for(uint32_t q = 0; q < hit->subgroupSize; q++) { + threadsInputs[q] = apiWrapper->GetInputPlaceholder(); DXDebug::PSLaneData *lane = (DXDebug::PSLaneData *)data; - DXILDebug::ThreadState &state = debugger->GetLane(q); - rdcarray &ins = state.m_Input.members; + rdcarray &ins = threadsInputs[q].members; + rdcflatmap &threadBuiltins = threadsBuiltins[q]; workgroupProperties[q][DXILDebug::ThreadProperty::Active] = lane->active; workgroupProperties[q][DXILDebug::ThreadProperty::Helper] = lane->isHelper; @@ -3223,12 +3249,12 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t data += inputElement.numwords * sizeof(uint32_t); } - state.m_Builtins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), q, 0U, 0U, 0U); - state.m_Builtins[ShaderBuiltin::PrimitiveIndex] = + threadBuiltins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), q, 0U, 0U, 0U); + threadBuiltins[ShaderBuiltin::PrimitiveIndex] = ShaderVariable(rdcstr(), lane->primitive, 0U, 0U, 0U); - state.m_Builtins[ShaderBuiltin::MSAACoverage] = + threadBuiltins[ShaderBuiltin::MSAACoverage] = ShaderVariable(rdcstr(), lane->coverage, 0U, 0U, 0U); - state.m_Builtins[ShaderBuiltin::IsFrontFace] = + threadBuiltins[ShaderBuiltin::IsFrontFace] = ShaderVariable(rdcstr(), lane->isFrontFace, 0U, 0U, 0U); for(const DXILDebug::InputData &input : inputDatas) @@ -3265,7 +3291,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t } if(input.sysattribute != ShaderBuiltin::Undefined) - state.m_Builtins[input.sysattribute] = invar; + threadBuiltins[input.sysattribute] = invar; } // TODO: UPDATE INPUTS FROM SAMPLE CACHE @@ -3292,10 +3318,14 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t #endif } - debugger->InitialiseWorkgroup(workgroupProperties); + apiWrapper->SetWorkgroupProperties(workgroupProperties); + apiWrapper->SetThreadsInputs(threadsInputs); + apiWrapper->SetThreadsBuiltins(threadsBuiltins); - ret->inputs = {debugger->GetActiveLane().m_Input}; - ret->constantBlocks = globalState.constantBlocks; + DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); + ret = debugger->BeginDebug(apiWrapper, eventId, dxbc, refl, hit->laneIndex, hit->subgroupSize); + + apiWrapper->ResetReplay(); } if(ret) @@ -3442,13 +3472,16 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, refl.dispatchThreadsDimension[2], }; - uint32_t numThreads = 1; uint32_t subgroupSize = 1; uint32_t activeLaneIndex = 0; + uint32_t numThreads = 1; - rdcflatmap globalBuiltins; - rdcarray> threadBuiltins; + DXILDebug::D3D12APIWrapper *apiWrapper = new DXILDebug::D3D12APIWrapper( + m_pDevice, dxbc->GetDXILByteCode(), refl, eventId, dxbc->GetReflection()->InputSig); + + DXILDebug::BuiltinInputs globalBuiltins; rdcarray workgroupProperties; + rdcarray> threadsBuiltins; // hard case - with subgroups we want the actual layout so read that from the GPU if(dxbc->GetThreadScope() & DXBC::ThreadScope::Subgroup) @@ -3594,13 +3627,13 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, if(dxbc->GetThreadScope() & DXBC::ThreadScope::Workgroup) numThreads = threadDim[0] * threadDim[1] * threadDim[2]; + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + // SV_GroupID globalBuiltins[ShaderBuiltin::GroupIndex] = ShaderVariable(rdcstr(), groupid[0], groupid[1], groupid[2], 0U); - threadBuiltins.resize(numThreads); - workgroupProperties.resize(numThreads); - // can't know our lane index from the hit if we are simulating the whole workgroup if(dxbc->GetThreadScope() & DXBC::ThreadScope::Workgroup) activeLaneIndex = ~0U; @@ -3632,18 +3665,19 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, workgroupProperties[lane][DXILDebug::ThreadProperty::Active] = value->active; workgroupProperties[lane][DXILDebug::ThreadProperty::SubgroupIdx] = t; - threadBuiltins[lane][ShaderBuiltin::DispatchThreadIndex] = + rdcflatmap &threadBuiltins = threadsBuiltins[lane]; + threadBuiltins[ShaderBuiltin::DispatchThreadIndex] = ShaderVariable(rdcstr(), groupid[0] * threadDim[0] + value->threadid[0], groupid[1] * threadDim[1] + value->threadid[1], groupid[2] * threadDim[2] + value->threadid[2], 0U); - threadBuiltins[lane][ShaderBuiltin::GroupThreadIndex] = + threadBuiltins[ShaderBuiltin::GroupThreadIndex] = ShaderVariable(rdcstr(), value->threadid[0], value->threadid[1], value->threadid[2], 0U); - threadBuiltins[lane][ShaderBuiltin::GroupFlatIndex] = + threadBuiltins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(rdcstr(), value->threadid[2] * threadDim[0] * threadDim[1] + value->threadid[1] * threadDim[0] + value->threadid[0], 0U, 0U, 0U); - threadBuiltins[lane][ShaderBuiltin::IndexInSubgroup] = + threadBuiltins[ShaderBuiltin::IndexInSubgroup] = ShaderVariable(rdcstr(), value->laneIndex, 0U, 0U, 0U); } @@ -3663,7 +3697,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, { for(uint32_t tx = 0; tx < threadDim[0]; tx++) { - rdcflatmap &thread_builtins = threadBuiltins[i]; + rdcflatmap &thread_builtins = threadsBuiltins[i]; if(workgroupProperties[i][DXILDebug::ThreadProperty::Active]) { @@ -3705,13 +3739,13 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, { numThreads = threadDim[0] * threadDim[1] * threadDim[2]; + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + // SV_GroupID globalBuiltins[ShaderBuiltin::GroupIndex] = ShaderVariable(rdcstr(), groupid[0], groupid[1], groupid[2], 0U); - threadBuiltins.resize(numThreads); - workgroupProperties.resize(numThreads); - // if we have workgroup scope that means we need to simulate the whole workgroup but don't // have subgroup ops. We assume the layout of this is irrelevant and don't attempt to read // it back from the GPU like we do with subgroups. We lay things out in plain linear order, @@ -3724,7 +3758,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, { for(uint32_t tx = 0; tx < threadDim[0]; tx++) { - rdcflatmap &thread_builtins = threadBuiltins[i]; + rdcflatmap &thread_builtins = threadsBuiltins[i]; thread_builtins[ShaderBuiltin::DispatchThreadIndex] = ShaderVariable(rdcstr(), groupid[0] * threadDim[0] + tx, groupid[1] * threadDim[1] + ty, groupid[2] * threadDim[2] + tz, 0U); @@ -3744,7 +3778,9 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, } else { - workgroupProperties.resize(1); + workgroupProperties.resize(numThreads); + threadsBuiltins.resize(numThreads); + workgroupProperties[0][DXILDebug::ThreadProperty::Active] = 1; // put everything in globals, no per-thread values @@ -3775,6 +3811,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, { uint32_t newNumThreads = numThreads + numPaddingThreads; workgroupProperties.resize(newNumThreads); + threadsBuiltins.resize(newNumThreads); for(uint32_t i = numThreads; i < newNumThreads; ++i) { workgroupProperties[i][DXILDebug::ThreadProperty::Active] = 0; @@ -3782,25 +3819,24 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, } numThreads = newNumThreads; } + rdcarray threadsInputs; + threadsInputs.resize(numThreads); + for(uint32_t t = 0; t < numThreads; t++) + threadsInputs[t] = apiWrapper->GetInputPlaceholder(); - DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); - ret = debugger->BeginDebug(eventId, dxbc, refl, activeLaneIndex, numThreads); - DXILDebug::GlobalState &globalState = debugger->GetGlobalState(); - - globalState.builtins.swap(globalBuiltins); - globalState.subgroupSize = subgroupSize; - - for(uint32_t i = 0; i < threadBuiltins.size(); i++) - debugger->GetLane(i).m_Builtins.swap(threadBuiltins[i]); + apiWrapper->SetSubgroupSize(subgroupSize); + apiWrapper->SetWorkgroupProperties(workgroupProperties); + apiWrapper->SetThreadsInputs(threadsInputs); + apiWrapper->SetThreadsBuiltins(threadsBuiltins); + apiWrapper->SetBuiltins(globalBuiltins); // Fetch constant buffer data from root signature - DXILDebug::FetchConstantBufferData(m_pDevice, dxbc->GetDXILByteCode(), rs.compute, refl, - globalState, ret->sourceVars); + apiWrapper->FetchConstantBufferData(rs.compute); - debugger->InitialiseWorkgroup(workgroupProperties); + DXILDebug::Debugger *debugger = new DXILDebug::Debugger(); + ret = debugger->BeginDebug(apiWrapper, eventId, dxbc, refl, activeLaneIndex, numThreads); - // ret->inputs = state.inputs; - ret->constantBlocks = globalState.constantBlocks; + apiWrapper->ResetReplay(); } if(ret) @@ -3824,10 +3860,11 @@ rdcarray D3D12Replay::ContinueDebug(ShaderDebugger *debugger) if(((DXBCContainerDebugger *)debugger)->isDXIL) { DXILDebug::Debugger *dxilDebugger = (DXILDebug::Debugger *)debugger; - DXILDebug::D3D12APIWrapper apiWrapper(m_pDevice, dxilDebugger->GetProgram(), - dxilDebugger->GetGlobalState(), dxilDebugger->GetEventId()); D3D12MarkerRegion region(m_pDevice->GetQueue()->GetReal(), "ContinueDebug Simulation Loop"); - return dxilDebugger->ContinueDebug(&apiWrapper); + rdcarray ret = dxilDebugger->ContinueDebug(); + DXILDebug::D3D12APIWrapper *api = (DXILDebug::D3D12APIWrapper *)dxilDebugger->GetAPIWrapper(); + api->ResetReplay(); + return ret; } else { diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index 19dfa25c9..2756a9ee8 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -1220,7 +1220,7 @@ static size_t ComputeDXILTypeByteSize(const Type *type) return byteSize; } -static void TypedUAVStore(DXILDebug::GlobalState::ViewFmt &fmt, byte *d, const ShaderValue &value) +static void TypedUAVStore(DXILDebug::ViewFmt &fmt, byte *d, const ShaderValue &value) { if(fmt.byteWidth == 10) { @@ -1354,7 +1354,7 @@ static void TypedUAVStore(DXILDebug::GlobalState::ViewFmt &fmt, byte *d, const S } } -static ShaderValue TypedUAVLoad(DXILDebug::GlobalState::ViewFmt &fmt, const byte *d) +static ShaderValue TypedUAVLoad(DXILDebug::ViewFmt &fmt, const byte *d) { ShaderValue result; result.f32v[0] = 0.0f; @@ -1511,7 +1511,7 @@ static ShaderValue TypedUAVLoad(DXILDebug::GlobalState::ViewFmt &fmt, const byte return result; } -void ConvertTypeToViewFormat(const DXIL::Type *type, DXILDebug::GlobalState::ViewFmt &fmt) +void ConvertTypeToViewFormat(const DXIL::Type *type, DXILDebug::ViewFmt &fmt) { // variable should be a pointer to the underlying type RDCASSERTEQUAL(type->type, Type::Pointer); @@ -1562,7 +1562,7 @@ void ConvertTypeToViewFormat(const DXIL::Type *type, DXILDebug::GlobalState::Vie } } -static void FillViewFmtFromVarType(VarType type, DXILDebug::GlobalState::ViewFmt &fmt) +static void FillViewFmtFromVarType(VarType type, DXILDebug::ViewFmt &fmt) { switch(type) { @@ -2343,25 +2343,19 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, uint32_t depthPitch = 0; uint32_t firstElem = 0; uint32_t numElems = 0; - GlobalState::ViewFmt fmt; + ViewFmt fmt; // Helper lanes can't modify UAVs if(!load && (resClass == ResourceClass::UAV) && m_Helper) break; RDCASSERT((resClass == ResourceClass::SRV || resClass == ResourceClass::UAV), resClass); - GlobalState::ResourceInfo resInfo; + ResourceInfo resInfo; switch(resClass) { case ResourceClass::UAV: { - GlobalState::UAVIterator uavIter = m_GlobalState.uavs.find(resRefInfo.binding); - if(uavIter == m_GlobalState.uavs.end()) - { - apiWrapper->FetchUAV(resRefInfo.binding); - uavIter = m_GlobalState.uavs.find(resRefInfo.binding); - } - const GlobalState::UAVData &uav = uavIter->second; + const UAVData &uav = apiWrapper->GetUAVData(resRefInfo.binding); resInfo = uav.resInfo; data = uav.data.data(); dataSize = uav.data.size(); @@ -2372,13 +2366,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, } case ResourceClass::SRV: { - GlobalState::SRVIterator srvIter = m_GlobalState.srvs.find(resRefInfo.binding); - if(srvIter == m_GlobalState.srvs.end()) - { - apiWrapper->FetchSRV(resRefInfo.binding); - srvIter = m_GlobalState.srvs.find(resRefInfo.binding); - } - const GlobalState::SRVData &srv = srvIter->second; + const SRVData &srv = apiWrapper->GetSRVData(resRefInfo.binding); resInfo = srv.resInfo; data = srv.data.data(); dataSize = srv.data.size(); @@ -2895,7 +2883,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, const uint32_t byteWidth = 4; const byte *data = cbufferData.data() + dataOffset; const uint32_t numComps = RDCMIN(4U, (bufferSize - dataOffset) / byteWidth); - GlobalState::ViewFmt cbufferFmt; + ViewFmt cbufferFmt; cbufferFmt.byteWidth = byteWidth; cbufferFmt.numComps = numComps; cbufferFmt.compType = CompType::Float; @@ -3511,17 +3499,10 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, uint32_t depthPitch = 0; uint32_t firstElem = 0; uint32_t numElems = 0; - GlobalState::ViewFmt fmt; + ViewFmt fmt; - GlobalState::ResourceInfo resInfo; - GlobalState::UAVIterator uavIter = m_GlobalState.uavs.find(resRefInfo.binding); - if(uavIter == m_GlobalState.uavs.end()) - { - apiWrapper->FetchUAV(resRefInfo.binding); - uavIter = m_GlobalState.uavs.find(resRefInfo.binding); - } - const GlobalState::UAVData &uav = uavIter->second; - resInfo = uav.resInfo; + const UAVData &uav = apiWrapper->GetUAVData(resRefInfo.binding); + const ResourceInfo resInfo = uav.resInfo; data = uav.data.data(); dataSize = uav.data.size(); texData = uav.tex; @@ -7668,6 +7649,11 @@ rdcstr Debugger::GetResourceReferenceName(const DXIL::Program *program, return "UNKNOWN_RESOURCE_HANDLE"; } +Debugger::~Debugger() +{ + SAFE_DELETE(m_ApiWrapper); +} + ScopedDebugData *Debugger::FindScopedDebugData(const DXIL::Metadata *md) const { for(ScopedDebugData *s : m_DebugInfo.scopedDebugDatas) @@ -8887,17 +8873,19 @@ void Debugger::ParseDebugData() } } -ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContainer *dxbcContainer, +ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, uint32_t eventId, + const DXBC::DXBCContainer *dxbcContainer, const ShaderReflection &reflection, uint32_t activeLaneIndex, uint32_t threadsInWorkgroup) { ShaderStage shaderStage = reflection.stage; + m_ApiWrapper = apiWrapper; m_Program = dxbcContainer->GetDXILByteCode(); - m_EventId = eventId; m_ActiveLaneIndex = activeLaneIndex; m_Steps = 0; m_Stage = shaderStage; + m_EntryPointInterface = m_Program->GetEntryPointInterface(); uint32_t outputSSAId = m_Program->m_NextSSAId; uint32_t maxSSAId = outputSSAId + 1; @@ -8905,27 +8893,30 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain ShaderDebugTrace *ret = new ShaderDebugTrace; ret->stage = shaderStage; + // Get the global state from the API wrapper + m_GlobalState.builtins = apiWrapper->GetBuiltins(); + m_GlobalState.subgroupSize = apiWrapper->GetSubgroupSize(); + m_GlobalState.constantBlocks = apiWrapper->GetConstantBlocks(); + m_GlobalState.constantBlocksDatas = apiWrapper->GetConstantBlocksDatas(); + for(uint32_t i = 0; i < threadsInWorkgroup; i++) m_Workgroup.push_back(ThreadState(*this, m_GlobalState, maxSSAId)); - ThreadState &state = GetActiveLane(); + // Get the thread state from the API wrapper + const rdcarray> &threadsBuiltins = + apiWrapper->GetThreadsBuiltins(); + const rdcarray &threadsInputs = apiWrapper->GetThreadsInputs(); - // Create the storage layout for the constant buffers - // The constant buffer data and details are filled in outside of this method - size_t count = reflection.constantBlocks.size(); - m_GlobalState.constantBlocks.resize(count); - for(uint32_t i = 0; i < count; i++) + for(uint32_t i = 0; i < threadsInWorkgroup; i++) { - m_GlobalState.constantBlocks[i].type = VarType::ConstantBlock; - const ConstantBlock &cbuffer = reflection.constantBlocks[i]; - uint32_t bindCount = cbuffer.bindArraySize; - if(bindCount > 1) - { - // Create nested structure for constant buffer array - m_GlobalState.constantBlocks[i].members.resize(bindCount); - } + m_Workgroup[i].m_Builtins = threadsBuiltins[i]; + m_Workgroup[i].m_Input = threadsInputs[i]; } + ret->sourceVars = apiWrapper->GetSourceVars(); + + ThreadState &activeState = GetActiveLane(); + struct ResourceList { VarType varType; @@ -8994,7 +8985,7 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain } // Create the variables for Samplers - count = reflection.samplers.size(); + size_t count = reflection.samplers.size(); m_GlobalState.samplers.reserve(count); for(uint32_t i = 0; i < count; i++) { @@ -9046,7 +9037,8 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain const MemoryTracking::Allocation &allocation = itAlloc->second; void *allocMemoryBackingPtr = allocation.backingMemory; uint64_t allocSize = allocation.size; - state.UpdateBackingMemoryFromVariable(allocMemoryBackingPtr, allocSize, globalVar.var); + activeState.UpdateBackingMemoryFromVariable(allocMemoryBackingPtr, allocSize, + globalVar.var); RDCASSERTEQUAL(allocSize, 0); } else @@ -9464,120 +9456,18 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain } } - // Add inputs to the shader trace - // Use the DXIL reflection data to map the input signature to input variables - const EntryPointInterface *entryPointIf = NULL; - for(size_t e = 0; e < m_Program->m_EntryPointInterfaces.size(); ++e) - { - if(entryFunction == m_Program->m_EntryPointInterfaces[e].name) - { - entryPointIf = &m_Program->m_EntryPointInterfaces[e]; - break; - } - } - RDCASSERT(entryPointIf); - m_EntryPointInterface = entryPointIf; - const rdcarray &inputs = m_EntryPointInterface->inputs; - - const uint32_t countInParams = (uint32_t)inputs.size(); - if(countInParams) - { - // Make fake ShaderVariable struct to hold all the inputs - ShaderVariable &inStruct = state.m_Input; - inStruct.name = DXIL_FAKE_INPUT_STRUCT_NAME; - inStruct.rows = 0; - inStruct.columns = 0; - inStruct.type = VarType::Struct; - inStruct.members.resize(countInParams); - - const rdcarray &dxbcInParams = dxbcContainer->GetReflection()->InputSig; - for(uint32_t i = 0; i < countInParams; ++i) - { - const EntryPointInterface::Signature &sig = inputs[i]; - - ShaderVariable &v = inStruct.members[i]; - - // Get the name from the DXBC reflection - SigParameter sigParam; - if(FindSigParameter(dxbcInParams, sig, sigParam)) - { - v.name = sigParam.semanticIdxName; - } - else - { - v.name = sig.name; - } - v.rows = (uint8_t)sig.rows; - v.columns = (uint8_t)sig.cols; - v.type = VarTypeForComponentType(sig.type); - if(v.rows <= 1) - { - v.rows = 1; - } - else - { - v.members.resize(v.rows); - for(uint32_t r = 0; r < v.rows; r++) - { - v.members[r].rows = 1; - v.members[r].columns = (uint8_t)sig.cols; - v.members[r].type = v.type; - v.members[r].name = StringFormat::Fmt("[%u]", r); - } - } - - SourceVariableMapping inputMapping; - inputMapping.name = v.name; - inputMapping.type = v.type; - inputMapping.rows = sig.rows; - inputMapping.columns = sig.cols; - inputMapping.variables.reserve(sig.cols); - inputMapping.signatureIndex = i; - if(v.rows <= 1) - { - inputMapping.variables.reserve(sig.cols); - for(uint32_t c = 0; c < sig.cols; ++c) - { - DebugVariableReference ref; - ref.type = DebugVariableType::Input; - ref.name = inStruct.name + "." + v.name; - ref.component = c; - inputMapping.variables.push_back(ref); - } - } - else - { - DebugVariableReference ref; - ref.type = DebugVariableType::Input; - ref.name = inStruct.name + "." + v.name; - inputMapping.variables.push_back(ref); - } - ret->sourceVars.push_back(inputMapping); - } - - // Make a single source variable mapping for the whole input struct - SourceVariableMapping inputMapping; - inputMapping.name = inStruct.name; - inputMapping.type = VarType::Struct; - inputMapping.rows = 0; - inputMapping.columns = 0; - inputMapping.variables.resize(1); - inputMapping.variables.push_back(DebugVariableReference(DebugVariableType::Input, inStruct.name)); - ret->sourceVars.push_back(inputMapping); - } - const rdcarray &dxbcOutParams = dxbcContainer->GetReflection()->OutputSig; const rdcarray &outputs = m_EntryPointInterface->outputs; uint32_t countOutputs = (uint32_t)outputs.size(); // Make fake ShaderVariable struct to hold all the outputs - ShaderVariable &outStruct = state.m_Output.var; + ShaderVariable &outStruct = activeState.m_Output.var; outStruct.name = DXIL_FAKE_OUTPUT_STRUCT_NAME; outStruct.rows = 0; outStruct.columns = 0; outStruct.type = VarType::Struct; outStruct.members.resize(countOutputs); - state.m_Output.id = outputSSAId; + activeState.m_Output.id = outputSSAId; for(uint32_t i = 0; i < countOutputs; ++i) { @@ -9707,12 +9597,12 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain { // Make a single source variable mapping for the whole output struct SourceVariableMapping outputMapping; - outputMapping.name = state.m_Output.var.name; + outputMapping.name = activeState.m_Output.var.name; outputMapping.type = VarType::Struct; outputMapping.rows = 0; outputMapping.columns = 0; outputMapping.variables.resize(1); - outputMapping.variables[0].name = state.m_Output.var.name; + outputMapping.variables[0].name = activeState.m_Output.var.name; outputMapping.variables[0].type = DebugVariableType::Variable; ret->sourceVars.push_back(outputMapping); } @@ -9731,8 +9621,8 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain ret->sourceVars.push_back(outputMapping); } - ret->inputs = {state.m_Input}; - ret->inputs.append(state.m_Input.members); + ret->inputs = {activeState.m_Input}; + ret->inputs.append(activeState.m_Input.members); ret->constantBlocks = m_GlobalState.constantBlocks; ret->readOnlyResources = m_GlobalState.readOnlyResources; ret->readWriteResources = m_GlobalState.readWriteResources; @@ -9746,23 +9636,25 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain if(i != m_ActiveLaneIndex) { - lane.m_Input = state.m_Input; - lane.m_Variables = state.m_Variables; - lane.m_Assigned = state.m_Assigned; - lane.m_Live = state.m_Live; - lane.m_IsGlobal = state.m_IsGlobal; + lane.m_Variables = activeState.m_Variables; + lane.m_Assigned = activeState.m_Assigned; + lane.m_Live = activeState.m_Live; + lane.m_IsGlobal = activeState.m_IsGlobal; } } // Add the output struct to the global state if(countOutputs) - m_GlobalState.globals.push_back(state.m_Output); + m_GlobalState.globals.push_back(activeState.m_Output); + + InitialiseWorkgroup(); return ret; } -void Debugger::InitialiseWorkgroup(const rdcarray &workgroupProperties) +void Debugger::InitialiseWorkgroup() { + const rdcarray &workgroupProperties = m_ApiWrapper->GetWorkgroupProperties(); const uint32_t threadsInWorkgroup = (uint32_t)m_Workgroup.size(); if(threadsInWorkgroup == 1) @@ -9853,7 +9745,7 @@ void Debugger::InitialiseWorkgroup(const rdcarray &workgroupPr } } -rdcarray Debugger::ContinueDebug(DebugAPIWrapper *apiWrapper) +rdcarray Debugger::ContinueDebug() { ThreadState &active = GetActiveLane(); @@ -9987,12 +9879,12 @@ rdcarray Debugger::ContinueDebug(DebugAPIWrapper *apiWrapper) { hasDebugState = true; state.stepIndex = m_Steps; - thread.StepNext(&state, apiWrapper, m_Workgroup, activeMask); + thread.StepNext(&state, m_ApiWrapper, m_Workgroup, activeMask); m_Steps++; } else { - thread.StepNext(NULL, apiWrapper, m_Workgroup, activeMask); + thread.StepNext(NULL, m_ApiWrapper, m_Workgroup, activeMask); } threadExecutionStates[threadId] = thread.m_EnteredPoints; diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index b49a2552e..7a5a2ce69 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -173,13 +173,87 @@ struct ConstantBlockReference } }; +struct ViewFmt +{ + int byteWidth = 0; + int numComps = 0; + CompType compType = CompType::Typeless; + int stride = 0; +}; + +struct ResourceInfo +{ + ResourceInfo() : firstElement(0), numElements(0), isByteBuffer(false), isRootDescriptor(false) {} + + uint32_t firstElement; + uint32_t numElements; + + bool isByteBuffer; + bool isRootDescriptor; + // Buffer stride is stored in format.stride + ViewFmt format; +}; + +struct UAVData +{ + UAVData() = default; + + ResourceInfo resInfo; + bytebuf data; + + uint32_t rowPitch = 0; + uint32_t depthPitch = 0; + uint32_t hiddenCounter = 0; + bool tex = false; +}; + +struct SRVData +{ + SRVData() = default; + + ResourceInfo resInfo; + bytebuf data; +}; + +enum class ThreadProperty : uint32_t +{ + Helper, + QuadId, + QuadLane, + Active, + SubgroupIdx, + Count, +}; + +struct ThreadProperties +{ + rdcfixedarray()> props; + + uint32_t &operator[](ThreadProperty p) + { + if(p >= ThreadProperty::Count) + return props[0]; + return props[(uint32_t)p]; + } + + uint32_t operator[](ThreadProperty p) const + { + if(p >= ThreadProperty::Count) + return 0; + return props[(uint32_t)p]; + } +}; + +typedef rdcflatmap BuiltinInputs; + class DebugAPIWrapper { public: - // During shader debugging, when a new resource is encountered - // These will be called to fetch the data on demand. - virtual void FetchSRV(const BindingSlot &slot) = 0; - virtual void FetchUAV(const BindingSlot &slot) = 0; + virtual ~DebugAPIWrapper() {} + + // These will fetch the data on demand. + virtual const UAVData &GetUAVData(const BindingSlot &slot) = 0; + virtual const SRVData &GetSRVData(const BindingSlot &slot) = 0; virtual bool CalculateMathIntrinsic(DXIL::DXOp dxOp, const ShaderVariable &input, ShaderVariable &output) = 0; @@ -193,14 +267,28 @@ public: ShaderVariable &output) = 0; virtual ShaderVariable GetResourceInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, uint32_t mipLevel, - const DXBC::ShaderType shaderType, int &dim) = 0; + const DXBC::ShaderType shaderType, int &dim) const = 0; virtual ShaderVariable GetSampleInfo(DXIL::ResourceClass resClass, const DXDebug::BindingSlot &slot, - const DXBC::ShaderType shaderType, const char *opString) = 0; + const DXBC::ShaderType shaderType, + const char *opString) const = 0; virtual ShaderVariable GetRenderTargetSampleInfo(const DXBC::ShaderType shaderType, - const char *opString) = 0; - virtual ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) = 0; + const char *opString) const = 0; + virtual ResourceReferenceInfo GetResourceReferenceInfo(const DXDebug::BindingSlot &slot) const = 0; virtual ShaderDirectAccess GetShaderDirectAccess(DescriptorType type, - const DXDebug::BindingSlot &slot) = 0; + const DXDebug::BindingSlot &slot) const = 0; + + virtual bool IsSRVCached(const DXDebug::BindingSlot &slot) = 0; + virtual bool IsUAVCached(const DXDebug::BindingSlot &slot) = 0; + + virtual const ShaderVariable &GetInputPlaceholder() const = 0; + virtual const rdcarray &GetWorkgroupProperties() const = 0; + virtual const rdcarray &GetConstantBlocks() const = 0; + virtual const std::map &GetConstantBlocksDatas() const = 0; + virtual const BuiltinInputs &GetBuiltins() const = 0; + virtual uint32_t GetSubgroupSize() const = 0; + virtual const rdcarray> &GetThreadsBuiltins() const = 0; + virtual const rdcarray &GetThreadsInputs() const = 0; + virtual const rdcarray &GetSourceVars() const = 0; }; struct MemoryTracking @@ -237,8 +325,6 @@ struct MemoryTracking std::map m_Pointers; }; -typedef rdcflatmap BuiltinInputs; - struct ThreadState { ThreadState(Debugger &debugger, const GlobalState &globalState, uint32_t maxSSAId); @@ -401,56 +487,6 @@ struct GlobalState uint32_t subgroupSize = 1; bool waveOpsIncludeHelpers = false; - struct ViewFmt - { - int byteWidth = 0; - int numComps = 0; - CompType compType = CompType::Typeless; - int stride = 0; - }; - - struct ResourceInfo - { - ResourceInfo() : firstElement(0), numElements(0), isByteBuffer(false), isRootDescriptor(false) - { - } - - uint32_t firstElement; - uint32_t numElements; - - bool isByteBuffer; - bool isRootDescriptor; - // Buffer stride is stored in format.stride - ViewFmt format; - }; - - struct UAVData - { - UAVData() : tex(false), rowPitch(0), depthPitch(0), hiddenCounter(0) {} - - ResourceInfo resInfo; - - bytebuf data; - bool tex; - uint32_t rowPitch, depthPitch; - - uint32_t hiddenCounter; - }; - - std::map uavs; - typedef std::map::const_iterator UAVIterator; - - struct SRVData - { - SRVData() {} - - ResourceInfo resInfo; - bytebuf data; - }; - - std::map srvs; - typedef std::map::const_iterator SRVIterator; - // allocated storage for opaque uniform blocks, does not change over the course of debugging rdcarray constantBlocks; std::map constantBlocksDatas; @@ -556,62 +592,33 @@ struct TypeData bool colMajorMat = false; }; -enum class ThreadProperty : uint32_t -{ - Helper, - QuadId, - QuadLane, - Active, - SubgroupIdx, - Count, -}; - -struct ThreadProperties -{ - rdcfixedarray()> props; - - uint32_t &operator[](ThreadProperty p) - { - if(p >= ThreadProperty::Count) - return props[0]; - return props[(uint32_t)p]; - } - - uint32_t operator[](ThreadProperty p) const - { - if(p >= ThreadProperty::Count) - return 0; - return props[(uint32_t)p]; - } -}; - class Debugger : public DXBCContainerDebugger { public: Debugger() : DXBCContainerDebugger(true){}; - ShaderDebugTrace *BeginDebug(uint32_t eventId, const DXBC::DXBCContainer *dxbcContainer, + ~Debugger(); + + ShaderDebugTrace *BeginDebug(DebugAPIWrapper *apiWrapper, uint32_t eventId, + const DXBC::DXBCContainer *dxbcContainer, const ShaderReflection &reflection, uint32_t activeLaneIndex, uint32_t threadsInWorkgroup); - void InitialiseWorkgroup(const rdcarray &workgroupProperties); - rdcarray ContinueDebug(DebugAPIWrapper *apiWrapper); - GlobalState &GetGlobalState() { return m_GlobalState; } - ThreadState &GetActiveLane() { return m_Workgroup[m_ActiveLaneIndex]; } - ThreadState &GetLane(const uint32_t i) { return m_Workgroup[i]; } - rdcarray &GetWorkgroup() { return m_Workgroup; } - const rdcarray &GetLiveGlobals() { return m_LiveGlobals; } - static rdcstr GetResourceReferenceName(const DXIL::Program *program, DXIL::ResourceClass resClass, - const BindingSlot &slot); + rdcarray ContinueDebug(); + + const rdcarray &GetLiveGlobals() const { return m_LiveGlobals; } + const DXIL::Program &GetProgram() const { return *m_Program; } + const FunctionInfo *GetFunctionInfo(const DXIL::Function *function) const; + + DebugAPIWrapper *GetAPIWrapper() const { return m_ApiWrapper; } + static rdcstr GetResourceBaseName(const DXIL::Program *program, const DXIL::ResourceReference *resRef); - const DXIL::Program &GetProgram() const { return *m_Program; } - uint32_t GetEventId() { return m_EventId; } - const FunctionInfo *GetFunctionInfo(const DXIL::Function *function) const; - const rdcarray &GetDXILEntryPointInputs(void) const - { - return m_EntryPointInterface->inputs; - } + + static rdcstr GetResourceReferenceName(const DXIL::Program *program, DXIL::ResourceClass resClass, + const BindingSlot &slot); private: + void InitialiseWorkgroup(); + ThreadState &GetActiveLane() { return m_Workgroup[m_ActiveLaneIndex]; } void ParseDbgOpDeclare(const DXIL::Instruction &inst, uint32_t instructionIndex); void ParseDbgOpValue(const DXIL::Instruction &inst, uint32_t instructionIndex); const DXIL::Metadata *GetMDScope(const DXIL::Metadata *scopeMD) const; @@ -622,6 +629,8 @@ private: void AddLocalVariable(const DXIL::SourceMappingInfo &srcMapping, uint32_t instructionIndex); void ParseDebugData(); + DebugAPIWrapper *m_ApiWrapper = NULL; + rdcarray m_Workgroup; std::map m_FunctionInfos; rdcshaders::ControlFlow m_ControlFlow; @@ -644,7 +653,6 @@ private: const DXIL::EntryPointInterface *m_EntryPointInterface = NULL; ShaderStage m_Stage; - uint32_t m_EventId = 0; uint32_t m_ActiveLaneIndex = 0; int m_Steps = 0; };