From 1cc0fd0323cba57fa956d95b699daf90a991861c Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Wed, 4 Sep 2024 11:12:47 +0100 Subject: [PATCH] D3D12 Shader Debug preparation for DXIL Pixel Shader Debugging Move pixel shader debugging code which is shared by DXBC/DXIL to outside of if DXBC scope --- renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 1050 +++++++++--------- 1 file changed, 545 insertions(+), 505 deletions(-) diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index b2c86694b..fd1a44d63 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -1938,7 +1938,7 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui } else { - RDCERR("TODO ADD DXIL VERTEX SHADER DEBUGGER SUPPORT"); + RDCERR("DXIL Vertex Shader Debugging is not supported"); } if(ret) @@ -1993,80 +1993,90 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t return new ShaderDebugTrace; } + if(!dxbc->GetDXBCByteCode()) + { + RDCERR("DXIL Pixel Shader Debugging is not supported"); + return new ShaderDebugTrace; + } + dxbc->GetDisassembly(false); ShaderDebugTrace *ret = NULL; - if(dxbc->GetDXBCByteCode()) + + // Fetch the previous stage's disassembly, to match outputs to PS inputs + DXBCContainer *prevDxbc = NULL; + // Check for geometry shader first { - // Fetch the previous stage's disassembly, to match outputs to PS inputs - DXBCContainer *prevDxbc = NULL; - // Check for geometry shader first - { - WrappedID3D12Shader *gs = (WrappedID3D12Shader *)pso->graphics->GS.pShaderBytecode; - if(gs) - prevDxbc = gs->GetDXBC(); - } - // Check for domain shader next - if(prevDxbc == NULL) - { - WrappedID3D12Shader *ds = (WrappedID3D12Shader *)pso->graphics->DS.pShaderBytecode; - if(ds) - prevDxbc = ds->GetDXBC(); - } - // Check for vertex shader last - if(prevDxbc == NULL) - { - WrappedID3D12Shader *vs = (WrappedID3D12Shader *)pso->graphics->VS.pShaderBytecode; - if(vs) - prevDxbc = vs->GetDXBC(); - } + WrappedID3D12Shader *gs = (WrappedID3D12Shader *)pso->graphics->GS.pShaderBytecode; + if(gs) + prevDxbc = gs->GetDXBC(); + } + // Check for domain shader next + if(prevDxbc == NULL) + { + WrappedID3D12Shader *ds = (WrappedID3D12Shader *)pso->graphics->DS.pShaderBytecode; + if(ds) + prevDxbc = ds->GetDXBC(); + } + // Check for vertex shader last + if(prevDxbc == NULL) + { + WrappedID3D12Shader *vs = (WrappedID3D12Shader *)pso->graphics->VS.pShaderBytecode; + if(vs) + prevDxbc = vs->GetDXBC(); + } - rdcarray initialValues; - rdcarray floatInputs; - rdcarray inputVarNames; - rdcstr extractHlsl; - int structureStride = 0; + rdcarray initialValues; + rdcarray floatInputs; + rdcarray inputVarNames; + rdcstr extractHlsl; + int structureStride = 0; - rdcarray interpModes; - const rdcarray &inputSig = dxbc->GetReflection()->InputSig; + rdcarray interpModes; + const rdcarray &inputSig = dxbc->GetReflection()->InputSig; + if(dxbc->GetDXBCByteCode()) DXBCDebug::GetInterpolationModeForInputParams(inputSig, dxbc->GetDXBCByteCode(), interpModes); + else + RDCERR("DXIL Pixel Shader Debugging is not supported"); - DXDebug::GatherPSInputDataForInitialValues(inputSig, prevDxbc->GetReflection()->OutputSig, - interpModes, initialValues, floatInputs, - inputVarNames, extractHlsl, structureStride); + DXDebug::GatherPSInputDataForInitialValues(inputSig, prevDxbc->GetReflection()->OutputSig, + interpModes, initialValues, floatInputs, inputVarNames, + extractHlsl, structureStride); - uint32_t overdrawLevels = 100; // maximum number of overdraw levels + uint32_t overdrawLevels = 100; // maximum number of overdraw levels - // If the pipe contains a geometry shader, then SV_PrimitiveID cannot be used in the pixel - // shader without being emitted from the geometry shader. For now, check if this semantic - // will succeed in a new pixel shader with the rest of the pipe unchanged - bool usePrimitiveID = (prevDxbc->m_Type != ShaderType::Geometry); - for(const PSInputElement &e : initialValues) + // If the pipe contains a geometry shader, then SV_PrimitiveID cannot be used in the pixel shader + // without being emitted from the geometry shader. For now, check if this semantic will succeed in + // a new pixel shader with the rest of the pipe unchanged + bool usePrimitiveID = (prevDxbc->m_Type != ShaderType::Geometry); + for(const PSInputElement &e : initialValues) + { + if(e.sysattribute == ShaderBuiltin::PrimitiveIndex) { - if(e.sysattribute == ShaderBuiltin::PrimitiveIndex) - { - usePrimitiveID = true; - break; - } + usePrimitiveID = true; + break; } + } - // Store a copy of the event's render state to restore later - D3D12RenderState prevState = rs; + // Store a copy of the event's render state to restore later + D3D12RenderState prevState = rs; - // Fetch the multisample count from the PSO - WrappedID3D12PipelineState *origPSO = - m_pDevice->GetResourceManager()->GetCurrentAs(rs.pipe); + // Fetch the multisample count from the PSO + WrappedID3D12PipelineState *origPSO = + m_pDevice->GetResourceManager()->GetCurrentAs(rs.pipe); - D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC pipeDesc; - origPSO->Fill(pipeDesc); - uint32_t outputSampleCount = RDCMAX(1U, pipeDesc.SampleDesc.Count); + D3D12_EXPANDED_PIPELINE_STATE_STREAM_DESC pipeDesc; + origPSO->Fill(pipeDesc); + uint32_t outputSampleCount = RDCMAX(1U, pipeDesc.SampleDesc.Count); - std::set evalSampleCacheData; - uint64_t sampleEvalRegisterMask = 0; + std::set evalSampleCacheData; + uint64_t sampleEvalRegisterMask = 0; - // if we're not rendering at MSAA, no need to fill the cache because evaluates will all return - // the plain input anyway. - if(outputSampleCount > 1) + // if we're not rendering at MSAA, no need to fill the cache because evaluates will all return the + // plain input anyway. + if(outputSampleCount > 1) + { + if(dxbc->GetDXBCByteCode()) { // scan the instructions to see if it contains any evaluates. size_t numInstructions = dxbc->GetDXBCByteCode()->GetNumInstructions(); @@ -2146,8 +2156,13 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t } } } + else + { + RDCERR("DXIL Pixel Shader Debugging is not supported"); + } + } - extractHlsl += R"( + extractHlsl += R"( struct PSInitialData { // metadata we need ourselves @@ -2169,503 +2184,545 @@ struct PSInitialData )"; - WrappedID3D12RootSignature *sig = - m_pDevice->GetResourceManager()->GetCurrentAs(rs.graphics.rootsig); + WrappedID3D12RootSignature *sig = + m_pDevice->GetResourceManager()->GetCurrentAs(rs.graphics.rootsig); - // Need to be able to add a descriptor table with our UAV without hitting the 64 DWORD limit - RDCASSERT(sig->sig.dwordLength < 64); - D3D12RootSignature modsig = sig->sig; + // Need to be able to add a descriptor table with our UAV without hitting the 64 DWORD limit + RDCASSERT(sig->sig.dwordLength < 64); + D3D12RootSignature modsig = sig->sig; - UINT regSpace = - GetFreeRegSpace(modsig, 0, D3D12DescriptorType::UAV, D3D12_SHADER_VISIBILITY_PIXEL); + UINT regSpace = GetFreeRegSpace(modsig, 0, D3D12DescriptorType::UAV, D3D12_SHADER_VISIBILITY_PIXEL); - // If this event uses MSAA, then at least one render target must be preserved to get - // multisampling info. leave u0 alone and start with register u1 - extractHlsl += StringFormat::Fmt( - "RWStructuredBuffer PSInitialBuffer : register(u1, space%u);\n\n", regSpace); + // If this event uses MSAA, then at least one render target must be preserved to get multisampling + // info. leave u0 alone and start with register u1 + extractHlsl += StringFormat::Fmt( + "RWStructuredBuffer PSInitialBuffer : register(u1, space%u);\n\n", regSpace); - if(!evalSampleCacheData.empty()) + if(!evalSampleCacheData.empty()) + { + // float4 is wasteful in some cases but it's easier than using byte buffers and manual packing + extractHlsl += + StringFormat::Fmt("RWBuffer PSEvalBuffer : register(u2, space%u);\n\n", regSpace); + } + + // The semantics that RenderDoc requires in the shader + bool inputHas_SV_Position = false; + bool inputHas_SV_PrimitiveID = false; + bool inputHas_SV_SampleIndex = false; + bool inputHas_SV_Coverage = false; + bool inputHas_SV_IsFrontFace = false; + + // DXC compiler errors if a semantic input is declared in multiple places + if(dxbc->GetDXILByteCode()) + { + inputHas_SV_Position = extractHlsl.contains(": SV_Position"); + inputHas_SV_PrimitiveID = extractHlsl.contains(": SV_PrimitiveID"); + inputHas_SV_SampleIndex = extractHlsl.contains(": SV_SampleIndex"); + inputHas_SV_Coverage = extractHlsl.contains(": SV_Coverage"); + inputHas_SV_IsFrontFace = extractHlsl.contains(": SV_IsFrontFace"); + } + + extractHlsl += "void ExtractInputsPS(PSInput IN"; + if(!inputHas_SV_Position) + extractHlsl += ", float4 debug_pixelPos : SV_Position"; + if(usePrimitiveID && !inputHas_SV_PrimitiveID) + extractHlsl += ", uint prim : SV_PrimitiveID"; + if(!inputHas_SV_SampleIndex) + extractHlsl += ", uint sample : SV_SampleIndex"; + if(!inputHas_SV_Coverage) + extractHlsl += ", uint covge : SV_Coverage"; + if(!inputHas_SV_IsFrontFace) + extractHlsl += ", bool fface : SV_IsFrontFace"; + + extractHlsl += ")\n{\n"; + + // Only used for DXIL shaders: copy any SV inputs we need from the input structure + if(inputHas_SV_Position) + extractHlsl += " float4 debug_pixelPos = IN.input_SV_Position;\n"; + if(usePrimitiveID && inputHas_SV_PrimitiveID) + extractHlsl += " uint prim = IN.input_SV_PrimitiveID;\n"; + if(inputHas_SV_SampleIndex) + extractHlsl += " uint sample = IN.input_SV_SampleIndex;\n"; + if(inputHas_SV_Coverage) + extractHlsl += " uint covge = IN.input_SV_Coverage;\n"; + if(inputHas_SV_IsFrontFace) + extractHlsl += " bool fface = IN.input_SV_IsFrontFace;\n"; + + extractHlsl += " uint idx = " + ToStr(overdrawLevels) + ";\n"; + extractHlsl += StringFormat::Fmt( + " if(abs(debug_pixelPos.x - %u.5) < 0.5f && abs(debug_pixelPos.y - %u.5) < 0.5f)\n", x, y); + extractHlsl += " InterlockedAdd(PSInitialBuffer[0].hit, 1, idx);\n\n"; + extractHlsl += " idx = min(idx, " + ToStr(overdrawLevels) + ");\n\n"; + extractHlsl += " PSInitialBuffer[idx].pos = debug_pixelPos.xyz;\n"; + + if(usePrimitiveID) + extractHlsl += " PSInitialBuffer[idx].prim = prim;\n"; + else + extractHlsl += " PSInitialBuffer[idx].prim = 0;\n"; + + extractHlsl += " PSInitialBuffer[idx].fface = fface;\n"; + extractHlsl += " PSInitialBuffer[idx].covge = covge;\n"; + extractHlsl += " PSInitialBuffer[idx].sample = sample;\n"; + extractHlsl += " PSInitialBuffer[idx].IN = IN;\n"; + extractHlsl += " PSInitialBuffer[idx].derivValid = ddx(debug_pixelPos.x);\n"; + extractHlsl += " PSInitialBuffer[idx].INddx = (PSInput)0;\n"; + extractHlsl += " PSInitialBuffer[idx].INddy = (PSInput)0;\n"; + extractHlsl += " PSInitialBuffer[idx].INddxfine = (PSInput)0;\n"; + extractHlsl += " PSInitialBuffer[idx].INddyfine = (PSInput)0;\n"; + + if(!evalSampleCacheData.empty()) + { + extractHlsl += StringFormat::Fmt(" uint evalIndex = idx * %zu;\n", evalSampleCacheData.size()); + + uint32_t evalIdx = 0; + for(const GlobalState::SampleEvalCacheKey &key : evalSampleCacheData) { - // float4 is wasteful in some cases but it's easier than using byte buffers and manual packing - extractHlsl += - StringFormat::Fmt("RWBuffer PSEvalBuffer : register(u2, space%u);\n\n", regSpace); - } + uint32_t keyMask = 0; - if(usePrimitiveID) - { - extractHlsl += R"( -void ExtractInputsPS(PSInput IN, - float4 debug_pixelPos : SV_Position, - uint prim : SV_PrimitiveID, - uint fface : SV_IsFrontFace, - uint sample : SV_SampleIndex, - uint covge : SV_Coverage) -{ -)"; - } - else - { - extractHlsl += R"( -void ExtractInputsPS(PSInput IN, - float4 debug_pixelPos : SV_Position, - uint fface : SV_IsFrontFace, - uint sample : SV_SampleIndex, - uint covge : SV_Coverage) -{ -)"; - } + for(int32_t i = 0; i < key.numComponents; i++) + keyMask |= (1 << (key.firstComponent + i)); - extractHlsl += " uint idx = " + ToStr(overdrawLevels) + ";\n"; - extractHlsl += StringFormat::Fmt( - " if(abs(debug_pixelPos.x - %u.5) < 0.5f && abs(debug_pixelPos.y - %u.5) < 0.5f)\n", x, y); - extractHlsl += " InterlockedAdd(PSInitialBuffer[0].hit, 1, idx);\n\n"; - extractHlsl += " idx = min(idx, " + ToStr(overdrawLevels) + ");\n\n"; - extractHlsl += " PSInitialBuffer[idx].pos = debug_pixelPos.xyz;\n"; - - if(usePrimitiveID) - extractHlsl += " PSInitialBuffer[idx].prim = prim;\n"; - else - extractHlsl += " PSInitialBuffer[idx].prim = 0;\n"; - - extractHlsl += " PSInitialBuffer[idx].fface = fface;\n"; - extractHlsl += " PSInitialBuffer[idx].covge = covge;\n"; - extractHlsl += " PSInitialBuffer[idx].sample = sample;\n"; - extractHlsl += " PSInitialBuffer[idx].IN = IN;\n"; - extractHlsl += " PSInitialBuffer[idx].derivValid = ddx(debug_pixelPos.x);\n"; - extractHlsl += " PSInitialBuffer[idx].INddx = (PSInput)0;\n"; - extractHlsl += " PSInitialBuffer[idx].INddy = (PSInput)0;\n"; - extractHlsl += " PSInitialBuffer[idx].INddxfine = (PSInput)0;\n"; - extractHlsl += " PSInitialBuffer[idx].INddyfine = (PSInput)0;\n"; - - if(!evalSampleCacheData.empty()) - { - extractHlsl += StringFormat::Fmt(" uint evalIndex = idx * %zu;\n", evalSampleCacheData.size()); - - uint32_t evalIdx = 0; - for(const GlobalState::SampleEvalCacheKey &key : evalSampleCacheData) + // find the name of the variable matching the operand, in the case of merged input variables. + rdcstr name, swizzle = "xyzw"; + for(size_t i = 0; i < dxbc->GetReflection()->InputSig.size(); i++) { - uint32_t keyMask = 0; - - for(int32_t i = 0; i < key.numComponents; i++) - keyMask |= (1 << (key.firstComponent + i)); - - // find the name of the variable matching the operand, in the case of merged input variables. - rdcstr name, swizzle = "xyzw"; - for(size_t i = 0; i < dxbc->GetReflection()->InputSig.size(); i++) + if(dxbc->GetReflection()->InputSig[i].regIndex == (uint32_t)key.inputRegisterIndex && + dxbc->GetReflection()->InputSig[i].systemValue == ShaderBuiltin::Undefined && + (dxbc->GetReflection()->InputSig[i].regChannelMask & keyMask) == keyMask) { - if(dxbc->GetReflection()->InputSig[i].regIndex == (uint32_t)key.inputRegisterIndex && - dxbc->GetReflection()->InputSig[i].systemValue == ShaderBuiltin::Undefined && - (dxbc->GetReflection()->InputSig[i].regChannelMask & keyMask) == keyMask) - { - name = inputVarNames[i]; + name = inputVarNames[i]; - if(!name.empty()) - break; - } + if(!name.empty()) + break; } - - swizzle.resize(key.numComponents); - - if(name.empty()) - { - RDCERR("Couldn't find matching input variable for v%d [%d:%d]", key.inputRegisterIndex, - key.firstComponent, key.numComponents); - extractHlsl += StringFormat::Fmt(" PSEvalBuffer[evalIndex+%u] = 0;\n", evalIdx); - evalIdx++; - continue; - } - - name = StringFormat::Fmt("IN.%s.%s", name.c_str(), swizzle.c_str()); - - // we must write all components, so just swizzle the values - they'll be ignored later. - rdcstr expandSwizzle = swizzle; - while(expandSwizzle.size() < 4) - expandSwizzle.push_back('x'); - - if(key.sample >= 0) - { - extractHlsl += StringFormat::Fmt( - " PSEvalBuffer[evalIndex+%u] = EvaluateAttributeAtSample(%s, %d).%s;\n", evalIdx, - name.c_str(), key.sample, expandSwizzle.c_str()); - } - else - { - // we don't need to special-case EvaluateAttributeAtCentroid, since it's just a case with - // 0,0 - extractHlsl += StringFormat::Fmt( - " PSEvalBuffer[evalIndex+%u] = EvaluateAttributeSnapped(%s, int2(%d, %d)).%s;\n", - evalIdx, name.c_str(), key.offsetx, key.offsety, expandSwizzle.c_str()); - } - evalIdx++; } - } - for(size_t i = 0; i < floatInputs.size(); i++) - { - const rdcstr &name = floatInputs[i]; - extractHlsl += " PSInitialBuffer[idx].INddx." + name + " = ddx(IN." + name + ");\n"; - extractHlsl += " PSInitialBuffer[idx].INddy." + name + " = ddy(IN." + name + ");\n"; - extractHlsl += " PSInitialBuffer[idx].INddxfine." + name + " = ddx_fine(IN." + name + ");\n"; - extractHlsl += " PSInitialBuffer[idx].INddyfine." + name + " = ddy_fine(IN." + name + ");\n"; - } - extractHlsl += "\n}"; + swizzle.resize(key.numComponents); - // Create pixel shader to get initial values from previous stage output - ID3DBlob *psBlob = NULL; - UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS; + if(name.empty()) + { + RDCERR("Couldn't find matching input variable for v%d [%d:%d]", key.inputRegisterIndex, + key.firstComponent, key.numComponents); + extractHlsl += StringFormat::Fmt(" PSEvalBuffer[evalIndex+%u] = 0;\n", evalIdx); + evalIdx++; + continue; + } + + name = StringFormat::Fmt("IN.%s.%s", name.c_str(), swizzle.c_str()); + + // we must write all components, so just swizzle the values - they'll be ignored later. + rdcstr expandSwizzle = swizzle; + while(expandSwizzle.size() < 4) + expandSwizzle.push_back('x'); + + if(key.sample >= 0) + { + extractHlsl += StringFormat::Fmt( + " PSEvalBuffer[evalIndex+%u] = EvaluateAttributeAtSample(%s, %d).%s;\n", evalIdx, + name.c_str(), key.sample, expandSwizzle.c_str()); + } + else + { + // we don't need to special-case EvaluateAttributeAtCentroid, since it's just a case with 0,0 + extractHlsl += StringFormat::Fmt( + " PSEvalBuffer[evalIndex+%u] = EvaluateAttributeSnapped(%s, int2(%d, %d)).%s;\n", + evalIdx, name.c_str(), key.offsetx, key.offsety, expandSwizzle.c_str()); + } + evalIdx++; + } + } + + for(size_t i = 0; i < floatInputs.size(); i++) + { + const rdcstr &name = floatInputs[i]; + extractHlsl += " PSInitialBuffer[idx].INddx." + name + " = ddx(IN." + name + ");\n"; + extractHlsl += " PSInitialBuffer[idx].INddy." + name + " = ddy(IN." + name + ");\n"; + extractHlsl += " PSInitialBuffer[idx].INddxfine." + name + " = ddx_fine(IN." + name + ");\n"; + extractHlsl += " PSInitialBuffer[idx].INddyfine." + name + " = ddy_fine(IN." + name + ");\n"; + } + extractHlsl += "\n}"; + + // Create pixel shader to get initial values from previous stage output + ID3DBlob *psBlob = NULL; + UINT flags = D3DCOMPILE_WARNINGS_ARE_ERRORS; + if(dxbc->GetDXBCByteCode()) + { if(m_pDevice->GetShaderCache()->GetShaderBlob(extractHlsl.c_str(), "ExtractInputsPS", flags, {}, "ps_5_1", &psBlob) != "") { RDCERR("Failed to create shader to extract inputs"); return new ShaderDebugTrace; } + } + else + { + if(m_pDevice->GetShaderCache()->GetShaderBlob(extractHlsl.c_str(), "ExtractInputsPS", flags, {}, + "ps_6_0", &psBlob) != "") + { + RDCERR("Failed to create shader to extract inputs"); + return new ShaderDebugTrace; + } + } - uint32_t structStride = - sizeof(uint32_t) // uint hit; - + sizeof(float) * 3 // float3 pos; - + sizeof(uint32_t) // uint prim; - + sizeof(uint32_t) // uint fface; - + sizeof(uint32_t) // uint sample; - + sizeof(uint32_t) // uint covge; - + sizeof(float) // float derivValid; - + structureStride * 5; // PSInput IN, INddx, INddy, INddxfine, INddyfine; + uint32_t structStride = sizeof(uint32_t) // uint hit; + + sizeof(float) * 3 // float3 pos; + + sizeof(uint32_t) // uint prim; + + sizeof(uint32_t) // uint fface; + + sizeof(uint32_t) // uint sample; + + sizeof(uint32_t) // uint covge; + + sizeof(float) // float derivValid; + + + structureStride * 5; // PSInput IN, INddx, INddy, INddxfine, INddyfine; - HRESULT hr = S_OK; + HRESULT hr = S_OK; - // Create buffer to store initial values captured in pixel shader - D3D12_RESOURCE_DESC rdesc; - ZeroMemory(&rdesc, sizeof(D3D12_RESOURCE_DESC)); - rdesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - rdesc.Width = structStride * (overdrawLevels + 1); - 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; // TODO: Support MSAA - rdesc.SampleDesc.Quality = 0; + // Create buffer to store initial values captured in pixel shader + D3D12_RESOURCE_DESC rdesc; + ZeroMemory(&rdesc, sizeof(D3D12_RESOURCE_DESC)); + rdesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + rdesc.Width = structStride * (overdrawLevels + 1); + 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; // TODO: Support MSAA + 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; + 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; - ID3D12Resource *pInitialValuesBuffer = NULL; - D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + ID3D12Resource *pInitialValuesBuffer = NULL; + D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, resourceState, + NULL, __uuidof(ID3D12Resource), + (void **)&pInitialValuesBuffer); + if(FAILED(hr)) + { + RDCERR("Failed to create buffer for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(psBlob); + return new ShaderDebugTrace; + } + + // Create buffer to store MSAA evaluations captured in pixel shader + ID3D12Resource *pMsaaEvalBuffer = NULL; + if(!evalSampleCacheData.empty()) + { + rdesc.Width = UINT(evalSampleCacheData.size() * sizeof(Vec4f) * (overdrawLevels + 1)); hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, resourceState, NULL, __uuidof(ID3D12Resource), - (void **)&pInitialValuesBuffer); + (void **)&pMsaaEvalBuffer); if(FAILED(hr)) { - RDCERR("Failed to create buffer for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); + RDCERR("Failed to create MSAA buffer for pixel shader debugging HRESULT: %s", + ToStr(hr).c_str()); + SAFE_RELEASE(pInitialValuesBuffer); SAFE_RELEASE(psBlob); return new ShaderDebugTrace; } + } - // Create buffer to store MSAA evaluations captured in pixel shader - ID3D12Resource *pMsaaEvalBuffer = NULL; - if(!evalSampleCacheData.empty()) - { - rdesc.Width = UINT(evalSampleCacheData.size() * sizeof(Vec4f) * (overdrawLevels + 1)); - hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, - resourceState, NULL, __uuidof(ID3D12Resource), - (void **)&pMsaaEvalBuffer); - if(FAILED(hr)) - { - RDCERR("Failed to create MSAA buffer for pixel shader debugging HRESULT: %s", - ToStr(hr).c_str()); - SAFE_RELEASE(pInitialValuesBuffer); - SAFE_RELEASE(psBlob); - return new ShaderDebugTrace; - } - } + // Create UAV of initial values buffer + 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 = overdrawLevels + 1; + uavDesc.Buffer.StructureByteStride = structStride; - // Create UAV of initial values buffer - 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 = overdrawLevels + 1; - uavDesc.Buffer.StructureByteStride = structStride; + D3D12_CPU_DESCRIPTOR_HANDLE uav = m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV); + m_pDevice->CreateUnorderedAccessView(pInitialValuesBuffer, NULL, &uavDesc, uav); - D3D12_CPU_DESCRIPTOR_HANDLE uav = m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV); - m_pDevice->CreateUnorderedAccessView(pInitialValuesBuffer, NULL, &uavDesc, uav); + uavDesc.Format = DXGI_FORMAT_R32_UINT; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = structStride * (overdrawLevels + 1) / sizeof(uint32_t); + uavDesc.Buffer.StructureByteStride = 0; + D3D12_CPU_DESCRIPTOR_HANDLE clearUav = + m_pDevice->GetDebugManager()->GetUAVClearHandle(SHADER_DEBUG_UAV); + m_pDevice->CreateUnorderedAccessView(pInitialValuesBuffer, NULL, &uavDesc, clearUav); + + // Create UAV of MSAA eval buffer + D3D12_CPU_DESCRIPTOR_HANDLE msaaClearUav = + m_pDevice->GetDebugManager()->GetUAVClearHandle(SHADER_DEBUG_MSAA_UAV); + if(pMsaaEvalBuffer) + { + D3D12_CPU_DESCRIPTOR_HANDLE msaaUav = + m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_MSAA_UAV); + uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + uavDesc.Buffer.NumElements = (overdrawLevels + 1) * (uint32_t)evalSampleCacheData.size(); + m_pDevice->CreateUnorderedAccessView(pMsaaEvalBuffer, NULL, &uavDesc, msaaUav); uavDesc.Format = DXGI_FORMAT_R32_UINT; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.NumElements = structStride * (overdrawLevels + 1) / sizeof(uint32_t); - uavDesc.Buffer.StructureByteStride = 0; - D3D12_CPU_DESCRIPTOR_HANDLE clearUav = - m_pDevice->GetDebugManager()->GetUAVClearHandle(SHADER_DEBUG_UAV); - m_pDevice->CreateUnorderedAccessView(pInitialValuesBuffer, NULL, &uavDesc, clearUav); + uavDesc.Buffer.NumElements = + (UINT)evalSampleCacheData.size() * (overdrawLevels + 1) / sizeof(uint32_t); + m_pDevice->CreateUnorderedAccessView(pMsaaEvalBuffer, NULL, &uavDesc, msaaClearUav); + } - // Create UAV of MSAA eval buffer - D3D12_CPU_DESCRIPTOR_HANDLE msaaClearUav = - m_pDevice->GetDebugManager()->GetUAVClearHandle(SHADER_DEBUG_MSAA_UAV); - if(pMsaaEvalBuffer) - { - D3D12_CPU_DESCRIPTOR_HANDLE msaaUav = - m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_MSAA_UAV); - uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; - uavDesc.Buffer.NumElements = (overdrawLevels + 1) * (uint32_t)evalSampleCacheData.size(); - m_pDevice->CreateUnorderedAccessView(pMsaaEvalBuffer, NULL, &uavDesc, msaaUav); + // Create the descriptor table for our UAV + D3D12_DESCRIPTOR_RANGE1 descRange; + descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + descRange.NumDescriptors = pMsaaEvalBuffer ? 2 : 1; + descRange.BaseShaderRegister = 1; + descRange.RegisterSpace = regSpace; + descRange.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + descRange.OffsetInDescriptorsFromTableStart = 0; - uavDesc.Format = DXGI_FORMAT_R32_UINT; - uavDesc.Buffer.NumElements = - (UINT)evalSampleCacheData.size() * (overdrawLevels + 1) / sizeof(uint32_t); - m_pDevice->CreateUnorderedAccessView(pMsaaEvalBuffer, NULL, &uavDesc, msaaClearUav); - } + modsig.Parameters.push_back(D3D12RootSignatureParameter()); + D3D12RootSignatureParameter ¶m = modsig.Parameters.back(); + param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + param.DescriptorTable.NumDescriptorRanges = 1; + param.DescriptorTable.pDescriptorRanges = &descRange; - // Create the descriptor table for our UAV - D3D12_DESCRIPTOR_RANGE1 descRange; - descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - descRange.NumDescriptors = pMsaaEvalBuffer ? 2 : 1; - descRange.BaseShaderRegister = 1; - descRange.RegisterSpace = regSpace; - descRange.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; - descRange.OffsetInDescriptorsFromTableStart = 0; + uint32_t sigElem = uint32_t(modsig.Parameters.size() - 1); - modsig.Parameters.push_back(D3D12RootSignatureParameter()); - D3D12RootSignatureParameter ¶m = modsig.Parameters.back(); - param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - param.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - param.DescriptorTable.NumDescriptorRanges = 1; - param.DescriptorTable.pDescriptorRanges = &descRange; + modsig.Flags &= ~D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; - uint32_t sigElem = uint32_t(modsig.Parameters.size() - 1); - - modsig.Flags &= ~D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS; - - // Create the root signature for gathering initial pixel shader values - bytebuf root = EncodeRootSig(m_pDevice->RootSigVersion(), modsig); - ID3D12RootSignature *pRootSignature = NULL; - hr = m_pDevice->CreateRootSignature(0, root.data(), root.size(), __uuidof(ID3D12RootSignature), - (void **)&pRootSignature); - if(FAILED(hr)) - { - RDCERR("Failed to create root signature for pixel shader debugging HRESULT: %s", - ToStr(hr).c_str()); - SAFE_RELEASE(psBlob); - SAFE_RELEASE(pInitialValuesBuffer); - SAFE_RELEASE(pMsaaEvalBuffer); - return new ShaderDebugTrace; - } - - // All PSO state is the same as the event's, except for the pixel shader and root signature - pipeDesc.PS.BytecodeLength = psBlob->GetBufferSize(); - pipeDesc.PS.pShaderBytecode = psBlob->GetBufferPointer(); - pipeDesc.pRootSignature = pRootSignature; - - ID3D12PipelineState *initialPso = NULL; - hr = m_pDevice->CreatePipeState(pipeDesc, &initialPso); - if(FAILED(hr)) - { - RDCERR("Failed to create PSO for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(psBlob); - SAFE_RELEASE(pInitialValuesBuffer); - SAFE_RELEASE(pMsaaEvalBuffer); - SAFE_RELEASE(pRootSignature); - return new ShaderDebugTrace; - } - - // if we have a depth buffer bound and we are testing EQUAL grab the current depth value for our - // target sample - D3D12_COMPARISON_FUNC depthFunc = pipeDesc.DepthStencilState.DepthFunc; - float existingDepth = -1.0f; - ResourceId depthTarget = rs.dsv.GetResResourceId(); - - if(depthFunc == D3D12_COMPARISON_FUNC_EQUAL && depthTarget != ResourceId()) - { - float depthStencilValue[4] = {}; - PickPixel(depthTarget, x, y, - Subresource(rs.dsv.GetDSV().Texture2DArray.MipSlice, - rs.dsv.GetDSV().Texture2DArray.FirstArraySlice, sample), - CompType::Depth, depthStencilValue); - - existingDepth = depthStencilValue[0]; - } - - ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); - - // clear our UAVs - m_pDevice->GetDebugManager()->SetDescriptorHeaps(cmdList, true, false); - D3D12_GPU_DESCRIPTOR_HANDLE gpuUav = m_pDevice->GetDebugManager()->GetGPUHandle(SHADER_DEBUG_UAV); - UINT zero[4] = {0, 0, 0, 0}; - cmdList->ClearUnorderedAccessViewUint(gpuUav, clearUav, pInitialValuesBuffer, zero, 0, NULL); - - if(pMsaaEvalBuffer) - { - D3D12_GPU_DESCRIPTOR_HANDLE gpuMsaaUav = - m_pDevice->GetDebugManager()->GetGPUHandle(SHADER_DEBUG_MSAA_UAV); - cmdList->ClearUnorderedAccessViewUint(gpuMsaaUav, msaaClearUav, pMsaaEvalBuffer, zero, 0, NULL); - } - - // Add the descriptor for our UAV - std::set copiedHeaps; - rdcarray debugHandles; - debugHandles.push_back(ToPortableHandle(GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV))); - if(pMsaaEvalBuffer) - debugHandles.push_back(ToPortableHandle(GetDebugManager()->GetCPUHandle(SHADER_DEBUG_MSAA_UAV))); - AddDebugDescriptorsToRenderState(m_pDevice, rs, debugHandles, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, sigElem, copiedHeaps); - - rs.ApplyDescriptorHeaps(cmdList); - - // Execute the command to ensure that UAV clear and resource creation occur before replay - hr = cmdList->Close(); - if(FAILED(hr)) - { - RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(psBlob); - SAFE_RELEASE(pInitialValuesBuffer); - SAFE_RELEASE(pMsaaEvalBuffer); - SAFE_RELEASE(pRootSignature); - SAFE_RELEASE(initialPso); - return new ShaderDebugTrace; - } - - { - ID3D12CommandList *l = cmdList; - m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); - m_pDevice->GPUSync(); - } - - { - D3D12MarkerRegion initState(m_pDevice->GetQueue()->GetReal(), - "Replaying event for initial states"); - - // Set the PSO and root signature - rs.pipe = GetResID(initialPso); - rs.graphics.rootsig = GetResID(pRootSignature); - - // Replay the event with our modified state - m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); - - // Restore D3D12 state to what the event uses - rs = prevState; - } - - bytebuf initialData; - m_pDevice->GetDebugManager()->GetBufferData(pInitialValuesBuffer, 0, 0, initialData); - - bytebuf evalData; - if(pMsaaEvalBuffer) - m_pDevice->GetDebugManager()->GetBufferData(pMsaaEvalBuffer, 0, 0, evalData); - - // Replaying the event has finished, and the data has been copied out. - // Free all the resources that were created. + // Create the root signature for gathering initial pixel shader values + bytebuf root = EncodeRootSig(m_pDevice->RootSigVersion(), modsig); + ID3D12RootSignature *pRootSignature = NULL; + hr = m_pDevice->CreateRootSignature(0, root.data(), root.size(), __uuidof(ID3D12RootSignature), + (void **)&pRootSignature); + if(FAILED(hr)) + { + RDCERR("Failed to create root signature for pixel shader debugging HRESULT: %s", + ToStr(hr).c_str()); SAFE_RELEASE(psBlob); - SAFE_RELEASE(pRootSignature); SAFE_RELEASE(pInitialValuesBuffer); SAFE_RELEASE(pMsaaEvalBuffer); + return new ShaderDebugTrace; + } + + // All PSO state is the same as the event's, except for the pixel shader and root signature + pipeDesc.PS.BytecodeLength = psBlob->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = psBlob->GetBufferPointer(); + pipeDesc.pRootSignature = pRootSignature; + + ID3D12PipelineState *initialPso = NULL; + hr = m_pDevice->CreatePipeState(pipeDesc, &initialPso); + if(FAILED(hr)) + { + RDCERR("Failed to create PSO for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(psBlob); + SAFE_RELEASE(pInitialValuesBuffer); + SAFE_RELEASE(pMsaaEvalBuffer); + SAFE_RELEASE(pRootSignature); + return new ShaderDebugTrace; + } + + // if we have a depth buffer bound and we are testing EQUAL grab the current depth value for our target sample + D3D12_COMPARISON_FUNC depthFunc = pipeDesc.DepthStencilState.DepthFunc; + float existingDepth = -1.0f; + ResourceId depthTarget = rs.dsv.GetResResourceId(); + + if(depthFunc == D3D12_COMPARISON_FUNC_EQUAL && depthTarget != ResourceId()) + { + float depthStencilValue[4] = {}; + PickPixel(depthTarget, x, y, + Subresource(rs.dsv.GetDSV().Texture2DArray.MipSlice, + rs.dsv.GetDSV().Texture2DArray.FirstArraySlice, sample), + CompType::Depth, depthStencilValue); + + existingDepth = depthStencilValue[0]; + } + + ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); + + // clear our UAVs + m_pDevice->GetDebugManager()->SetDescriptorHeaps(cmdList, true, false); + D3D12_GPU_DESCRIPTOR_HANDLE gpuUav = m_pDevice->GetDebugManager()->GetGPUHandle(SHADER_DEBUG_UAV); + UINT zero[4] = {0, 0, 0, 0}; + cmdList->ClearUnorderedAccessViewUint(gpuUav, clearUav, pInitialValuesBuffer, zero, 0, NULL); + + if(pMsaaEvalBuffer) + { + D3D12_GPU_DESCRIPTOR_HANDLE gpuMsaaUav = + m_pDevice->GetDebugManager()->GetGPUHandle(SHADER_DEBUG_MSAA_UAV); + cmdList->ClearUnorderedAccessViewUint(gpuMsaaUav, msaaClearUav, pMsaaEvalBuffer, zero, 0, NULL); + } + + // Add the descriptor for our UAV + std::set copiedHeaps; + rdcarray debugHandles; + debugHandles.push_back(ToPortableHandle(GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV))); + if(pMsaaEvalBuffer) + debugHandles.push_back(ToPortableHandle(GetDebugManager()->GetCPUHandle(SHADER_DEBUG_MSAA_UAV))); + AddDebugDescriptorsToRenderState(m_pDevice, rs, debugHandles, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, sigElem, copiedHeaps); + + rs.ApplyDescriptorHeaps(cmdList); + + // Execute the command to ensure that UAV clear and resource creation occur before replay + hr = cmdList->Close(); + if(FAILED(hr)) + { + RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(psBlob); + SAFE_RELEASE(pInitialValuesBuffer); + SAFE_RELEASE(pMsaaEvalBuffer); + SAFE_RELEASE(pRootSignature); SAFE_RELEASE(initialPso); + return new ShaderDebugTrace; + } - DebugHit *buf = (DebugHit *)initialData.data(); + { + ID3D12CommandList *l = cmdList; + m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); + m_pDevice->GPUSync(); + } - D3D12MarkerRegion::Set(m_pDevice->GetQueue()->GetReal(), - StringFormat::Fmt("Got %u hits", buf[0].numHits)); - if(buf[0].numHits == 0) + { + D3D12MarkerRegion initState(m_pDevice->GetQueue()->GetReal(), + "Replaying event for initial states"); + + // Set the PSO and root signature + rs.pipe = GetResID(initialPso); + rs.graphics.rootsig = GetResID(pRootSignature); + + // Replay the event with our modified state + m_pDevice->ReplayLog(0, eventId, eReplay_OnlyDraw); + + // Restore D3D12 state to what the event uses + rs = prevState; + } + + bytebuf initialData; + m_pDevice->GetDebugManager()->GetBufferData(pInitialValuesBuffer, 0, 0, initialData); + + bytebuf evalData; + if(pMsaaEvalBuffer) + m_pDevice->GetDebugManager()->GetBufferData(pMsaaEvalBuffer, 0, 0, evalData); + + // Replaying the event has finished, and the data has been copied out. + // Free all the resources that were created. + SAFE_RELEASE(psBlob); + SAFE_RELEASE(pRootSignature); + SAFE_RELEASE(pInitialValuesBuffer); + SAFE_RELEASE(pMsaaEvalBuffer); + SAFE_RELEASE(initialPso); + + DebugHit *buf = (DebugHit *)initialData.data(); + + D3D12MarkerRegion::Set(m_pDevice->GetQueue()->GetReal(), + StringFormat::Fmt("Got %u hits", buf[0].numHits)); + if(buf[0].numHits == 0) + { + RDCLOG("No hit for this event"); + return new ShaderDebugTrace; + } + + // if we encounter multiple hits at our destination pixel co-ord (or any other) we check to see if + // a specific primitive was requested (via primitive parameter not being set to ~0U). If it was, + // debug that pixel, otherwise do a best-estimate of which fragment was the last to successfully + // depth test and debug that, just by checking if the depth test is ordered and picking the final + // fragment in the series + + // figure out the TL pixel's coords. Assume even top left (towards 0,0) + // this isn't spec'd but is a reasonable assumption. + int xTL = x & (~1); + int yTL = y & (~1); + + // get the index of our desired pixel + int destIdx = (x - xTL) + 2 * (y - yTL); + + // Get depth func and determine "winner" pixel + DebugHit *pWinnerHit = NULL; + float *evalSampleCache = (float *)evalData.data(); + + if(sample == ~0U) + sample = 0; + + if(primitive != ~0U) + { + for(size_t i = 0; i < buf[0].numHits && i < overdrawLevels; i++) { - RDCLOG("No hit for this event"); - return new ShaderDebugTrace; - } + DebugHit *pHit = (DebugHit *)(initialData.data() + i * structStride); - // if we encounter multiple hits at our destination pixel co-ord (or any other) we - // check to see if a specific primitive was requested (via primitive parameter not - // being set to ~0U). If it was, debug that pixel, otherwise do a best-estimate - // of which fragment was the last to successfully depth test and debug that, just by - // checking if the depth test is ordered and picking the final fragment in the series - - // figure out the TL pixel's coords. Assume even top left (towards 0,0) - // this isn't spec'd but is a reasonable assumption. - int xTL = x & (~1); - int yTL = y & (~1); - - // get the index of our desired pixel - int destIdx = (x - xTL) + 2 * (y - yTL); - - // Get depth func and determine "winner" pixel - DebugHit *pWinnerHit = NULL; - float *evalSampleCache = (float *)evalData.data(); - - if(sample == ~0U) - sample = 0; - - if(primitive != ~0U) - { - for(size_t i = 0; i < buf[0].numHits && i < overdrawLevels; i++) + if(pHit->primitive == primitive && pHit->sample == sample) { - DebugHit *pHit = (DebugHit *)(initialData.data() + i * structStride); - - if(pHit->primitive == primitive && pHit->sample == sample) - { - pWinnerHit = pHit; - evalSampleCache = ((float *)evalData.data() + evalSampleCacheData.size() * 4 * i); - } + pWinnerHit = pHit; + evalSampleCache = ((float *)evalData.data() + evalSampleCacheData.size() * 4 * i); } } + } - if(pWinnerHit == NULL) + if(pWinnerHit == NULL) + { + for(size_t i = 0; i < buf[0].numHits && i < overdrawLevels; i++) { - for(size_t i = 0; i < buf[0].numHits && i < overdrawLevels; i++) - { - DebugHit *pHit = (DebugHit *)(initialData.data() + i * structStride); + DebugHit *pHit = (DebugHit *)(initialData.data() + i * structStride); - if(pWinnerHit == NULL) + if(pWinnerHit == NULL) + { + // If we haven't picked a winner at all yet, use the first one + pWinnerHit = pHit; + evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; + } + else if(pHit->sample == sample) + { + // If this hit is for the sample we want, check whether it's a better pick + if(pWinnerHit->sample != sample) { - // If we haven't picked a winner at all yet, use the first one + // The previously selected winner was for the wrong sample, use this one pWinnerHit = pHit; evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; } - else if(pHit->sample == sample) + else if(depthFunc == D3D12_COMPARISON_FUNC_EQUAL && existingDepth >= 0.0f) { - // If this hit is for the sample we want, check whether it's a better pick - if(pWinnerHit->sample != sample) + // for depth equal, check if this hit is closer than the winner, and if so use it. + if(fabs(pHit->depth - existingDepth) < fabs(pWinnerHit->depth - existingDepth)) { - // The previously selected winner was for the wrong sample, use this one - pWinnerHit = pHit; - evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; - } - else if(depthFunc == D3D12_COMPARISON_FUNC_EQUAL && existingDepth >= 0.0f) - { - // for depth equal, check if this hit is closer than the winner, and if so use it. - if(fabs(pHit->depth - existingDepth) < fabs(pWinnerHit->depth - existingDepth)) - { - pWinnerHit = pHit; - evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; - } - } - else if(depthFunc == D3D12_COMPARISON_FUNC_ALWAYS || - depthFunc == D3D12_COMPARISON_FUNC_NEVER || - depthFunc == D3D12_COMPARISON_FUNC_NOT_EQUAL) - { - // For depth functions without a sensible comparison, use the last sample encountered - pWinnerHit = pHit; - evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; - } - else if((depthFunc == D3D12_COMPARISON_FUNC_LESS && pHit->depth < pWinnerHit->depth) || - (depthFunc == D3D12_COMPARISON_FUNC_LESS_EQUAL && pHit->depth <= pWinnerHit->depth) || - (depthFunc == D3D12_COMPARISON_FUNC_GREATER && pHit->depth > pWinnerHit->depth) || - (depthFunc == D3D12_COMPARISON_FUNC_GREATER_EQUAL && - pHit->depth >= pWinnerHit->depth)) - { - // For depth functions with an inequality, find the hit that "wins" the most pWinnerHit = pHit; evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; } } + else if(depthFunc == D3D12_COMPARISON_FUNC_ALWAYS || + depthFunc == D3D12_COMPARISON_FUNC_NEVER || + depthFunc == D3D12_COMPARISON_FUNC_NOT_EQUAL) + { + // For depth functions without a sensible comparison, use the last sample encountered + pWinnerHit = pHit; + evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; + } + else if((depthFunc == D3D12_COMPARISON_FUNC_LESS && pHit->depth < pWinnerHit->depth) || + (depthFunc == D3D12_COMPARISON_FUNC_LESS_EQUAL && pHit->depth <= pWinnerHit->depth) || + (depthFunc == D3D12_COMPARISON_FUNC_GREATER && pHit->depth > pWinnerHit->depth) || + (depthFunc == D3D12_COMPARISON_FUNC_GREATER_EQUAL && pHit->depth >= pWinnerHit->depth)) + { + // For depth functions with an inequality, find the hit that "wins" the most + pWinnerHit = pHit; + evalSampleCache = ((float *)evalData.data()) + evalSampleCacheData.size() * 4 * i; + } } } + } - if(pWinnerHit == NULL) - { - RDCLOG("Couldn't find any pixels that passed depth test at target coordinates"); - return new ShaderDebugTrace; - } + if(pWinnerHit == NULL) + { + RDCLOG("Couldn't find any pixels that passed depth test at target coordinates"); + return new ShaderDebugTrace; + } + DebugHit *pHit = pWinnerHit; + uint32_t *data = &pHit->rawdata; + float *pos_ddx = (float *)data; + + // ddx(SV_Position.x) MUST be 1.0 + if(*pos_ddx != 1.0f) + { + RDCERR("Derivatives invalid"); + delete ret; + return new ShaderDebugTrace; + } + data++; + + if(dxbc->GetDXBCByteCode()) + { InterpretDebugger *interpreter = new InterpretDebugger; interpreter->eventId = eventId; ret = interpreter->BeginDebug(dxbc, refl, destIdx); @@ -2679,8 +2736,6 @@ void ExtractInputsPS(PSInput IN, global.sampleEvalRegisterMask = sampleEvalRegisterMask; { - DebugHit *pHit = pWinnerHit; - rdcarray &ins = state.inputs; if(!ins.empty() && ins.back().name == "vCoverage") ins.back().value.u32v[0] = pHit->coverage; @@ -2689,21 +2744,6 @@ void ExtractInputsPS(PSInput IN, state.semantics.primID = pHit->primitive; state.semantics.isFrontFace = pHit->isFrontFace; - uint32_t *data = &pHit->rawdata; - - float *pos_ddx = (float *)data; - - // ddx(SV_Position.x) MUST be 1.0 - if(*pos_ddx != 1.0f) - { - RDCERR("Derivatives invalid"); - delete interpreter; - delete ret; - return new ShaderDebugTrace; - } - - data++; - for(size_t i = 0; i < initialValues.size(); i++) { int32_t *rawout = NULL; @@ -2780,7 +2820,7 @@ void ExtractInputsPS(PSInput IN, } else { - RDCERR("TODO ADD DXIL PIXEL SHADER DEBUGGER SUPPORT"); + RDCERR("DXIL Pixel Shader Debugging is not supported"); } if(ret) @@ -2914,7 +2954,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, } else { - RDCERR("TODO ADD DXIL COMPUTE SHADER DEBUGGER SUPPORT"); + RDCERR("DXIL Compute Shader Debugging is not supported"); } if(ret)