private void shader_Click(object sender, EventArgs e) { GLPipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) { return; } ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null) { return; } ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, stage.stage, null, ""); s.Show(m_DockContent.DockPanel); }
private void csDebug_Click(object sender, EventArgs e) { uint gx = 0, gy = 0, gz = 0; uint tx = 0, ty = 0, tz = 0; if (m_Core.CurD3D11PipelineState == null || m_Core.CurD3D11PipelineState.m_CS.Shader == ResourceId.Null || m_Core.CurD3D11PipelineState.m_CS.ShaderDetails == null) return; if (uint.TryParse(groupX.Text, out gx) && uint.TryParse(groupY.Text, out gy) && uint.TryParse(groupZ.Text, out gz) && uint.TryParse(threadX.Text, out tx) && 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; m_Core.Renderer.Invoke((ReplayRenderer r) => { trace = r.DebugThread(new uint[] { gx, gy, gz }, new uint[] { tx, ty, tz }); }); if (trace == null || trace.states.Length == 0) { MessageBox.Show("Couldn't debug compute shader.", "Uh Oh!", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } this.BeginInvoke(new Action(() => { ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, ShaderStageType.Compute, trace, debugContext); s.Show(m_DockContent.DockPanel); })); } else { MessageBox.Show("Enter numbers for group and thread ID.", "Invalid thread", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void shader_Click(object sender, EventArgs e) { if (sender == iaBytecode || sender == iaBytecodeCog) { if(m_Core.CurD3D11PipelineState != null && m_Core.CurD3D11PipelineState.m_IA.Bytecode != null) { (new ShaderViewer(m_Core, m_Core.CurD3D11PipelineState.m_IA.Bytecode, ShaderStageType.Vertex, null, "")) .Show(m_DockContent.DockPanel); } return; } D3D11PipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) return; ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null) return; ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, stage.stage, null, ""); s.Show(m_DockContent.DockPanel); }
// start a shaderviewer to edit this shader, optionally generating stub HLSL if there isn't // HLSL source available for this shader. private void shaderedit_Click(object sender, EventArgs e) { D3D11PipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) return; ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null || shaderDetails == null) return; var entryFunc = String.Format("EditedShader{0}S", stage.stage.ToString()[0]); string mainfile = ""; var files = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase); if (shaderDetails.DebugInfo.entryFunc.Length > 0 && shaderDetails.DebugInfo.files.Length > 0) { entryFunc = shaderDetails.DebugInfo.entryFunc; foreach (var s in shaderDetails.DebugInfo.files) { if (files.ContainsKey(s.FullFilename)) renderdoc.StaticExports.LogText(String.Format("Duplicate full filename {0}", s.FullFilename)); else files.Add(s.FullFilename, s.filetext); } int entryFile = shaderDetails.DebugInfo.entryFile; if (entryFile < 0 || entryFile >= shaderDetails.DebugInfo.files.Length) entryFile = 0; mainfile = shaderDetails.DebugInfo.files[entryFile].FullFilename; } else { var nl = Environment.NewLine; var nl2 = Environment.NewLine + Environment.NewLine; string hlsl = "// No HLSL available - function stub generated" + nl2; var shType = String.Format("{0}S", stage.stage.ToString()[0]); for (int i = 0; i < 2; i++) { ShaderResource[] resources = (i == 0 ? shaderDetails.ReadOnlyResources : shaderDetails.ReadWriteResources); foreach (var res in resources) { if (res.IsSampler) { hlsl += String.Format("//SamplerComparisonState {0} : register(s{1}); // can't disambiguate", res.name, res.bindPoint) + nl; hlsl += String.Format("SamplerState {0} : register(s{1}); // can't disambiguate", res.name, res.bindPoint) + nl; } else { char regChar = 't'; if (i == 1) { hlsl += "RW"; regChar = 'u'; } if (res.IsTexture) { hlsl += String.Format("{0}<{1}> {2} : register({3}{4});", res.resType.ToString(), res.variableType.descriptor.name, res.name, regChar, res.bindPoint) + nl; } else { if (res.variableType.descriptor.rows == 1) hlsl += String.Format("Buffer<{0}> {1} : register({2}{3});", res.variableType.descriptor.name, res.name, regChar, res.bindPoint) + nl; else hlsl += String.Format("StructuredBuffer<{0}> {1} : register({2}{3});", res.variableType.descriptor.name, res.name, regChar, res.bindPoint) + nl; } } } } hlsl += nl2; string cbuffers = ""; int cbufIdx = 0; foreach (var cbuf in shaderDetails.ConstantBlocks) { if (cbuf.name.Length > 0 && cbuf.variables.Length > 0) { cbuffers += String.Format("cbuffer {0} : register(b{1}) {{", cbuf.name, cbufIdx) + nl; MakeShaderVariablesHLSL(true, cbuf.variables, ref cbuffers, ref hlsl); cbuffers += "};" + nl2; } cbufIdx++; } hlsl += cbuffers + nl2; hlsl += String.Format("struct {0}Input{1}{{{1}", shType, nl); foreach(var sig in shaderDetails.InputSig) hlsl += String.Format("\t{0} {1} : {2};" + nl, sig.TypeString, sig.varName.Length > 0 ? sig.varName : ("param" + sig.regIndex), sig.D3D11SemanticString); hlsl += "};" + nl2; hlsl += String.Format("struct {0}Output{1}{{{1}", shType, nl); foreach (var sig in shaderDetails.OutputSig) hlsl += String.Format("\t{0} {1} : {2};" + nl, sig.TypeString, sig.varName.Length > 0 ? sig.varName : ("param" + sig.regIndex), sig.D3D11SemanticString); hlsl += "};" + nl2; hlsl += String.Format("{0}Output {1}(in {0}Input IN){2}{{{2}\t{0}Output OUT = ({0}Output)0;{2}{2}\t// ...{2}{2}\treturn OUT;{2}}}{2}", shType, entryFunc, nl); mainfile = "generated.hlsl"; files.Add(mainfile, hlsl); } if (files.Count == 0) return; D3D11PipelineStateViewer pipeviewer = this; ShaderViewer sv = new ShaderViewer(m_Core, false, entryFunc, files, // Save Callback (ShaderViewer viewer, Dictionary<string, string> updatedfiles) => { string compileSource = updatedfiles[mainfile]; // try and match up #includes against the files that we have. This isn't always // possible as fxc only seems to include the source for files if something in // that file was included in the compiled output. So you might end up with // dangling #includes - we just have to ignore them int offs = compileSource.IndexOf("#include"); while(offs >= 0) { // search back to ensure this is a valid #include (ie. not in a comment). // Must only see whitespace before, then a newline. int ws = Math.Max(0, offs-1); while (ws >= 0 && (compileSource[ws] == ' ' || compileSource[ws] == '\t')) ws--; // not valid? jump to next. if (ws > 0 && compileSource[ws] != '\n') { offs = compileSource.IndexOf("#include", offs + 1); continue; } int start = ws+1; bool tail = true; int lineEnd = compileSource.IndexOf("\n", start+1); if(lineEnd == -1) { lineEnd = compileSource.Length; tail = false; } ws = offs + "#include".Length; while (compileSource[ws] == ' ' || compileSource[ws] == '\t') ws++; string line = compileSource.Substring(offs, lineEnd-offs+1); if (compileSource[ws] != '<' && compileSource[ws] != '"') { viewer.ShowErrors("Invalid #include directive found:\r\n" + line); return; } // find matching char, either <> or ""; int end = compileSource.IndexOf(compileSource[ws] == '"' ? '"' : '>', ws + 1); if (end == -1) { viewer.ShowErrors("Invalid #include directive found:\r\n" + line); return; } string fname = compileSource.Substring(ws + 1, end - ws - 1); string fileText = ""; // look for exact match first if (updatedfiles.ContainsKey(fname)) { fileText = updatedfiles[fname]; } else { string search = renderdocui.Code.Helpers.SafeGetFileName(fname); // if not, try and find the same filename (this is not proper include handling!) foreach (var k in updatedfiles.Keys) { if (renderdocui.Code.Helpers.SafeGetFileName(k) == search) { fileText = updatedfiles[k]; break; } } if(fileText == "") fileText = "// Can't find file " + fname + "\n"; } compileSource = compileSource.Substring(0, offs) + "\n\n" + fileText + "\n\n" + (tail ? compileSource.Substring(lineEnd + 1) : ""); // need to start searching from the beginning - wasteful but allows nested includes to work offs = compileSource.IndexOf("#include"); } if (updatedfiles.ContainsKey("@cmdline")) compileSource = updatedfiles["@cmdline"] + "\n\n" + compileSource; // invoke off to the ReplayRenderer to replace the log's shader // with our edited one m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { string errs = ""; uint flags = shaderDetails.DebugInfo.compileFlags; ResourceId from = stage.Shader; ResourceId to = r.BuildTargetShader(entryFunc, compileSource, flags, stage.stage, out errs); viewer.BeginInvoke((MethodInvoker)delegate { viewer.ShowErrors(errs); }); if (to == ResourceId.Null) { r.RemoveReplacement(from); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } else { r.ReplaceResource(from, to); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } }); }, // Close Callback () => { // remove the replacement on close (we could make this more sophisticated if there // was a place to control replaced resources/shaders). m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.RemoveReplacement(stage.Shader); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); }); }); sv.Show(m_DockContent.DockPanel); }
private void shader_Click(object sender, EventArgs e) { GLPipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) return; ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null) return; ShaderViewer s = new ShaderViewer(m_Core, shaderDetails, stage.stage, null, ""); s.Show(m_DockContent.DockPanel); }
private void shaderedit_Click(object sender, EventArgs e) { GLPipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) return; ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null || shaderDetails == null) return; var files = new Dictionary<string, string>(); foreach (var s in shaderDetails.DebugInfo.files) files.Add(s.BaseFilename, s.filetext); if (files.Count == 0) return; ShaderViewer sv = new ShaderViewer(m_Core, false, "main", files, // Save Callback (ShaderViewer viewer, Dictionary<string, string> updatedfiles) => { string compileSource = ""; foreach (var kv in updatedfiles) compileSource += kv.Value; // invoke off to the ReplayRenderer to replace the log's shader // with our edited one m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { string errs = ""; ResourceId from = stage.Shader; ResourceId to = r.BuildTargetShader("main", compileSource, shaderDetails.DebugInfo.compileFlags, stage.stage, out errs); viewer.BeginInvoke((MethodInvoker)delegate { viewer.ShowErrors(errs); }); if (to == ResourceId.Null) { r.RemoveReplacement(from); } else { r.ReplaceResource(from, to); } }); }, // Close Callback () => { // remove the replacement on close (we could make this more sophisticated if there // was a place to control replaced resources/shaders). m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.RemoveReplacement(stage.Shader); }); }); sv.Show(m_DockContent.DockPanel); }
private void csDebug_Click(object sender, EventArgs e) { uint gx = 0, gy = 0, gz = 0; uint tx = 0, ty = 0, tz = 0; if (m_Core.CurD3D11PipelineState == null || m_Core.CurD3D11PipelineState.m_CS.Shader == ResourceId.Null || m_Core.CurD3D11PipelineState.m_CS.ShaderDetails == null) return; if (uint.TryParse(groupX.Text, out gx) && uint.TryParse(groupY.Text, out gy) && uint.TryParse(groupZ.Text, out gz) && uint.TryParse(threadX.Text, out tx) && uint.TryParse(threadY.Text, out ty) && uint.TryParse(threadZ.Text, out tz)) { ShaderDebugTrace trace = null; ShaderReflection shaderDetails = m_Core.CurD3D11PipelineState.m_CS.ShaderDetails; m_Core.Renderer.Invoke((ReplayRenderer r) => { trace = r.CSGetDebugStates(new uint[] { gx, gy, gz }, new uint[] { tx, ty, tz }); }); if (trace == null || trace.states.Length == 0) { MessageBox.Show("Couldn't debug compute shader.", "Uh Oh!", MessageBoxButtons.OK, MessageBoxIcon.Information); return; } 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); })); } else { MessageBox.Show("Enter numbers for group and thread ID.", "Invalid thread", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void ShowShaderViewer(VulkanPipelineState.ShaderStage stage, Dictionary<String, String> files) { VulkanPipelineStateViewer pipeviewer = this; ShaderViewer sv = new ShaderViewer(m_Core, false, "main", files, // Save Callback (ShaderViewer viewer, Dictionary<string, string> updatedfiles) => { string compileSource = ""; foreach (var kv in updatedfiles) compileSource += kv.Value; // invoke off to the ReplayRenderer to replace the log's shader // with our edited one m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { string errs = ""; ResourceId from = stage.Shader; ResourceId to = r.BuildTargetShader("main", compileSource, stage.ShaderDetails.DebugInfo.compileFlags, stage.stage, out errs); viewer.BeginInvoke((MethodInvoker)delegate { viewer.ShowErrors(errs); }); if (to == ResourceId.Null) { r.RemoveReplacement(from); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } else { r.ReplaceResource(from, to); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } }); }, // Close Callback () => { // remove the replacement on close (we could make this more sophisticated if there // was a place to control replaced resources/shaders). m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.RemoveReplacement(stage.Shader); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); }); }); sv.Show(m_DockContent.DockPanel); }
// start a shaderviewer to edit this shader, optionally generating stub GLSL if there isn't // GLSL source available for this shader. private void shaderedit_Click(object sender, EventArgs e) { VulkanPipelineState.ShaderStage stage = GetStageForSender(sender); if (stage == null) return; ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null || shaderDetails == null) return; var files = new Dictionary<string, string>(); // use disassembly for now. It's not compilable GLSL but it's better than // starting with a blank canvas files.Add("Disassembly", shaderDetails.Disassembly); VulkanPipelineStateViewer pipeviewer = this; ShaderViewer sv = new ShaderViewer(m_Core, false, "main", files, // Save Callback (ShaderViewer viewer, Dictionary<string, string> updatedfiles) => { string compileSource = ""; foreach (var kv in updatedfiles) compileSource += kv.Value; // invoke off to the ReplayRenderer to replace the log's shader // with our edited one m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { string errs = ""; ResourceId from = stage.Shader; ResourceId to = r.BuildTargetShader("main", compileSource, shaderDetails.DebugInfo.compileFlags, stage.stage, out errs); viewer.BeginInvoke((MethodInvoker)delegate { viewer.ShowErrors(errs); }); if (to == ResourceId.Null) { r.RemoveReplacement(from); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } else { r.ReplaceResource(from, to); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); } }); }, // Close Callback () => { // remove the replacement on close (we could make this more sophisticated if there // was a place to control replaced resources/shaders). m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { r.RemoveReplacement(stage.Shader); pipeviewer.BeginInvoke((MethodInvoker)delegate { m_Core.RefreshStatus(); }); }); }); sv.Show(m_DockContent.DockPanel); }