public void SetStates(APIProperties props, D3D11PipelineState d3d11, D3D12PipelineState d3d12, GLPipelineState gl, VulkanPipelineState vk) { m_APIProps = props; m_D3D11 = d3d11; m_D3D12 = d3d12; m_GL = gl; m_Vulkan = vk; }
public void CloseLogfile() { if (!m_LogLoaded) return; m_LogFile = ""; m_Renderer.CloseThreadSync(); m_APIProperties = null; m_FrameInfo = null; m_DrawCalls = null; m_Buffers = null; m_Textures = null; m_D3D11PipelineState = null; m_D3D12PipelineState = null; m_GLPipelineState = null; m_VulkanPipelineState = null; m_PipelineState.SetStates(null, null,null, null, null); DebugMessages.Clear(); UnreadMessageCount = 0; m_LogLoaded = false; if (m_LogWatcher != null) m_LogWatcher.EnableRaisingEvents = false; m_LogWatcher = null; foreach (var logviewer in m_LogViewers) { Control c = (Control)logviewer; if (c.InvokeRequired) c.Invoke(new Action(() => logviewer.OnLogfileClosed())); else logviewer.OnLogfileClosed(); } }
private void ExportHTML(XmlTextWriter writer, D3D12PipelineState.Rasterizer rs) { { writer.WriteStartElement("h3"); writer.WriteString("States"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Fill Mode", "Cull Mode", "Front CCW" }, new object[] { rs.m_State.FillMode, rs.m_State.CullMode, rs.m_State.FrontCCW ? "Yes" : "No" }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Line AA Enable", "Multisample Enable", "Forced Sample Count", "Conservative Raster" }, new object[] { rs.m_State.AntialiasedLineEnable ? "Yes" : "No", rs.m_State.MultisampleEnable ? "Yes" : "No", rs.m_State.ForcedSampleCount, rs.m_State.ConservativeRasterization ? "Yes" : "No" }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Depth Clip", "Depth Bias", "Depth Bias Clamp", "Slope Scaled Bias" }, new object[] { rs.m_State.DepthClip ? "Yes" : "No", rs.m_State.DepthBias, Formatter.Format(rs.m_State.DepthBiasClamp), Formatter.Format(rs.m_State.SlopeScaledDepthBias)}); } { writer.WriteStartElement("h3"); writer.WriteString("Viewports"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var v in rs.Viewports) { if (v.Width == v.Height && v.Width == 0 && v.Height == 0) continue; rows.Add(new object[] { i, v.TopLeft[0], v.TopLeft[1], v.Width, v.Height, v.MinDepth, v.MaxDepth }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "X", "Y", "Width", "Height", "Min Depth", "Max Depth" }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Scissors"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var s in rs.Scissors) { if (s.right == 0 && s.bottom == 0) continue; rows.Add(new object[] { i, s.left, s.top, s.right - s.left, s.bottom - s.top }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "X", "Y", "Width", "Height" }, rows.ToArray()); } }
private void ExportHTML(XmlTextWriter writer, D3D12PipelineState.OutputMerger om) { { writer.WriteStartElement("h3"); writer.WriteString("Blend State"); writer.WriteEndElement(); var blendFactor = om.m_BlendState.BlendFactor[0].ToString("F2") + ", " + om.m_BlendState.BlendFactor[1].ToString("F2") + ", " + om.m_BlendState.BlendFactor[2].ToString("F2") + ", " + om.m_BlendState.BlendFactor[3].ToString("F2"); ExportHTMLTable(writer, new string[] { "Independent Blend Enable", "Alpha to Coverage", "Blend Factor" }, new object[] { om.m_BlendState.IndependentBlend ? "Yes" : "No", om.m_BlendState.AlphaToCoverage ? "Yes" : "No", blendFactor, }); writer.WriteStartElement("h3"); writer.WriteString("Target Blends"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var b in om.m_BlendState.Blends) { if (!b.Enabled) continue; rows.Add(new object[] { i, b.Enabled ? "Yes" : "No", b.LogicEnabled ? "Yes" : "No", b.m_Blend.Source, b.m_Blend.Destination, b.m_Blend.Operation, b.m_AlphaBlend.Source, b.m_AlphaBlend.Destination, b.m_AlphaBlend.Operation, b.LogicOp, ((b.WriteMask & 0x1) == 0 ? "_" : "R") + ((b.WriteMask & 0x2) == 0 ? "_" : "G") + ((b.WriteMask & 0x4) == 0 ? "_" : "B") + ((b.WriteMask & 0x8) == 0 ? "_" : "A") }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Blend Enable", "Logic Enable", "Blend Source", "Blend Destination", "Blend Operation", "Alpha Blend Source", "Alpha Blend Destination", "Alpha Blend Operation", "Logic Operation", "Write Mask", }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Depth State"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Depth Test Enable", "Depth Writes Enable", "Depth Function" }, new object[] { om.m_State.DepthEnable ? "Yes" : "No", om.m_State.DepthWrites ? "Yes" : "No", om.m_State.DepthFunc }); } { writer.WriteStartElement("h3"); writer.WriteString("Stencil State"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Stencil Test Enable", "Stencil Read Mask", "Stencil Write Mask" }, new object[] { om.m_State.StencilEnable ? "Yes" : "No", om.m_State.StencilReadMask.ToString("X2"), om.m_State.StencilWriteMask.ToString("X2") }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Face", "Function", "Pass Operation", "Fail Operation", "Depth Fail Operation" }, new object[][] { new object[] { "Front", om.m_State.m_FrontFace.Func, om.m_State.m_FrontFace.PassOp, om.m_State.m_FrontFace.FailOp, om.m_State.m_FrontFace.DepthFailOp }, new object[] { "Back", om.m_State.m_BackFace.Func, om.m_State.m_BackFace.PassOp, om.m_State.m_BackFace.FailOp, om.m_State.m_BackFace.DepthFailOp }, }); } { writer.WriteStartElement("h3"); writer.WriteString("Render targets"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); for (int i = 0; i < om.RenderTargets.Length; i++) { if (om.RenderTargets[i].Resource == ResourceId.Null) continue; rows.Add(ExportViewHTML(om.RenderTargets[i], i, null, "")); } ExportHTMLTable(writer, new string[] { "Slot", "Name", "View Type", "Resource Type", "Width", "Height", "Depth", "Array Size", "View Format", "Resource Format", "View Parameters", }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Depth target"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); string extra = ""; if(om.DepthReadOnly && om.StencilReadOnly) extra = "Depth & Stencil Read-Only"; else if (om.DepthReadOnly) extra = "Depth Read-Only"; else if (om.StencilReadOnly) extra = "Stencil Read-Only"; rows.Add(ExportViewHTML(om.DepthTarget, 0, null, extra)); ExportHTMLTable(writer, new string[] { "Slot", "Name", "View Type", "Resource Type", "Width", "Height", "Depth", "Array Size", "View Format", "Resource Format", "View Parameters", }, rows.ToArray()); } }
private void ExportHTML(XmlTextWriter writer, D3D12PipelineState.ShaderStage sh) { FetchBuffer[] bufs = m_Core.CurBuffers; { writer.WriteStartElement("h3"); writer.WriteString("Shader"); writer.WriteEndElement(); ShaderReflection shaderDetails = sh.ShaderDetails; D3D12PipelineState state = m_Core.CurD3D12PipelineState; string shadername = "Unknown"; if (sh.Shader == ResourceId.Null) shadername = "Unbound"; else if (state.customName) shadername = state.PipelineName + " - " + m_Core.CurPipelineState.Abbrev(sh.stage); else shadername = sh.stage.Str(GraphicsAPI.D3D12); if (shaderDetails != null && shaderDetails.DebugInfo.entryFunc.Length > 0 && shaderDetails.DebugInfo.files.Length > 0) shadername = shaderDetails.DebugInfo.entryFunc + "()" + " - " + shaderDetails.DebugInfo.files[0].BaseFilename; writer.WriteStartElement("p"); writer.WriteString(shadername); writer.WriteEndElement(); if (sh.Shader == ResourceId.Null) return; } }
private void ExportHTML(XmlTextWriter writer, D3D12PipelineState.Streamout so) { FetchBuffer[] bufs = m_Core.CurBuffers; { writer.WriteStartElement("h3"); writer.WriteString("Stream Out Targets"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var o in so.Outputs) { string name = "Buffer " + o.Buffer.ToString(); UInt64 length = 0; if (o.Buffer == ResourceId.Null) { name = "Empty"; } else { for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == o.Buffer) { name = bufs[t].name; length = bufs[t].length; } } } rows.Add(new object[] { i, name, o.Offset, length }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Buffer", "Offset", "Byte Length" }, rows.ToArray()); } }
public ViewTexTag(D3D12PipelineState.ResourceView v, FetchTexture t, bool u, ShaderResource r) { view = v; tex = t; uav = u; res = r; }
private bool HasImportantViewParams(D3D12PipelineState.ResourceView view, FetchTexture tex) { // we don't count 'upgrade typeless to typed' as important, we just display the typed format // in the row since there's no real hidden important information there. The formats can't be // different for any other reason (if the SRV format differs from the texture format, the // texture must have been typeless. if (view.HighestMip > 0 || view.FirstArraySlice > 0 || (view.NumMipLevels < tex.mips && tex.mips > 1) || (view.ArraySize < tex.arraysize && tex.arraysize > 1)) return true; // in the case of the swapchain case, types can be different and it won't have shown // up as taking the view's format because the swapchain already has one. Make sure to mark it // as important if (view.Format.compType != FormatComponentType.None && view.Format != tex.format) return true; return false; }
private void ShowCBuffer(D3D12PipelineState.ShaderStage stage, CBufTag tag) { if (tag.idx == uint.MaxValue) { // unused cbuffer, open regular buffer viewer var viewer = new BufferViewer(m_Core, false); var buf = stage.Spaces[tag.space].ConstantBuffers[tag.reg]; viewer.ViewRawBuffer(true, buf.Offset, buf.ByteSize, buf.Buffer); viewer.Show(m_DockContent.DockPanel); return; } var existing = ConstantBufferPreviewer.Has(stage.stage, tag.idx, 0); if (existing != null) { existing.Show(); return; } var prev = new ConstantBufferPreviewer(m_Core, stage.stage, tag.idx, 0); prev.ShowDock(m_DockContent.Pane, DockAlignment.Right, 0.3); }
public ViewBufTag(D3D12PipelineState.ResourceView v, FetchBuffer b, bool u, ShaderResource r) { view = v; buf = b; uav = u; res = r; }
private void AddResourceRow(D3D12PipelineState.ShaderStage stage, TreelistView.TreeListView list, int space, int reg, bool uav) { D3D12PipelineState state = m_Core.CurD3D12PipelineState; FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; BindpointMap bind = null; ShaderResource shaderInput = null; D3D12PipelineState.ResourceView r = uav ? stage.Spaces[space].UAVs[reg] : stage.Spaces[space].SRVs[reg]; // consider this register to not exist - it's in a gap defined by sparse root signature elements if (r.RootElement == uint.MaxValue) return; if (stage.BindpointMapping != null && stage.ShaderDetails != null) { BindpointMap[] binds = uav ? stage.BindpointMapping.ReadWriteResources : stage.BindpointMapping.ReadOnlyResources; ShaderResource[] resources = uav ? stage.ShaderDetails.ReadWriteResources : stage.ShaderDetails.ReadOnlyResources; for (int i=0; i < binds.Length; i++) { var b = binds[i]; var res = resources[i]; bool regMatch = b.bind == reg; // handle unbounded arrays specially. It's illegal to have an unbounded array with // anything after it if (b.bind <= reg) regMatch = (b.arraySize == UInt32.MaxValue) || (b.bind + b.arraySize > reg); if (b.bindset == space && regMatch && !res.IsSampler) { bind = b; shaderInput = res; break; } } } TreelistView.NodeCollection parent = list.Nodes; string rootel = r.Immediate ? String.Format("#{0} Direct", r.RootElement) : rootel = String.Format("#{0} Table[{1}]", r.RootElement, r.TableIndex); bool filledSlot = r.Resource != ResourceId.Null; bool usedSlot = (bind != null && bind.used); // show if if (usedSlot || // it's referenced by the shader - regardless of empty or not (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled" (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty" ) { string regname = reg.ToString(); if (shaderInput != null && shaderInput.name.Length > 0) regname += ": " + shaderInput.name; UInt64 w = 1; UInt32 h = 1, d = 1; UInt32 a = 1; string format = "Unknown"; string name = "Unbound"; string typename = "Unknown"; object tag = null; bool viewDetails = false; if (!filledSlot) { name = "Empty"; format = "-"; typename = "-"; w = h = d = a = 0; } if (r != null) { name = "Shader Resource " + r.Resource.ToString(); // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == r.Resource) { w = texs[t].width; h = texs[t].height; d = texs[t].depth; a = texs[t].arraysize; format = texs[t].format.ToString(); name = texs[t].name; typename = texs[t].resType.Str(); if (texs[t].resType == ShaderResourceType.Texture2DMS || texs[t].resType == ShaderResourceType.Texture2DMSArray) { typename += String.Format(" {0}x", texs[t].msSamp); } // if it's a typeless format, show the format of the view if (texs[t].format != r.Format) { format = "Viewed as " + r.Format.ToString(); } tag = new ViewTexTag(r, texs[t], true, shaderInput); if (HasImportantViewParams(r, texs[t])) viewDetails = true; } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == r.Resource) { w = bufs[t].length; h = 1; d = 1; a = 1; format = ""; name = bufs[t].name; typename = uav ? "RWBuffer" : "Buffer"; if (r.BufferFlags.HasFlag(D3DBufferViewFlags.Raw)) { typename = uav ? "RWByteAddressBuffer" : "ByteAddressBuffer"; } else if (r.ElementSize > 0) { // for structured buffers, display how many 'elements' there are in the buffer typename = (uav ? "RWStructuredBuffer" : "StructuredBuffer"); a = (uint)(bufs[t].length / r.ElementSize); } if (r.CounterResource != ResourceId.Null) { typename += " (Count: " + r.BufferStructCount + ")"; } // get the buffer type, whether it's just a basic type or a complex struct if (shaderInput != null && !shaderInput.IsTexture) { if (shaderInput.variableType.members.Length > 0) format = "struct " + shaderInput.variableType.Name; else if (r.Format.compType == FormatComponentType.None) format = shaderInput.variableType.Name; else format = r.Format.ToString(); } tag = new ViewBufTag(r, bufs[t], true, shaderInput); if (HasImportantViewParams(r, bufs[t])) viewDetails = true; } } } var node = parent.Add(new object[] { rootel, space, regname, name, typename, w, h, d, a, format }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = tag; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); ViewDetailsRow(node, viewDetails); } }
// Set a shader stage's resources and values private void SetShaderState(D3D12PipelineState.ShaderStage stage, Label shader, TreelistView.TreeListView resources, TreelistView.TreeListView samplers, TreelistView.TreeListView cbuffers, TreelistView.TreeListView uavs) { FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; D3D12PipelineState state = m_Core.CurD3D12PipelineState; ShaderReflection shaderDetails = stage.ShaderDetails; ShaderBindpointMapping bindpointMapping = stage.BindpointMapping; if (stage.Shader == ResourceId.Null) shader.Text = "Unbound"; else if (state.customName) shader.Text = state.PipelineName + " - " + m_Core.CurPipelineState.Abbrev(stage.stage); else shader.Text = state.PipelineName + " - " + stage.stage.Str(GraphicsAPI.D3D12) + " Shader"; if (shaderDetails != null && shaderDetails.DebugInfo.entryFunc.Length > 0 && shaderDetails.DebugInfo.files.Length > 0) { string shaderfn = ""; int entryFile = shaderDetails.DebugInfo.entryFile; if (entryFile < 0 || entryFile >= shaderDetails.DebugInfo.files.Length) entryFile = 0; shaderfn = shaderDetails.DebugInfo.files[entryFile].BaseFilename; shader.Text = shaderDetails.DebugInfo.entryFunc + "()" + " - " + shaderfn; } int vs = 0; vs = resources.VScrollValue(); resources.BeginUpdate(); resources.Nodes.Clear(); for (int space = 0; space < stage.Spaces.Length; space++) { for (int reg = 0; reg < stage.Spaces[space].SRVs.Length; reg++) { AddResourceRow(stage, resources, space, reg, false); } } resources.EndUpdate(); resources.NodesSelection.Clear(); resources.SetVScrollValue(vs); vs = uavs.VScrollValue(); uavs.BeginUpdate(); uavs.Nodes.Clear(); for (int space = 0; space < stage.Spaces.Length; space++) { for (int reg = 0; reg < stage.Spaces[space].UAVs.Length; reg++) { AddResourceRow(stage, uavs, space, reg, true); } } uavs.EndUpdate(); uavs.NodesSelection.Clear(); uavs.SetVScrollValue(vs); vs = samplers.VScrollValue(); samplers.BeginUpdate(); samplers.Nodes.Clear(); for (int space = 0; space < stage.Spaces.Length; space++) { for (int reg = 0; reg < stage.Spaces[space].Samplers.Length; reg++) { D3D12PipelineState.Sampler s = stage.Spaces[space].Samplers[reg]; // consider this register to not exist - it's in a gap defined by sparse root signature elements if (s.RootElement == uint.MaxValue) continue; BindpointMap bind = null; ShaderResource shaderInput = null; if (stage.BindpointMapping != null && stage.ShaderDetails != null) { for (int i = 0; i < stage.BindpointMapping.ReadOnlyResources.Length; i++) { var b = stage.BindpointMapping.ReadOnlyResources[i]; var res = stage.ShaderDetails.ReadOnlyResources[i]; bool regMatch = b.bind == reg; // handle unbounded arrays specially. It's illegal to have an unbounded array with // anything after it if (b.bind <= reg) regMatch = (b.arraySize == UInt32.MaxValue) || (b.bind + b.arraySize > reg); if (b.bindset == space && regMatch && res.IsSampler) { bind = b; shaderInput = res; break; } } } string rootel = s.Immediate ? String.Format("#{0} Static", s.RootElement) : String.Format("#{0} Table[{1}]", s.RootElement, s.TableIndex); bool filledSlot = (s.AddressU.Length > 0); bool usedSlot = (bind != null && bind.used); // show if if (usedSlot || // it's referenced by the shader - regardless of empty or not (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled" (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty" ) { string regname = reg.ToString(); if (shaderInput != null && shaderInput.name.Length > 0) regname += ": " + shaderInput.name; string borderColor = ""; string addressing = ""; string addPrefix = ""; string addVal = ""; string[] addr = { "", "", "" }; if (s != null) { borderColor = s.BorderColor[0].ToString() + ", " + s.BorderColor[1].ToString() + ", " + s.BorderColor[2].ToString() + ", " + s.BorderColor[3].ToString(); addr[0] = s.AddressU; addr[1] = s.AddressV; addr[2] = s.AddressW; } // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP for (int a = 0; a < 3; a++) { string prefix = "" + "UVW"[a]; if (a == 0 || addr[a] == addr[a - 1]) { addPrefix += prefix; } else { addressing += addPrefix + ": " + addVal + ", "; addPrefix = prefix; } addVal = addr[a]; } addressing += addPrefix + ": " + addVal; string filter = ""; string lodclamp = ""; float lodbias = 0.0f; if (s != null) { if (s.UseBorder) addressing += String.Format("<{0}>", borderColor); filter = s.Filter; if (s.MaxAniso > 0) filter += String.Format(" {0}x", s.MaxAniso); if (s.UseComparison) filter += String.Format(" ({0})", s.Comparison); lodclamp = (s.MinLOD == -float.MaxValue ? "0" : s.MinLOD.ToString()) + " - " + (s.MaxLOD == float.MaxValue ? "FLT_MAX" : s.MaxLOD.ToString()); lodbias = s.MipLODBias; } var node = samplers.Nodes.Add(new object[] { rootel, space, regname, addressing, filter, lodclamp, lodbias.ToString() }); if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); } } } samplers.EndUpdate(); samplers.NodesSelection.Clear(); samplers.SetVScrollValue(vs); vs = cbuffers.VScrollValue(); cbuffers.BeginUpdate(); cbuffers.Nodes.Clear(); for (int space = 0; space < stage.Spaces.Length; space++) { for (int reg = 0; reg < stage.Spaces[space].ConstantBuffers.Length; reg++) { D3D12PipelineState.CBuffer b = stage.Spaces[space].ConstantBuffers[reg]; // consider this register to not exist - it's in a gap defined by sparse root signature elements if (b.RootElement == uint.MaxValue) continue; BindpointMap bind = null; ConstantBlock shaderCBuf = null; object tag = null; if (stage.BindpointMapping != null && stage.ShaderDetails != null) { for (int i = 0; i < stage.BindpointMapping.ConstantBlocks.Length; i++) { var bd = stage.BindpointMapping.ConstantBlocks[i]; var res = stage.ShaderDetails.ConstantBlocks[i]; bool regMatch = bd.bind == reg; // handle unbounded arrays specially. It's illegal to have an unbounded array with // anything after it if (bd.bind <= reg) regMatch = (bd.arraySize == UInt32.MaxValue) || (bd.bind + bd.arraySize > reg); if (bd.bindset == space && regMatch) { bind = bd; shaderCBuf = res; tag = new CBufTag((uint)i); break; } } } if(tag == null) tag = new CBufTag(space, reg); string rootel; if (b.Immediate) { if (b.RootValues.Length > 0) rootel = String.Format("#{0} Consts", b.RootElement); else rootel = String.Format("#{0} Direct", b.RootElement); } else { rootel = String.Format("#{0} Table[{1}]", b.RootElement, b.TableIndex); } bool filledSlot = (b.Buffer != ResourceId.Null); if (b.Immediate && b.RootValues.Length > 0) filledSlot = true; bool usedSlot = (bind != null && bind.used); // show if if (usedSlot || // it's referenced by the shader - regardless of empty or not (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled" (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty" ) { string name = "Constant Buffer " + b.Buffer.ToString(); UInt64 length = 0; UInt64 offset = 0; int numvars = shaderCBuf != null ? shaderCBuf.variables.Length : 0; UInt32 byteSize = shaderCBuf != null ? shaderCBuf.byteSize : 0; if (b.Immediate && b.RootValues.Length > 0) byteSize = (UInt32)(b.RootValues.Length * 4); if (!filledSlot) name = "Empty"; if (b != null) { offset = b.Offset; length = b.ByteSize; for (int t = 0; t < bufs.Length; t++) if (bufs[t].ID == b.Buffer) name = bufs[t].name; } string regname = reg.ToString(); if (shaderCBuf != null && shaderCBuf.name.Length > 0) regname += ": " + shaderCBuf.name; string sizestr; if (byteSize == length) sizestr = String.Format("{0} Variables, {1} bytes", numvars, length); else sizestr = String.Format("{0} Variables, {1} bytes needed, {2} provided", numvars, byteSize, length); if (length < byteSize) filledSlot = false; var node = cbuffers.Nodes.Add(new object[] { rootel, space, regname, name, offset, sizestr }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = tag; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); } } } cbuffers.EndUpdate(); cbuffers.NodesSelection.Clear(); cbuffers.SetVScrollValue(vs); }
private bool HasImportantViewParams(D3D12PipelineState.ResourceView view, FetchBuffer buf) { if (view.FirstElement > 0 || view.NumElements*view.ElementSize < buf.length) return true; return false; }
// generally logFile == origFilename, but if the log was transferred remotely then origFilename // is the log locally before being copied we can present to the user in dialogs, etc. public void LoadLogfile(string logFile, string origFilename, bool temporary, bool local) { m_LogFile = origFilename; m_LogLocal = local; m_LogLoadingInProgress = true; if (File.Exists(Core.ConfigFilename)) m_Config.Serialize(Core.ConfigFilename); float postloadProgress = 0.0f; bool progressThread = true; // start a modal dialog to prevent the user interacting with the form while the log is loading. // We'll close it down when log loading finishes (whether it succeeds or fails) ProgressPopup modal = new ProgressPopup(LogLoadCallback, true); Thread modalThread = Helpers.NewThread(new ThreadStart(() => { modal.SetModalText(string.Format("Loading Log: {0}", origFilename)); AppWindow.BeginInvoke(new Action(() => { modal.ShowDialog(AppWindow); })); })); modalThread.Start(); // this thread continually ticks and notifies any threads of the progress, through a float // that is updated by the main loading code Thread thread = Helpers.NewThread(new ThreadStart(() => { modal.LogfileProgressBegin(); foreach (var p in m_ProgressListeners) p.LogfileProgressBegin(); while (progressThread) { Thread.Sleep(2); float progress = 0.8f * m_Renderer.LoadProgress + 0.19f * postloadProgress + 0.01f; modal.LogfileProgress(progress); foreach (var p in m_ProgressListeners) p.LogfileProgress(progress); } })); thread.Start(); // this function call will block until the log is either loaded, or there's some failure m_Renderer.OpenCapture(logFile); // if the renderer isn't running, we hit a failure case so display an error message if (!m_Renderer.Running) { string errmsg = m_Renderer.InitException.Status.Str(); MessageBox.Show(String.Format("{0}\nFailed to open file for replay: {1}.\n\n" + "Check diagnostic log in Help menu for more details.", origFilename, errmsg), "Error opening log", MessageBoxButtons.OK, MessageBoxIcon.Error); progressThread = false; thread.Join(); m_LogLoadingInProgress = false; modal.LogfileProgress(-1.0f); foreach (var p in m_ProgressListeners) p.LogfileProgress(-1.0f); return; } if (!temporary) { m_Config.AddRecentFile(m_Config.RecentLogFiles, origFilename, 10); if (File.Exists(Core.ConfigFilename)) m_Config.Serialize(Core.ConfigFilename); } m_EventID = 0; m_FrameInfo = null; m_APIProperties = null; // fetch initial data like drawcalls, textures and buffers m_Renderer.Invoke((ReplayRenderer r) => { m_FrameInfo = r.GetFrameInfo(); m_APIProperties = r.GetAPIProperties(); postloadProgress = 0.2f; m_DrawCalls = FakeProfileMarkers(r.GetDrawcalls()); bool valid = HasValidMarkerColors(m_DrawCalls); if (!valid) RemoveMarkerColors(m_DrawCalls); postloadProgress = 0.4f; m_Buffers = r.GetBuffers(); postloadProgress = 0.7f; var texs = new List<FetchTexture>(r.GetTextures()); m_Textures = texs.OrderBy(o => o.name).ToArray(); postloadProgress = 0.9f; m_D3D11PipelineState = r.GetD3D11PipelineState(); m_D3D12PipelineState = r.GetD3D12PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_VulkanPipelineState = r.GetVulkanPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_D3D12PipelineState, m_GLPipelineState, m_VulkanPipelineState); UnreadMessageCount = 0; AddMessages(m_FrameInfo.debugMessages); postloadProgress = 1.0f; }); Thread.Sleep(20); DateTime today = DateTime.Now; DateTime compare = today.AddDays(-21); if (compare.CompareTo(Config.DegradedLog_LastUpdate) >= 0 && m_APIProperties.degraded) { Config.DegradedLog_LastUpdate = today; MessageBox.Show(String.Format("{0}\nThis log opened with degraded support - " + "this could mean missing hardware support caused a fallback to software rendering.\n\n" + "This warning will not appear every time this happens, " + "check debug errors/warnings window for more details.", origFilename), "Degraded support of log", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } m_LogLoaded = true; progressThread = false; if (local) { m_LogWatcher = new FileSystemWatcher(Path.GetDirectoryName(m_LogFile), Path.GetFileName(m_LogFile)); m_LogWatcher.EnableRaisingEvents = true; m_LogWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.FileName | NotifyFilters.LastAccess | NotifyFilters.LastWrite; m_LogWatcher.Created += new FileSystemEventHandler(OnLogfileChanged); m_LogWatcher.Changed += new FileSystemEventHandler(OnLogfileChanged); m_LogWatcher.SynchronizingObject = m_MainWindow; // callbacks on UI thread please } List<ILogViewerForm> logviewers = new List<ILogViewerForm>(); logviewers.AddRange(m_LogViewers); // notify all the registers log viewers that a log has been loaded foreach (var logviewer in logviewers) { if (logviewer == null || !(logviewer is Control)) continue; Control c = (Control)logviewer; if (c.InvokeRequired) { if (!c.IsDisposed) { c.Invoke(new Action(() => { try { logviewer.OnLogfileLoaded(); } catch (Exception ex) { throw new AccessViolationException("Rethrown from Invoke:\n" + ex.ToString()); } })); } } else if (!c.IsDisposed) logviewer.OnLogfileLoaded(); } m_LogLoadingInProgress = false; modal.LogfileProgress(1.0f); foreach (var p in m_ProgressListeners) p.LogfileProgress(1.0f); }
private void ExportHTML(XmlTextWriter writer, D3D12PipelineState.InputAssembler ia) { FetchBuffer[] bufs = m_Core.CurBuffers; { writer.WriteStartElement("h3"); writer.WriteString("Input Layouts"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var l in ia.layouts) { rows.Add(new object[] { i, l.SemanticName, l.SemanticIndex, l.Format, l.InputSlot, l.ByteOffset, l.PerInstance, l.InstanceDataStepRate }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Semantic Name", "Semantic Index", "Format", "Input Slot", "Byte Offset", "Per Instance", "Instance Data Step Rate" }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Vertex Buffers"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var vb in ia.vbuffers) { string name = "Buffer " + vb.Buffer.ToString(); UInt64 length = 0; if (vb.Buffer == ResourceId.Null) { continue; } else { for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == vb.Buffer) { name = bufs[t].name; length = bufs[t].length; } } } rows.Add(new object[] { i, name, vb.Stride, vb.Offset, length }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Buffer", "Stride", "Offset", "Byte Length" }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Index Buffer"); writer.WriteEndElement(); string name = "Buffer " + ia.ibuffer.Buffer.ToString(); UInt64 length = 0; if (ia.ibuffer.Buffer == ResourceId.Null) { name = "Empty"; } else { for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == ia.ibuffer.Buffer) { name = bufs[t].name; length = bufs[t].length; } } } string ifmt = "UNKNOWN"; if (m_Core.CurDrawcall.indexByteWidth == 2) ifmt = "R16_UINT"; if (m_Core.CurDrawcall.indexByteWidth == 4) ifmt = "R32_UINT"; ExportHTMLTable(writer, new string[] { "Buffer", "Format", "Offset", "Byte Length" }, new object[] { name, ifmt, ia.ibuffer.Offset.ToString(), length.ToString() }); } writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Primitive Topology" }, new object[] { m_Core.CurDrawcall.topology.Str() }); }
private void SetEventID(ILogViewerForm exclude, UInt32 eventID, bool force) { m_EventID = eventID; m_Renderer.Invoke((ReplayRenderer r) => { r.SetFrameEvent(m_EventID, force); m_D3D11PipelineState = r.GetD3D11PipelineState(); m_D3D12PipelineState = r.GetD3D12PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_VulkanPipelineState = r.GetVulkanPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_D3D12PipelineState, m_GLPipelineState, m_VulkanPipelineState); }); foreach (var logviewer in m_LogViewers) { if(logviewer == exclude) continue; Control c = (Control)logviewer; if (c.InvokeRequired) c.Invoke(new Action(() => logviewer.OnEventSelected(eventID))); else logviewer.OnEventSelected(eventID); } }
private object[] ExportViewHTML(D3D12PipelineState.ResourceView view, int i, ShaderReflection refl, string extraParams) { FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; ShaderResource shaderInput = null; bool rw = false; if (refl != null) { foreach (var bind in refl.ReadOnlyResources) { if (bind.bindPoint == i) { shaderInput = bind; break; } } foreach (var bind in refl.ReadWriteResources) { if (bind.bindPoint == i) { shaderInput = bind; rw = true; break; } } } string name = "Empty"; string typename = "Unknown"; string format = "Unknown"; UInt64 w = 1; UInt32 h = 1, d = 1; UInt32 a = 0; string viewFormat = view.Format.ToString(); FetchTexture tex = null; FetchBuffer buf = null; // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == view.Resource) { w = texs[t].width; h = texs[t].height; d = texs[t].depth; a = texs[t].arraysize; format = texs[t].format.ToString(); name = texs[t].name; typename = texs[t].resType.ToString(); tex = texs[t]; } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == view.Resource) { w = bufs[t].length; h = 0; d = 0; a = 0; format = view.Format.ToString(); name = bufs[t].name; typename = "Buffer"; if (view.BufferFlags.HasFlag(D3DBufferViewFlags.Raw)) { typename = rw ? "RWByteAddressBuffer" : "ByteAddressBuffer"; } else if (view.ElementSize > 0) { // for structured buffers, display how many 'elements' there are in the buffer typename = (rw ? "RWStructuredBuffer" : "StructuredBuffer") + "[" + (bufs[t].length / view.ElementSize) + "]"; } if (view.CounterResource != ResourceId.Null) { typename += " (Count: " + view.BufferStructCount + ")"; } if (shaderInput != null && !shaderInput.IsTexture) { if (view.Format.compType == FormatComponentType.None) { if (shaderInput.variableType.members.Length > 0) viewFormat = format = "struct " + shaderInput.variableType.Name; else viewFormat = format = shaderInput.variableType.Name; } else { format = view.Format.ToString(); } } buf = bufs[t]; } } string viewParams = ""; if(buf != null) { viewParams = String.Format("First Element: {0}, Num Elements {1}, Flags {2}", view.FirstElement, view.NumElements, view.BufferFlags); } if (tex != null) { if(tex.mips > 1) viewParams = String.Format("Highest Mip: {0}, Num Mips: {1}", view.HighestMip, view.NumMipLevels); if (tex.arraysize > 1) { if (viewParams.Length > 0) viewParams += ", "; viewParams += String.Format("First Slice: {0}, Array Size: {1}", view.FirstArraySlice, view.ArraySize); } } if (viewParams == "") viewParams = extraParams; else viewParams += ", " + extraParams; return new object[] { i, name, view.Type, typename, w, h, d, a, viewFormat, format, viewParams }; }