diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 61993a2e7..2bae66288 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -188,6 +188,10 @@ struct FetchDrawcall parent = 0; previous = 0; next = 0; + + dispatchDimension[0] = dispatchDimension[1] = dispatchDimension[2] = 0; + dispatchThreadsDimension[0] = dispatchThreadsDimension[1] = dispatchThreadsDimension[2] = 0; + for(int i=0; i < 8; i++) outputs[i] = ResourceId(); } @@ -203,6 +207,9 @@ struct FetchDrawcall uint32_t indexOffset; uint32_t vertexOffset; uint32_t instanceOffset; + + uint32_t dispatchDimension[3]; + uint32_t dispatchThreadsDimension[3]; uint32_t indexByteWidth; PrimitiveTopology topology; diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 90fd74259..9a394c135 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -208,6 +208,8 @@ struct ShaderReflection ShaderDebugChunk DebugInfo; rdctype::str Disassembly; + uint32_t DispatchThreadsDimension[3]; + rdctype::array InputSig; rdctype::array OutputSig; diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index e8a6690db..8948ef213 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -201,6 +201,8 @@ void Serialiser::Serialise(const char *name, ShaderReflection &el) Serialise("", el.DebugInfo.entryFunc); Serialise("", el.DebugInfo.files); + Serialise<3>("", el.DispatchThreadsDimension); + Serialise("", el.Disassembly); Serialise("", el.InputSig); @@ -212,7 +214,7 @@ void Serialiser::Serialise(const char *name, ShaderReflection &el) Serialise("", el.Interfaces); - SIZE_CHECK(ShaderReflection, 72); + SIZE_CHECK(ShaderReflection, 84); } template<> @@ -764,7 +766,10 @@ void Serialiser::Serialise(const char *name, FetchDrawcall &el) Serialise("", el.indexOffset); Serialise("", el.vertexOffset); Serialise("", el.instanceOffset); - + + Serialise<3>("", el.dispatchDimension); + Serialise<3>("", el.dispatchThreadsDimension); + Serialise("", el.indexByteWidth); Serialise("", el.topology); @@ -780,7 +785,7 @@ void Serialiser::Serialise(const char *name, FetchDrawcall &el) Serialise("", el.events); Serialise("", el.children); - SIZE_CHECK(FetchDrawcall, 168); + SIZE_CHECK(FetchDrawcall, 192); } template<> diff --git a/renderdoc/driver/d3d11/d3d11_common.cpp b/renderdoc/driver/d3d11/d3d11_common.cpp index 791a76daa..bd86dfc41 100644 --- a/renderdoc/driver/d3d11/d3d11_common.cpp +++ b/renderdoc/driver/d3d11/d3d11_common.cpp @@ -904,6 +904,10 @@ ShaderReflection *MakeShaderReflection(DXBC::DXBCFile *dxbc) } } + ret->DispatchThreadsDimension[0] = dxbc->DispatchThreadsDimension[0]; + ret->DispatchThreadsDimension[1] = dxbc->DispatchThreadsDimension[1]; + ret->DispatchThreadsDimension[2] = dxbc->DispatchThreadsDimension[2]; + ret->Disassembly = dxbc->m_Disassembly; ret->InputSig = dxbc->m_InputSig; diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 54cc74b8c..ea8457a32 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -4509,6 +4509,20 @@ bool WrappedID3D11DeviceContext::Serialise_Dispatch(UINT ThreadGroupCountX_, UIN draw.name = name; draw.flags |= eDraw_Dispatch; + draw.dispatchDimension[0] = ThreadGroupCountX; + draw.dispatchDimension[1] = ThreadGroupCountY; + draw.dispatchDimension[2] = ThreadGroupCountZ; + + if(ThreadGroupCountX == 0) + m_pDevice->AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has ThreadGroup count X=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean X=1?"); + if(ThreadGroupCountY == 0) + m_pDevice->AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has ThreadGroup count Y=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Y=1?"); + if(ThreadGroupCountZ == 0) + m_pDevice->AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has ThreadGroup count Z=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Z=1?"); + AddDrawcall(draw, true); } @@ -4570,6 +4584,10 @@ bool WrappedID3D11DeviceContext::Serialise_DispatchIndirect(ID3D11Buffer *pBuffe name = "DispatchIndirect(<" + ToStr::Get(uargs[0]) + ", " + ToStr::Get(uargs[1]) + + ", " + ToStr::Get(uargs[2]) + ">)"; + + draw.dispatchDimension[0] = uargs[0]; + draw.dispatchDimension[1] = uargs[1]; + draw.dispatchDimension[2] = uargs[2]; } draw.name = name; diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 85621133a..470afd035 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -753,6 +753,15 @@ void MakeShaderReflection(const GLHookSet &gl, GLenum shadType, GLuint sepProg, refl.Disassembly = ""; + if(shadType == eGL_COMPUTE_SHADER) + { + gl.glGetProgramiv(sepProg, eGL_COMPUTE_WORK_GROUP_SIZE, (GLint *)refl.DispatchThreadsDimension); + } + else + { + RDCEraseEl(refl.DispatchThreadsDimension); + } + vector resources; GLint numUniforms = 0; diff --git a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp index 169200e7b..0a4dbe9bf 100644 --- a/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_draw_funcs.cpp @@ -53,6 +53,20 @@ bool WrappedOpenGL::Serialise_glDispatchCompute(GLuint num_groups_x, GLuint num_ draw.name = name; draw.flags |= eDraw_Dispatch; + draw.dispatchDimension[0] = X; + draw.dispatchDimension[1] = Y; + draw.dispatchDimension[2] = Z; + + if(X == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups X=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean X=1?"); + if(Y == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups Y=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Y=1?"); + if(Z == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups Z=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Z=1?"); + AddDrawcall(draw, true); } @@ -107,6 +121,33 @@ bool WrappedOpenGL::Serialise_glDispatchComputeGroupSizeARB(GLuint num_groups_x, draw.name = name; draw.flags |= eDraw_Dispatch; + draw.dispatchDimension[0] = X; + draw.dispatchDimension[1] = Y; + draw.dispatchDimension[2] = Z; + draw.dispatchThreadsDimension[0] = sX; + draw.dispatchThreadsDimension[1] = sY; + draw.dispatchThreadsDimension[2] = sZ; + + if(X == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups X=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean X=1?"); + if(Y == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups Y=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Y=1?"); + if(Z == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Num Groups Z=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Z=1?"); + + if(sX == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Group Size X=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean X=1?"); + if(sY == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Group Size Y=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Y=1?"); + if(sZ == 0) + AddDebugMessage(eDbgCategory_Execution, eDbgSeverity_Medium, eDbgSource_IncorrectAPIUse, + "Dispatch call has Group Size Z=0. This will do nothing, which is unusual for a non-indirect Dispatch. Did you mean Z=1?"); + AddDrawcall(draw, true); } @@ -147,15 +188,19 @@ bool WrappedOpenGL::Serialise_glDispatchComputeIndirect(GLintptr indirect) m_Real.glGetBufferSubData(eGL_DISPATCH_INDIRECT_BUFFER, (GLintptr)offs, sizeof(uint32_t)*3, groupSizes); AddEvent(DISPATCH_COMPUTE_INDIRECT, desc); - string name = "glDispatchComputeIndirect(" + + string name = "glDispatchComputeIndirect(<" + ToStr::Get(groupSizes[0]) + ", " + ToStr::Get(groupSizes[1]) + ", " + - ToStr::Get(groupSizes[2]) + ")"; + ToStr::Get(groupSizes[2]) + ">)"; FetchDrawcall draw; draw.name = name; draw.flags |= eDraw_Dispatch|eDraw_Indirect; + draw.dispatchDimension[0] = groupSizes[0]; + draw.dispatchDimension[1] = groupSizes[1]; + draw.dispatchDimension[2] = groupSizes[2]; + AddDrawcall(draw, true); } diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp index 55cb9bf60..208fc2ad5 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp @@ -1287,6 +1287,10 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.groupSize[2] = tokenStream[0]; tokenStream++; + DispatchThreadsDimension[0] = retDecl.groupSize[0]; + DispatchThreadsDimension[1] = retDecl.groupSize[1]; + DispatchThreadsDimension[2] = retDecl.groupSize[2]; + char buf[64] = {0}; StringFormat::snprintf(buf, 63, "%u", retDecl.groupSize[0]); retDecl.str += buf; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h index 0d4208a91..6cb2bb4a8 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h @@ -344,6 +344,8 @@ class DXBCFile vector m_Instructions; string m_Disassembly; + uint32_t DispatchThreadsDimension[3]; + vector m_HexDump; vector m_ShaderBlob; diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index 3862dc9eb..5177a919e 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -331,6 +331,11 @@ namespace renderdoc public UInt32 vertexOffset; public UInt32 instanceOffset; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 3)] + public UInt32[] dispatchDimension; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 3)] + public UInt32[] dispatchThreadsDimension; + public UInt32 indexByteWidth; public PrimitiveTopology topology; diff --git a/renderdocui/Interop/Shader.cs b/renderdocui/Interop/Shader.cs index 534c149ad..721565eb1 100644 --- a/renderdocui/Interop/Shader.cs +++ b/renderdocui/Interop/Shader.cs @@ -386,6 +386,9 @@ namespace renderdoc [CustomMarshalAs(CustomUnmanagedType.UTF8TemplatedString)] public string Disassembly; + [CustomMarshalAs(CustomUnmanagedType.FixedArray, FixedLength = 3)] + public UInt32[] DispatchThreadsDimension; + [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] public SigParameter[] InputSig; [CustomMarshalAs(CustomUnmanagedType.TemplatedArray)] diff --git a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs index 01745eea9..67b9210da 100644 --- a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs +++ b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs @@ -2255,6 +2255,31 @@ namespace renderdocui.Windows.PipelineState uint.TryParse(threadY.Text, out ty) && uint.TryParse(threadZ.Text, out tz)) { + uint[] groupdim = m_Core.CurDrawcall.dispatchDimension; + uint[] threadsdim = m_Core.CurDrawcall.dispatchThreadsDimension; + + for (int i = 0; i < 3; i++) + if (threadsdim[i] == 0) + threadsdim[i] = m_Core.CurD3D11PipelineState.m_CS.ShaderDetails.DispatchThreadsDimension[i]; + + string debugContext = String.Format("Group [{0},{1},{2}] Thread [{3},{4},{5}]", gx, gy, gz, tx, ty, tz); + + if (gx >= groupdim[0] || + gy >= groupdim[1] || + gz >= groupdim[2] || + tx >= threadsdim[0] || + ty >= threadsdim[1] || + tz >= threadsdim[2]) + { + string bounds = String.Format("Group Dimensions [{0},{1},{2}] Thread Dimensions [{3},{4},{5}]", + groupdim[0], groupdim[1], groupdim[2], + threadsdim[0], threadsdim[1], threadsdim[2]); + + MessageBox.Show(String.Format("{0} is out of bounds\n{1}", debugContext, bounds), "Couldn't debug compute shader.", + MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + ShaderDebugTrace trace = null; ShaderReflection shaderDetails = m_Core.CurD3D11PipelineState.m_CS.ShaderDetails; @@ -2273,8 +2298,6 @@ namespace renderdocui.Windows.PipelineState this.BeginInvoke(new Action(() => { - string debugContext = String.Format("Group [{0},{1},{2}] Thread [{3},{4},{5}]", gx, gy, gz, tx, ty, tz); - ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, ShaderStageType.Compute, trace, debugContext); s.Show(m_DockContent.DockPanel);