From ffa70fabdcbcb83801a4ebe480eddda08e4abcc4 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 21 Aug 2025 16:09:40 +0100 Subject: [PATCH] Auto-break on NonSemantic.DebugBreak instructions * This is almost completely worthless as it seems at least NV and amdvlk both actually crash the GPU on this instruction, meaning there's no way to get it to the shader debugger. But on other drivers like radv, or maybe if this is fixed in future, this will be useful. * For this reason it also can't be tested automatically. --- qrenderdoc/Windows/ShaderViewer.cpp | 2 ++ renderdoc/api/replay/replay_enums.h | 5 ++++ .../driver/shaders/spirv/spirv_debug.cpp | 10 ++++++-- renderdoc/driver/shaders/spirv/spirv_debug.h | 4 +++- .../shaders/spirv/spirv_debug_setup.cpp | 24 ++++++++++++++++++- .../shaders/spirv/spirv_disassemble.cpp | 3 +++ .../driver/shaders/spirv/spirv_processor.cpp | 2 ++ .../driver/shaders/spirv/spirv_processor.h | 1 + 8 files changed, 47 insertions(+), 4 deletions(-) diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 267aef6bc..495984e98 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -2617,6 +2617,8 @@ void ShaderViewer::runTo(const rdcarray &runToInstructions, bool forwa if(!m_Trace || m_States.empty()) return; + condition |= ShaderEvents::DebugBreak; + m_VariablesChanged.clear(); bool firstStep = true; diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index c4c8f8d5a..69b4fd81c 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -4879,12 +4879,17 @@ DOCUMENT(R"(A set of flags for events that may occur while debugging a shader .. data:: GeneratedNanOrInf A floating point operation generated a ``NaN`` or ``infinity`` result. + +.. data:: DebugBreak + + A debugbreak event was emitted. )"); enum class ShaderEvents : uint32_t { NoEvent = 0, SampleLoadGather = 0x1, GeneratedNanOrInf = 0x2, + DebugBreak = 0x4, }; BITMASK_OPERATORS(ShaderEvents); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index 0fb4db207..464fc8a46 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -438,6 +438,12 @@ ShaderVariable ThreadState::ReadPointerValue(Id pointer) return debugger.ReadFromPointer(GetSrc(pointer)); } +void ThreadState::DebugBreak() +{ + if(m_State) + m_State->flags |= ShaderEvents::DebugBreak; +} + void ThreadState::SetDst(Id id, const ShaderVariable &val) { if(m_State && ContainsNaNInf(val)) @@ -1567,8 +1573,8 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray const ExtInstDispatcher &dispatch = global.extInsts[extinst]; - // ignore nonsemantic instructions - if(dispatch.nonsemantic) + // ignore nonsemantic instructions that we have no implementations for + if(dispatch.skippedNonsemantic) break; uint32_t instruction = it.word(4); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.h b/renderdoc/driver/shaders/spirv/spirv_debug.h index 4fb3c9d2e..d0853253c 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.h +++ b/renderdoc/driver/shaders/spirv/spirv_debug.h @@ -116,7 +116,7 @@ typedef ShaderVariable (*ExtInstImpl)(ThreadState &, uint32_t, const rdcarray names; rdcarray functions; }; @@ -269,6 +269,8 @@ struct ThreadState void WritePointerValue(Id pointer, const ShaderVariable &val); ShaderVariable ReadPointerValue(Id pointer); + void DebugBreak(); + private: void EnterFunction(const rdcarray &arguments); void SetDst(Id id, const ShaderVariable &val); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp index ac6431c31..1586af5f2 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_setup.cpp @@ -255,6 +255,12 @@ static const void *VarElemPointer(const ShaderVariable &var, uint32_t comp) namespace rdcspv { +ShaderVariable ThreadDebugBreak(ThreadState &state, uint32_t, const rdcarray &) +{ + state.DebugBreak(); + return ShaderVariable("void", 0U, 0U, 0U, 0U); +} + rdcstr GetRawName(Id id) { // 32-bit value means at most 10 decimal digits, plus a preceeding _, plus trailing NULL. @@ -971,13 +977,29 @@ ShaderDebugTrace *Debugger::BeginDebug(DebugAPIWrapper *api, const ShaderStage s global.extInsts[id] = extinst; } + else if(setname == "NonSemantic.DebugBreak") + { + ExtInstDispatcher extinst; + + extinst.name = setname; + + // idx 0 is unused, fill with a dummy function + extinst.names.push_back("__"); + extinst.functions.push_back(&ThreadDebugBreak); + extinst.names.push_back("DebugBreak"); + extinst.functions.push_back(&ThreadDebugBreak); + + global.extInsts[id] = extinst; + + RDCLOG("extinst set %u is debug break", id.value()); + } else if(setname.beginsWith("NonSemantic.")) { ExtInstDispatcher extinst; extinst.name = setname; - extinst.nonsemantic = true; + extinst.skippedNonsemantic = true; global.extInsts[id] = extinst; } diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index d81dac90f..1dac79093 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -1635,6 +1635,7 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, const bool IsGLSL450 = knownExtSet[ExtSet_GLSL450] == decoded.set; const bool IsDebugPrintf = knownExtSet[ExtSet_Printf] == decoded.set; const bool IsShaderDbg = knownExtSet[ExtSet_ShaderDbg] == decoded.set; + const bool IsDebugBreak = knownExtSet[ExtSet_DebugBreak] == decoded.set; // GLSL.std.450 all parameters are Ids const bool idParams = IsGLSL450 || setname.beginsWith("NonSemantic."); @@ -1715,6 +1716,8 @@ rdcstr Reflector::Disassemble(const rdcstr &entryPoint, ret += StringFormat::Fmt("%s::%s(", setname.c_str(), ToStr(GLSLstd450(inst)).c_str()); else if(IsDebugPrintf) ret += "DebugPrintf("; + else if(IsDebugBreak) + ret += "DebugBreak("; else ret += StringFormat::Fmt("%s::[%u](", setname.c_str(), inst); diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.cpp b/renderdoc/driver/shaders/spirv/spirv_processor.cpp index 2cc3e7df3..f7047d7e5 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_processor.cpp @@ -569,6 +569,8 @@ void Processor::RegisterOp(Iter it) knownExtSet[ExtSet_Printf] = decoded.result; else if(decoded.name == "NonSemantic.Shader.DebugInfo.100") knownExtSet[ExtSet_ShaderDbg] = decoded.result; + else if(decoded.name == "NonSemantic.DebugBreak") + knownExtSet[ExtSet_DebugBreak] = decoded.result; } else if(opdata.op == Op::EntryPoint) { diff --git a/renderdoc/driver/shaders/spirv/spirv_processor.h b/renderdoc/driver/shaders/spirv/spirv_processor.h index b5d0126f9..d1ad9f2c1 100644 --- a/renderdoc/driver/shaders/spirv/spirv_processor.h +++ b/renderdoc/driver/shaders/spirv/spirv_processor.h @@ -624,6 +624,7 @@ protected: ExtSet_GLSL450 = 0, ExtSet_Printf = 1, ExtSet_ShaderDbg = 2, + ExtSet_DebugBreak = 3, ExtSet_Count, };