@@ -172,6 +172,79 @@ DebugLoopResult runDebugLoop(IReplayController* ctrl, ShaderDebugTrace* dbgTrace
172172 return result;
173173}
174174
175+ // Check if a shader stage is marked as not debuggable by RenderDoc and return
176+ // the reason string. Returns empty string if the shader is debuggable or if
177+ // the check cannot be performed.
178+ std::string getShaderNotDebuggableReason (IReplayController* ctrl, ::ShaderStage stage) {
179+ APIProperties props = ctrl->GetAPIProperties ();
180+ const ::ShaderReflection* refl = nullptr ;
181+
182+ switch (props.pipelineType ) {
183+ case GraphicsAPI::OpenGL: {
184+ const auto * s = ctrl->GetGLPipelineState ();
185+ if (!s) break ;
186+ switch (stage) {
187+ case ::ShaderStage::Vertex: refl = s->vertexShader .reflection ; break ;
188+ case ::ShaderStage::Pixel: refl = s->fragmentShader .reflection ; break ;
189+ case ::ShaderStage::Geometry: refl = s->geometryShader .reflection ; break ;
190+ case ::ShaderStage::Hull: refl = s->tessControlShader .reflection ; break ;
191+ case ::ShaderStage::Domain: refl = s->tessEvalShader .reflection ; break ;
192+ case ::ShaderStage::Compute: refl = s->computeShader .reflection ; break ;
193+ default : break ;
194+ }
195+ break ;
196+ }
197+ case GraphicsAPI::D3D11 : {
198+ const auto * s = ctrl->GetD3D11PipelineState ();
199+ if (!s) break ;
200+ switch (stage) {
201+ case ::ShaderStage::Vertex: refl = s->vertexShader .reflection ; break ;
202+ case ::ShaderStage::Pixel: refl = s->pixelShader .reflection ; break ;
203+ case ::ShaderStage::Geometry: refl = s->geometryShader .reflection ; break ;
204+ case ::ShaderStage::Hull: refl = s->hullShader .reflection ; break ;
205+ case ::ShaderStage::Domain: refl = s->domainShader .reflection ; break ;
206+ case ::ShaderStage::Compute: refl = s->computeShader .reflection ; break ;
207+ default : break ;
208+ }
209+ break ;
210+ }
211+ case GraphicsAPI::D3D12 : {
212+ const auto * s = ctrl->GetD3D12PipelineState ();
213+ if (!s) break ;
214+ switch (stage) {
215+ case ::ShaderStage::Vertex: refl = s->vertexShader .reflection ; break ;
216+ case ::ShaderStage::Pixel: refl = s->pixelShader .reflection ; break ;
217+ case ::ShaderStage::Geometry: refl = s->geometryShader .reflection ; break ;
218+ case ::ShaderStage::Hull: refl = s->hullShader .reflection ; break ;
219+ case ::ShaderStage::Domain: refl = s->domainShader .reflection ; break ;
220+ case ::ShaderStage::Compute: refl = s->computeShader .reflection ; break ;
221+ default : break ;
222+ }
223+ break ;
224+ }
225+ case GraphicsAPI::Vulkan: {
226+ const auto * s = ctrl->GetVulkanPipelineState ();
227+ if (!s) break ;
228+ switch (stage) {
229+ case ::ShaderStage::Vertex: refl = s->vertexShader .reflection ; break ;
230+ case ::ShaderStage::Pixel: refl = s->fragmentShader .reflection ; break ;
231+ case ::ShaderStage::Geometry: refl = s->geometryShader .reflection ; break ;
232+ case ::ShaderStage::Hull: refl = s->tessControlShader .reflection ; break ;
233+ case ::ShaderStage::Domain: refl = s->tessEvalShader .reflection ; break ;
234+ case ::ShaderStage::Compute: refl = s->computeShader .reflection ; break ;
235+ default : break ;
236+ }
237+ break ;
238+ }
239+ default : break ;
240+ }
241+
242+ if (refl && !refl->debugInfo .debuggable )
243+ return std::string (refl->debugInfo .debugStatus .c_str ());
244+
245+ return {};
246+ }
247+
175248} // anonymous namespace
176249
177250ShaderDebugResult debugPixel (
@@ -192,9 +265,22 @@ ShaderDebugResult debugPixel(
192265 ShaderDebugTrace* trace = ctrl->DebugPixel (x, y, inputs);
193266 if (!trace || !trace->debugger ) {
194267 if (trace) ctrl->FreeTrace (trace);
268+
269+ // Distinguish "shader not debuggable" from "no fragment hit" so users
270+ // know whether the issue is a RenderDoc limitation or a wrong coordinate.
271+ std::string reason = getShaderNotDebuggableReason (ctrl, ::ShaderStage::Pixel);
272+ if (!reason.empty ())
273+ throw CoreError (CoreError::Code::DebugNotSupported,
274+ " Fragment shader is not debuggable at event " +
275+ std::to_string (eventId) + " : " + reason);
276+
195277 throw CoreError (CoreError::Code::NoFragmentFound,
196- " No debuggable fragment at (" + std::to_string (x) +
197- " ," + std::to_string (y) + " ) for event " + std::to_string (eventId));
278+ " No fragment hit at (" + std::to_string (x) +
279+ " ," + std::to_string (y) + " ) for event " + std::to_string (eventId) +
280+ " . The shader is marked as debuggable, but RenderDoc could "
281+ " not produce a debug trace. This can happen with certain "
282+ " OpenGL shader features that are not fully supported by "
283+ " the software shader debugger." );
198284 }
199285
200286 ShaderDebugResult result;
@@ -233,9 +319,20 @@ ShaderDebugResult debugVertex(
233319 ShaderDebugTrace* trace = ctrl->DebugVertex (vertexId, instance, idx, view);
234320 if (!trace || !trace->debugger ) {
235321 if (trace) ctrl->FreeTrace (trace);
322+
323+ std::string reason = getShaderNotDebuggableReason (ctrl, ::ShaderStage::Vertex);
324+ if (!reason.empty ())
325+ throw CoreError (CoreError::Code::DebugNotSupported,
326+ " Vertex shader is not debuggable at event " +
327+ std::to_string (eventId) + " : " + reason);
328+
236329 throw CoreError (CoreError::Code::NoFragmentFound,
237330 " Cannot debug vertex " + std::to_string (vertexId) +
238- " at event " + std::to_string (eventId));
331+ " at event " + std::to_string (eventId) +
332+ " . The shader is marked as debuggable, but RenderDoc could "
333+ " not produce a debug trace. This can happen with certain "
334+ " OpenGL shader features that are not fully supported by "
335+ " the software shader debugger." );
239336 }
240337
241338 ShaderDebugResult result;
@@ -279,6 +376,13 @@ ShaderDebugResult debugThread(
279376 ShaderDebugTrace* trace = ctrl->DebugThread (groupid, threadid);
280377 if (!trace || !trace->debugger ) {
281378 if (trace) ctrl->FreeTrace (trace);
379+
380+ std::string reason = getShaderNotDebuggableReason (ctrl, ::ShaderStage::Compute);
381+ if (!reason.empty ())
382+ throw CoreError (CoreError::Code::DebugNotSupported,
383+ " Compute shader is not debuggable at event " +
384+ std::to_string (eventId) + " : " + reason);
385+
282386 throw CoreError (CoreError::Code::NoFragmentFound,
283387 " Cannot debug thread (" + std::to_string (threadX) + " ," +
284388 std::to_string (threadY) + " ," + std::to_string (threadZ) +
0 commit comments