diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index 1fd7feeca..b8de72e7e 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -2277,8 +2277,34 @@ void BufferViewer::stageRowMenu(MeshDataStage stage, QMenu *menu, const QPoint & menu->clear(); - if(m_MeshView && stage != MeshDataStage::GSOut && m_Ctx.APIProps().shaderDebugging) + menu->setToolTipsVisible(true); + + if(m_MeshView && stage != MeshDataStage::GSOut) { + const ShaderReflection *shaderDetails = + m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Vertex); + + m_DebugVert->setEnabled(false); + + if(!m_Ctx.APIProps().shaderDebugging) + { + m_DebugVert->setToolTip(tr("This API does not support shader debugging")); + } + else if(!shaderDetails) + { + m_DebugVert->setToolTip(tr("No vertex shader bound")); + } + else if(!shaderDetails->debugInfo.debuggable) + { + m_DebugVert->setToolTip( + tr("This shader doesn't support debugging: %1").arg(shaderDetails->debugInfo.debugStatus)); + } + else + { + m_DebugVert->setEnabled(true); + m_DebugVert->setToolTip(QString()); + } + menu->addAction(m_DebugVert); menu->addSeparator(); } diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index bd6038fce..03a5c835c 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -1846,7 +1846,9 @@ void D3D11PipelineStateViewer::setState() ui->stencils->endUpdate(); // set up thread debugging inputs - if(state.computeShader.reflection && draw && (draw->flags & DrawFlags::Dispatch)) + if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && + state.computeShader.reflection->debugInfo.debuggable && draw && + (draw->flags & DrawFlags::Dispatch)) { ui->groupX->setEnabled(true); ui->groupY->setEnabled(true); @@ -1875,6 +1877,8 @@ void D3D11PipelineStateViewer::setState() ui->threadY->setMaximum((int)draw->dispatchThreadsDimension[1] - 1); ui->threadZ->setMaximum((int)draw->dispatchThreadsDimension[2] - 1); } + + ui->debugThread->setToolTip(QString()); } else { @@ -1887,6 +1891,16 @@ void D3D11PipelineStateViewer::setState() ui->threadZ->setEnabled(false); ui->debugThread->setEnabled(false); + + if(!m_Ctx.APIProps().shaderDebugging) + ui->debugThread->setToolTip(tr("This API does not support shader debugging")); + else if(!draw || !(draw->flags & DrawFlags::Dispatch)) + ui->debugThread->setToolTip(tr("No dispatch selected")); + else if(!state.computeShader.reflection) + ui->debugThread->setToolTip(tr("No compute shader bound")); + else if(!state.computeShader.reflection->debugInfo.debuggable) + ui->debugThread->setToolTip(tr("This shader doesn't support debugging: %1") + .arg(state.computeShader.reflection->debugInfo.debugStatus)); } // highlight the appropriate stages in the flowchart diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 75e831caf..52d4030d7 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -1817,7 +1817,8 @@ void D3D12PipelineStateViewer::setState() ui->stencils->endUpdate(); // set up thread debugging inputs - if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && draw && + if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && + state.computeShader.reflection->debugInfo.debuggable && draw && (draw->flags & DrawFlags::Dispatch)) { ui->groupX->setEnabled(true); @@ -1847,6 +1848,8 @@ void D3D12PipelineStateViewer::setState() ui->threadY->setMaximum((int)draw->dispatchThreadsDimension[1] - 1); ui->threadZ->setMaximum((int)draw->dispatchThreadsDimension[2] - 1); } + + ui->debugThread->setToolTip(QString()); } else { @@ -1859,6 +1862,16 @@ void D3D12PipelineStateViewer::setState() ui->threadZ->setEnabled(false); ui->debugThread->setEnabled(false); + + if(!m_Ctx.APIProps().shaderDebugging) + ui->debugThread->setToolTip(tr("This API does not support shader debugging")); + else if(!draw || !(draw->flags & DrawFlags::Dispatch)) + ui->debugThread->setToolTip(tr("No dispatch selected")); + else if(!state.computeShader.reflection) + ui->debugThread->setToolTip(tr("No compute shader bound")); + else if(!state.computeShader.reflection->debugInfo.debuggable) + ui->debugThread->setToolTip(tr("This shader doesn't support debugging: %1") + .arg(state.computeShader.reflection->debugInfo.debugStatus)); } // highlight the appropriate stages in the flowchart diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index a4704fb5a..85d96de7c 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -2539,7 +2539,8 @@ void VulkanPipelineStateViewer::setState() ui->stencils->endUpdate(); // set up thread debugging inputs - if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && draw && + if(m_Ctx.APIProps().shaderDebugging && state.computeShader.reflection && + state.computeShader.reflection->debugInfo.debuggable && draw && (draw->flags & DrawFlags::Dispatch)) { ui->groupX->setEnabled(true); @@ -2569,6 +2570,8 @@ void VulkanPipelineStateViewer::setState() ui->threadY->setMaximum((int)draw->dispatchThreadsDimension[1] - 1); ui->threadZ->setMaximum((int)draw->dispatchThreadsDimension[2] - 1); } + + ui->debugThread->setToolTip(QString()); } else { @@ -2581,6 +2584,16 @@ void VulkanPipelineStateViewer::setState() ui->threadZ->setEnabled(false); ui->debugThread->setEnabled(false); + + if(!m_Ctx.APIProps().shaderDebugging) + ui->debugThread->setToolTip(tr("This API does not support shader debugging")); + else if(!draw || !(draw->flags & DrawFlags::Dispatch)) + ui->debugThread->setToolTip(tr("No dispatch selected")); + else if(!state.computeShader.reflection) + ui->debugThread->setToolTip(tr("No compute shader bound")); + else if(!state.computeShader.reflection->debugInfo.debuggable) + ui->debugThread->setToolTip(tr("This shader doesn't support debugging: %1") + .arg(state.computeShader.reflection->debugInfo.debugStatus)); } // highlight the appropriate stages in the flowchart diff --git a/qrenderdoc/Windows/PixelHistoryView.cpp b/qrenderdoc/Windows/PixelHistoryView.cpp index 0ae7f3f7c..6ac927c1f 100644 --- a/qrenderdoc/Windows/PixelHistoryView.cpp +++ b/qrenderdoc/Windows/PixelHistoryView.cpp @@ -716,6 +716,29 @@ void PixelHistoryView::startDebug(EventTag tag) { m_Ctx.SetEventID({this}, tag.eventId, tag.eventId); + const ShaderReflection *shaderDetails = + m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel); + + if(!m_Ctx.APIProps().shaderDebugging) + { + RDDialog::critical(this, tr("Can't debug pixel"), + tr("This API does not support shader debugging")); + return; + } + else if(!shaderDetails) + { + RDDialog::critical(this, tr("Can't debug pixel"), + tr("No pixel shader bound at event %1").arg(tag.eventId)); + return; + } + else if(!shaderDetails->debugInfo.debuggable) + { + RDDialog::critical( + this, tr("Can't debug pixel"), + tr("This shader doesn't support debugging: %1").arg(shaderDetails->debugInfo.debugStatus)); + return; + } + bool done = false; ShaderDebugTrace *trace = NULL; @@ -748,8 +771,6 @@ void PixelHistoryView::startDebug(EventTag tag) return; } - const ShaderReflection *shaderDetails = - m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel); const ShaderBindpointMapping &bindMapping = m_Ctx.CurPipelineState().GetBindpointMapping(ShaderStage::Pixel); ResourceId pipeline = m_Ctx.CurPipelineState().GetGraphicsPipelineObject(); @@ -832,6 +853,14 @@ void PixelHistoryView::on_events_customContextMenuRequested(const QPoint &pos) contextMenu.addAction(&debugAction); + if(!m_Ctx.APIProps().shaderDebugging) + { + debugAction.setToolTip(tr("This API does not support shader debugging")); + debugAction.setEnabled(false); + } + + // can't check if the shader supports debugging here because we don't have its details. + QObject::connect(&jumpAction, &QAction::triggered, [this, tag]() { jumpToPrimitive(tag); }); QObject::connect(&debugAction, &QAction::triggered, [this, tag]() { startDebug(tag); }); diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index db27e2633..050dd3a41 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -500,8 +500,55 @@ void TextureViewer::UI_UpdateCachedTexture() m_CachedTexture = m_Ctx.GetTexture(id); - ui->debugPixelContext->setEnabled(m_Ctx.APIProps().shaderDebugging && m_CachedTexture != NULL); - ui->pixelHistory->setEnabled(m_Ctx.APIProps().pixelHistory && m_CachedTexture != NULL); + if(m_CachedTexture != NULL) + { + if(m_Ctx.APIProps().shaderDebugging) + { + const ShaderReflection *shaderDetails = + m_Ctx.CurPipelineState().GetShaderReflection(ShaderStage::Pixel); + + if(!shaderDetails) + { + ui->debugPixelContext->setEnabled(false); + ui->debugPixelContext->setToolTip(tr("No pixel shader bound")); + } + else if(!shaderDetails->debugInfo.debuggable) + { + ui->debugPixelContext->setEnabled(false); + ui->debugPixelContext->setToolTip( + tr("The current pixel shader does not support debugging: %1") + .arg(shaderDetails->debugInfo.debugStatus)); + } + else + { + ui->debugPixelContext->setEnabled(true); + ui->debugPixelContext->setToolTip(QString()); + } + } + else + { + ui->debugPixelContext->setEnabled(false); + ui->debugPixelContext->setToolTip(tr("Shader Debugging not supported on this API")); + } + + if(m_Ctx.APIProps().pixelHistory) + { + ui->pixelHistory->setEnabled(true); + ui->pixelHistory->setToolTip(QString()); + } + else + { + ui->pixelHistory->setEnabled(false); + ui->pixelHistory->setToolTip(tr("Pixel History not supported on this API")); + } + } + else + { + ui->debugPixelContext->setEnabled(false); + ui->debugPixelContext->setToolTip(tr("No active texture selected")); + ui->pixelHistory->setEnabled(false); + ui->pixelHistory->setToolTip(tr("No active texture selected")); + } } TextureViewer::TextureViewer(ICaptureContext &ctx, QWidget *parent) @@ -2797,27 +2844,11 @@ void TextureViewer::OnCaptureLoaded() ui->locationGoto->setEnabled(true); ui->viewTexBuffer->setEnabled(true); - if(m_Ctx.APIProps().pixelHistory) - { - ui->pixelHistory->setEnabled(true); - ui->pixelHistory->setToolTip(QString()); - } - else - { - ui->pixelHistory->setEnabled(false); - ui->pixelHistory->setToolTip(tr("Pixel History not implemented on this API")); - } + ui->pixelHistory->setEnabled(false); + ui->pixelHistory->setToolTip(QString()); - if(m_Ctx.APIProps().shaderDebugging) - { - ui->debugPixelContext->setEnabled(true); - ui->debugPixelContext->setToolTip(QString()); - } - else - { - ui->debugPixelContext->setEnabled(false); - ui->debugPixelContext->setToolTip(tr("Shader Debugging not implemented on this API")); - } + ui->debugPixelContext->setEnabled(false); + ui->pixelHistory->setToolTip(QString()); TextureListItemModel *model = (TextureListItemModel *)ui->textureList->model(); diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 27844bdd7..d3624d6fe 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -1269,6 +1269,17 @@ The first entry in the list is always the file where the entry point is. DOCUMENT("The :class:`ShaderEncoding` of the source. See :data:`files`."); ShaderEncoding encoding = ShaderEncoding::Unknown; + + DOCUMENT(R"(Indicates whether this particular shader can be debugged. In some cases even if the +API can debug shaders in general, specific shaders cannot be debugged because they use unsupported +functionality +)"); + bool debuggable = true; + + DOCUMENT(R"(If :data:`debuggable` is false then this contains a simple explanation of why the +shader is not supported for debugging +)"); + rdcstr debugStatus; }; DECLARE_REFLECTION_STRUCT(ShaderDebugInfo); diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index 086bc2cd4..42944d5bb 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -1682,12 +1682,6 @@ void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Pro ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx) { - if(!GetAPIProperties().shaderDebugging) - { - RDCUNIMPLEMENTED("Vertex debugging not yet implemented for D3D12"); - return new ShaderDebugTrace; - } - using namespace DXBCBytecode; using namespace DXBCDebug; @@ -1700,13 +1694,25 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui WrappedID3D12Shader *vs = m_pDevice->GetResourceManager()->GetCurrentAs(vertexShader.resourceId); if(!vs) + { + RDCERR("Can't debug with no current vertex shader"); return new ShaderDebugTrace; + } DXBC::DXBCContainer *dxbc = vs->GetDXBC(); const ShaderReflection &refl = vs->GetDetails(); if(!dxbc) + { + RDCERR("Vertex shader couldn't be reflected"); return new ShaderDebugTrace; + } + + if(!refl.debugInfo.debuggable) + { + RDCERR("Vertex shader is not debuggable"); + return new ShaderDebugTrace; + } dxbc->GetDisassembly(); @@ -2050,12 +2056,6 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample, uint32_t primitive) { - if(!GetAPIProperties().shaderDebugging) - { - RDCUNIMPLEMENTED("Pixel debugging not yet implemented for D3D12"); - return new ShaderDebugTrace(); - } - using namespace DXBC; using namespace DXBCBytecode; using namespace DXBCDebug; @@ -2071,13 +2071,25 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t WrappedID3D12Shader *ps = m_pDevice->GetResourceManager()->GetCurrentAs(pixelShader.resourceId); if(!ps) + { + RDCERR("Can't debug with no current pixel shader"); return new ShaderDebugTrace; + } DXBCContainer *dxbc = ps->GetDXBC(); const ShaderReflection &refl = ps->GetDetails(); if(!dxbc) + { + RDCERR("Pixel shader couldn't be reflected"); return new ShaderDebugTrace; + } + + if(!refl.debugInfo.debuggable) + { + RDCERR("Pixel shader is not debuggable"); + return new ShaderDebugTrace; + } dxbc->GetDisassembly(); @@ -2836,12 +2848,6 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, const uint32_t groupid[3], const uint32_t threadid[3]) { - if(!GetAPIProperties().shaderDebugging) - { - RDCUNIMPLEMENTED("Compute shader debugging not yet implemented for D3D12"); - return new ShaderDebugTrace(); - } - using namespace DXBCBytecode; using namespace DXBCDebug; @@ -2855,13 +2861,25 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId, const uint32_t grou WrappedID3D12Shader *cs = m_pDevice->GetResourceManager()->GetCurrentAs(computeShader.resourceId); if(!cs) + { + RDCERR("Can't debug with no current compute shader"); return new ShaderDebugTrace; + } DXBC::DXBCContainer *dxbc = cs->GetDXBC(); const ShaderReflection &refl = cs->GetDetails(); if(!dxbc) + { + RDCERR("Pixel shader couldn't be reflected"); return new ShaderDebugTrace; + } + + if(!refl.debugInfo.debuggable) + { + RDCERR("Pixel shader is not debuggable"); + return new ShaderDebugTrace; + } dxbc->GetDisassembly(); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index 1be53e6a2..c9ce4e266 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -230,6 +230,20 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl, // by default, and SPDB has an extra sorting step that probably maybe possibly does this. } + if(dxbc->GetDXBCByteCode()) + { + refl->debugInfo.debuggable = true; + } + else + { + refl->debugInfo.debuggable = false; + + if(dxbc->GetDXILByteCode()) + refl->debugInfo.debugStatus = "Debugging DXIL is not supported"; + else + refl->debugInfo.debugStatus = "Shader contains no recognised bytecode"; + } + refl->encoding = ShaderEncoding::DXBC; refl->rawBytes = dxbc->m_ShaderBlob; diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index b1c358dc9..7c0ce2d54 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -182,24 +182,18 @@ void Debugger::MakeSignatureNames(const rdcarray &sigList, } } -ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const ShaderStage stage, - const rdcstr &entryPoint, - const rdcarray &specInfo, - const std::map &instructionLines, - const SPIRVPatchData &patchData, uint32_t activeIndex) +// this function is implemented here to keep it next to the code we might need to update, even +// though it's checked at reflection time. +void Reflector::CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const { - Id entryId = entryLookup[entryPoint]; - - if(entryId == Id()) - { - RDCERR("Invalid entry point '%s'", entryPoint.c_str()); - return new ShaderDebugTrace; - } + debuggable = true; + debugStatus.clear(); if(m_MajorVersion > 1 || m_MinorVersion > 5) { - RDCERR("Unsupported SPIR-V version %u.%u", m_MajorVersion, m_MinorVersion); - return new ShaderDebugTrace; + debugStatus += + StringFormat::Fmt("Unsupported SPIR-V version %u.%u\n", m_MajorVersion, m_MinorVersion); + debuggable = false; } // whitelist supported extensions @@ -218,8 +212,8 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader continue; } - RDCERR("Unsupported SPIR-V extension %s", ext.c_str()); - return new ShaderDebugTrace; + debuggable = false; + debugStatus += StringFormat::Fmt("Unsupported SPIR-V extension %s\n", ext.c_str()); } for(Capability c : capabilities) @@ -409,11 +403,40 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader if(!supported) { - RDCERR("Unsupported capability '%s'", ToStr(c).c_str()); - return new ShaderDebugTrace; + debuggable = false; + debugStatus += StringFormat::Fmt("Unsupported capability '%s'\n", ToStr(c).c_str()); } } + for(auto it = extSets.begin(); it != extSets.end(); it++) + { + Id id = it->first; + const rdcstr &setname = it->second; + + if(setname == "GLSL.std.450" || setname.beginsWith("NonSemantic.")) + continue; + + debuggable = false; + debugStatus += StringFormat::Fmt("Unsupported extended instruction set: '%s'\n", setname.c_str()); + } + + debugStatus.trim(); +} + +ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const ShaderStage stage, + const rdcstr &entryPoint, + const rdcarray &specInfo, + const std::map &instructionLines, + const SPIRVPatchData &patchData, uint32_t activeIndex) +{ + Id entryId = entryLookup[entryPoint]; + + if(entryId == Id()) + { + RDCERR("Invalid entry point '%s'", entryPoint.c_str()); + return new ShaderDebugTrace; + } + global.clock = uint64_t(time(NULL)) << 32; for(auto it = extSets.begin(); it != extSets.end(); it++) @@ -441,25 +464,6 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *apiWrapper, const Shader global.extInsts[id] = extinst; } - else - { - RDCERR("Unsupported extended instruction set: %s", setname.c_str()); - return new ShaderDebugTrace; - } - } - - for(const rdcstr &e : extensions) - { - if(e == "SPV_GOOGLE_decorate_string" || e == "SPV_GOOGLE_hlsl_functionality1" || - e == "SPV_EXT_descriptor_indexing") - { - // supported extensions - } - else - { - RDCERR("Unsupported extension '%s'", e.c_str()); - return new ShaderDebugTrace; - } } ShaderDebugTrace *ret = new ShaderDebugTrace; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 40de2c1c6..e7ebccbb3 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -610,6 +610,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st reflection.encoding = ShaderEncoding::SPIRV; reflection.rawBytes.assign((byte *)m_SPIRV.data(), m_SPIRV.size() * sizeof(uint32_t)); + CheckDebuggable(reflection.debugInfo.debuggable, reflection.debugInfo.debugStatus); + const EntryPoint *entry = NULL; for(const EntryPoint &e : entries) { @@ -1675,7 +1677,6 @@ void Reflector::AddSignatureParameter(const bool isInput, const ShaderStage stag } } } - }; // namespace rdcspv #if ENABLED(ENABLE_UNIT_TESTS) diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.h b/renderdoc/driver/shaders/spirv/spirv_reflect.h index 77efeea59..4719cd46d 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.h +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.h @@ -98,6 +98,7 @@ private: virtual void UnregisterOp(Iter iter); rdcstr StringiseConstant(rdcspv::Id id) const; + void CheckDebuggable(bool &debuggable, rdcstr &debugStatus) const; void MakeConstantBlockVariables(const DataType &structType, uint32_t arraySize, uint32_t arrayByteStride, rdcarray &cblock, diff --git a/renderdoc/driver/vulkan/vk_shaderdebug.cpp b/renderdoc/driver/vulkan/vk_shaderdebug.cpp index e821311e3..d15ea975c 100644 --- a/renderdoc/driver/vulkan/vk_shaderdebug.cpp +++ b/renderdoc/driver/vulkan/vk_shaderdebug.cpp @@ -3430,6 +3430,12 @@ ShaderDebugTrace *VulkanReplay::DebugVertex(uint32_t eventId, uint32_t vertid, u VulkanCreationInfo::ShaderModuleReflection &shadRefl = shader.GetReflection(entryPoint, state.graphics.pipeline); + if(!shadRefl.refl.debugInfo.debuggable) + { + RDCLOG("Shader is not debuggable: %s", shadRefl.refl.debugInfo.debugStatus.c_str()); + return new ShaderDebugTrace(); + } + shadRefl.PopulateDisassembly(shader.spirv); VulkanAPIWrapper *apiWrapper = @@ -3635,6 +3641,12 @@ ShaderDebugTrace *VulkanReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_ VulkanCreationInfo::ShaderModuleReflection &shadRefl = shader.GetReflection(entryPoint, state.graphics.pipeline); + if(!shadRefl.refl.debugInfo.debuggable) + { + RDCLOG("Shader is not debuggable: %s", shadRefl.refl.debugInfo.debugStatus.c_str()); + return new ShaderDebugTrace(); + } + shadRefl.PopulateDisassembly(shader.spirv); VulkanAPIWrapper *apiWrapper = @@ -4292,6 +4304,12 @@ ShaderDebugTrace *VulkanReplay::DebugThread(uint32_t eventId, const uint32_t gro VulkanCreationInfo::ShaderModuleReflection &shadRefl = shader.GetReflection(entryPoint, state.compute.pipeline); + if(!shadRefl.refl.debugInfo.debuggable) + { + RDCLOG("Shader is not debuggable: %s", shadRefl.refl.debugInfo.debugStatus.c_str()); + return new ShaderDebugTrace(); + } + shadRefl.PopulateDisassembly(shader.spirv); VulkanAPIWrapper *apiWrapper = diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 001a6674d..ad4990295 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -282,8 +282,10 @@ void DoSerialise(SerialiserType &ser, ShaderDebugInfo &el) SERIALISE_MEMBER(compileFlags); SERIALISE_MEMBER(files); SERIALISE_MEMBER(encoding); + SERIALISE_MEMBER(debuggable); + SERIALISE_MEMBER(debugStatus); - SIZE_CHECK(56); + SIZE_CHECK(80); } template @@ -315,7 +317,7 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el) SERIALISE_MEMBER(pointerTypes); - SIZE_CHECK(336); + SIZE_CHECK(360); } template diff --git a/util/test/rdtest/shared/Buffer_Truncation.py b/util/test/rdtest/shared/Buffer_Truncation.py index 4326fa92d..85d2e6f33 100644 --- a/util/test/rdtest/shared/Buffer_Truncation.py +++ b/util/test/rdtest/shared/Buffer_Truncation.py @@ -120,7 +120,8 @@ class Buffer_Truncation(rdtest.TestCase): if not rdtest.value_compare(outcol.value.fv[0:4], [0.0, 0.0, 0.0, 0.0]): raise rdtest.TestFailureException("expected outcol to be 0s, but got {}".format(outcol.value.fv[0:4])) - if self.controller.GetAPIProperties().shaderDebugging: + if self.controller.GetAPIProperties().shaderDebugging and pipe.GetShaderReflection( + rd.ShaderStage.Pixel).debugInfo.debuggable: # Debug the shader trace: rd.ShaderDebugTrace = self.controller.DebugPixel(int(pipe.GetViewport(0).width/2), int(pipe.GetViewport(0).height/2), diff --git a/util/test/rdtest/shared/Draw_Zoo.py b/util/test/rdtest/shared/Draw_Zoo.py index 453498d5e..d155fbdc2 100644 --- a/util/test/rdtest/shared/Draw_Zoo.py +++ b/util/test/rdtest/shared/Draw_Zoo.py @@ -115,7 +115,7 @@ class Draw_Zoo(rdtest.TestCase): rdtest.log.success("Checked vertex out data in instance {}".format(inst)) - if self.props.shaderDebugging: + if self.props.shaderDebugging and refl.debugInfo.debuggable: for vtx in range(num_verts): if vtx in restarts: continue diff --git a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py index 825336395..ffb609d8e 100644 --- a/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py +++ b/util/test/tests/D3D11/D3D11_CBuffer_Zoo.py @@ -27,9 +27,8 @@ class D3D11_CBuffer_Zoo(rdtest.TestCase): rdtest.log.success("CBuffer variables are as expected") - props: rd.APIProperties = self.controller.GetAPIProperties() - - if props.shaderDebugging: + if self.controller.GetAPIProperties().shaderDebugging and pipe.GetShaderReflection( + rd.ShaderStage.Pixel).debugInfo.debuggable: trace: rd.ShaderDebugTrace = self.controller.DebugPixel(int(pipe.GetViewport(0).width / 2.0), int(pipe.GetViewport(0).height / 2.0), rd.ReplayController.NoPreference, diff --git a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py index a24f217cc..912509bfb 100644 --- a/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py +++ b/util/test/tests/D3D12/D3D12_CBuffer_Zoo.py @@ -64,9 +64,8 @@ class D3D12_CBuffer_Zoo(rdtest.TestCase): rdtest.log.success("CBuffer variables are as expected") - props: rd.APIProperties = self.controller.GetAPIProperties() - - if props.shaderDebugging: + if self.controller.GetAPIProperties().shaderDebugging and pipe.GetShaderReflection( + rd.ShaderStage.Pixel).debugInfo.debuggable: trace: rd.ShaderDebugTrace = self.controller.DebugPixel(int(pipe.GetViewport(0).width / 2.0), int(pipe.GetViewport(0).height / 2.0), rd.ReplayController.NoPreference, diff --git a/util/test/tests/D3D12/D3D12_PrimitiveID.py b/util/test/tests/D3D12/D3D12_PrimitiveID.py index 02e96897c..86bbdb074 100644 --- a/util/test/tests/D3D12/D3D12_PrimitiveID.py +++ b/util/test/tests/D3D12/D3D12_PrimitiveID.py @@ -10,6 +10,10 @@ class D3D12_PrimitiveID(rdtest.TestCase): self.controller.SetFrameEvent(draw.eventId, True) pipe: rd.PipeState = self.controller.GetPipelineState() + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader at {}.".format(draw.name)) + return + trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference, prim) cycles, variables = self.process_trace(trace) diff --git a/util/test/tests/D3D12/D3D12_Resource_Mapping_Zoo.py b/util/test/tests/D3D12/D3D12_Resource_Mapping_Zoo.py index 3fd430e59..edf174e38 100644 --- a/util/test/tests/D3D12/D3D12_Resource_Mapping_Zoo.py +++ b/util/test/tests/D3D12/D3D12_Resource_Mapping_Zoo.py @@ -9,6 +9,10 @@ class D3D12_Resource_Mapping_Zoo(rdtest.TestCase): def test_debug_pixel(self, x, y, test_name): pipe: rd.PipeState = self.controller.GetPipelineState() + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader at {}.".format(test_name)) + return + # Debug the shader trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, rd.ReplayController.NoPreference, rd.ReplayController.NoPreference) diff --git a/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py b/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py index 986e3fbaa..7980ba08d 100644 --- a/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py +++ b/util/test/tests/D3D12/D3D12_Shader_Debug_Zoo.py @@ -24,6 +24,10 @@ class D3D12_Shader_Debug_Zoo(rdtest.TestCase): pipe: rd.PipeState = self.controller.GetPipelineState() + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader at {}.".format(draw.name)) + return + # Loop over every test for test in range(draw.numInstances): # Debug the shader diff --git a/util/test/tests/D3D12/D3D12_Shader_Linkage_Zoo.py b/util/test/tests/D3D12/D3D12_Shader_Linkage_Zoo.py index d43f77e2b..6a8427da5 100644 --- a/util/test/tests/D3D12/D3D12_Shader_Linkage_Zoo.py +++ b/util/test/tests/D3D12/D3D12_Shader_Linkage_Zoo.py @@ -22,6 +22,10 @@ class D3D12_Shader_Linkage_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(drawcall.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader at {}.".format(event_name)) + continue + # Debug the shader trace: rd.ShaderDebugTrace = self.controller.DebugPixel(200, 150, rd.ReplayController.NoPreference, rd.ReplayController.NoPreference) diff --git a/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py b/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py index 17f30c1f7..d4d411ed2 100644 --- a/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py +++ b/util/test/tests/Vulkan/VK_Shader_Debug_Zoo.py @@ -21,6 +21,10 @@ class VK_Shader_Debug_Zoo(rdtest.TestCase): self.controller.SetFrameEvent(section.eventId, False) pipe: rd.PipeState = self.controller.GetPipelineState() + if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable: + rdtest.log.print("Skipping undebuggable shader at {} in {}.".format(child, test_name)) + return + for test in range(section.numInstances): x = 4 * test + 1 y = 4 * child + 1