public void SetStates(APIProperties props, D3D11PipelineState d3d11, GLPipelineState gl, VulkanPipelineState vk) { m_APIProps = props; m_D3D11 = d3d11; m_GL = gl; m_Vulkan = vk; }
public void SetEventID(ILogViewerForm exclude, UInt32 frameID, UInt32 eventID) { m_FrameID = frameID; m_EventID = eventID; m_DeferredEvent = 0; m_Renderer.Invoke((ReplayRenderer r) => { r.SetContextFilter(ResourceId.Null, 0, 0); }); m_Renderer.Invoke((ReplayRenderer r) => { r.SetFrameEvent(m_FrameID, m_EventID); m_D3D11PipelineState = r.GetD3D11PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState); }); foreach (var logviewer in m_LogViewers) { if (logviewer == exclude) { continue; } Control c = (Control)logviewer; if (c.InvokeRequired) { c.BeginInvoke(new Action(() => logviewer.OnEventSelected(frameID, eventID))); } else { logviewer.OnEventSelected(frameID, eventID); } } }
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 (exclude.Contains(logviewer)) { continue; } Control c = (Control)logviewer; if (c.InvokeRequired) { c.Invoke(new Action(() => logviewer.OnEventSelected(eventID))); } else { logviewer.OnEventSelected(eventID); } } }
// setting a context filter allows replaying of deferred events. You can set the deferred // events to replay in a context, after replaying up to a given event on the main thread public void SetContextFilter(ILogViewerForm exclude, UInt32 eventID, ResourceId ctx, UInt32 firstDeferred, UInt32 lastDeferred) { m_EventID = eventID; m_DeferredEvent = lastDeferred; m_Renderer.Invoke((ReplayRenderer r) => { r.SetContextFilter(ctx, firstDeferred, lastDeferred); }); m_Renderer.Invoke((ReplayRenderer r) => { r.SetFrameEvent(m_EventID, true); m_D3D11PipelineState = r.GetD3D11PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_VulkanPipelineState = r.GetVulkanPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState, m_VulkanPipelineState); }); foreach (var logviewer in m_LogViewers) { if (logviewer == exclude) { continue; } Control c = (Control)logviewer; if (c.InvokeRequired) { c.BeginInvoke(new Action(() => logviewer.OnEventSelected(eventID))); } else { logviewer.OnEventSelected(eventID); } } }
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(); } } }
public void CloseLogfile() { if (!m_LogLoaded) { return; } m_LogFile = ""; m_Renderer.CloseThreadSync(); m_Renderer = new RenderManager(); m_APIProperties = null; m_FrameInfo = null; m_DrawCalls = null; m_Buffers = null; m_Textures = null; m_D3D11PipelineState = null; m_GLPipelineState = null; m_PipelineState.SetStates(null, null, null); m_LogLoaded = false; foreach (var logviewer in m_LogViewers) { Control c = (Control)logviewer; if (c.InvokeRequired) { c.Invoke(new Action(() => logviewer.OnLogfileClosed())); } else { logviewer.OnLogfileClosed(); } } }
// when loading a log while replaying remotely, provide the proxy renderer that will be used // as well as the hostname to replay on. public void LoadLogfile(int proxyRenderer, string replayHost, string logFile, bool temporary) { m_LogFile = logFile; m_LogLoadingInProgress = true; if (!temporary) { m_Config.AddRecentFile(m_Config.RecentLogFiles, logFile, 10); } 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) ModalPopup modal = new ModalPopup(LogLoadCallback, true); Thread modalThread = new Thread(new ThreadStart(() => { modal.SetModalText(string.Format("Loading Log {0}.", m_LogFile)); 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 = new Thread(new ThreadStart(() => { modal.LogfileProgressBegin(); foreach (var p in m_ProgressListeners) { p.LogfileProgressBegin(); } while (progressThread) { Thread.Sleep(2); float progress = 0.5f * m_Renderer.LoadProgress + 0.49f * 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.Init(proxyRenderer, replayHost, logFile); // if the renderer isn't running, we hit a failure case so display an error message if (!m_Renderer.Running) { string errmsg = "Unknown error message"; if (m_Renderer.InitException.Data.Contains("status")) { errmsg = ((ReplayCreateStatus)m_Renderer.InitException.Data["status"]).Str(); } if (proxyRenderer >= 0) { MessageBox.Show(String.Format("{0}\nFailed to transfer and replay on remote host {1}: {2}.\n\n" + "Check diagnostic log in Help menu for more details.", logFile, replayHost, errmsg), "Error opening log", MessageBoxButtons.OK, MessageBoxIcon.Error); } else { MessageBox.Show(String.Format("{0}\nFailed to open logfile for replay: {1}.\n\n" + "Check diagnostic log in Help menu for more details.", logFile, 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; } m_FrameID = 0; 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 = new FetchDrawcall[m_FrameInfo.Length][]; postloadProgress = 0.4f; for (int i = 0; i < m_FrameInfo.Length; i++) { m_DrawCalls[i] = FakeProfileMarkers(i, r.GetDrawcalls((UInt32)i, false)); } m_TimedDrawcalls = false; postloadProgress = 0.7f; m_Buffers = r.GetBuffers(); postloadProgress = 0.8f; var texs = new List <FetchTexture>(r.GetTextures()); m_Textures = texs.OrderBy(o => o.name).ToArray(); postloadProgress = 0.9f; m_D3D11PipelineState = r.GetD3D11PipelineState(); m_GLPipelineState = r.GetGLPipelineState(); m_PipelineState.SetStates(m_APIProperties, m_D3D11PipelineState, m_GLPipelineState); postloadProgress = 1.0f; }); Thread.Sleep(20); m_LogLoaded = true; progressThread = false; // notify all the registers log viewers that a log has been loaded foreach (var logviewer in m_LogViewers) { 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); } }
// 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) { try { 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 } catch (ArgumentException) { // likely an "invalid" directory name - FileSystemWatcher doesn't support UNC paths properly } } List <ILogViewerForm> logviewers = new List <ILogViewerForm>(); logviewers.AddRange(m_LogViewers); // make sure we're on a consistent event before invoking log viewer forms FetchDrawcall draw = m_DrawCalls.Last(); while (draw.children != null && draw.children.Length > 0) { draw = draw.children.Last(); } SetEventID(logviewers.ToArray(), draw.eventID, true); // 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); } }
public void SetStates(APIProperties props, D3D11PipelineState d3d11, GLPipelineState gl) { m_APIProps = props; m_D3D11 = d3d11; m_GL = gl; }
private void UpdateState() { if (!m_Core.LogLoaded) { return; } FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; GLPipelineState state = m_Core.CurGLPipelineState; FetchDrawcall draw = m_Core.CurDrawcall; var tick = global::renderdocui.Properties.Resources.tick; var cross = global::renderdocui.Properties.Resources.cross; bool[] usedVBuffers = new bool[128]; for (int i = 0; i < 128; i++) { usedVBuffers[i] = false; } //////////////////////////////////////////////// // Input Assembler inputLayouts.Nodes.Clear(); inputLayouts.BeginUpdate(); if (state.m_VtxIn.attributes != null) { int i = 0; foreach (var l in state.m_VtxIn.attributes) { if (l.Enabled || showDisabled.Checked) { string byteOffs = l.RelativeOffset.ToString(); var node = inputLayouts.Nodes.Add(new object[] { i, l.Enabled ? "Enabled" : "Disabled", "", l.Format, l.BufferSlot.ToString(), byteOffs, "", "" }); usedVBuffers[l.BufferSlot] = true; node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; if (!l.Enabled) { InactiveRow(node); } } i++; } } inputLayouts.NodesSelection.Clear(); inputLayouts.EndUpdate(); topology.Text = state.m_VtxIn.Topology.ToString(); if (state.m_VtxIn.Topology > PrimitiveTopology.PatchList) { int numCPs = (int)state.m_VtxIn.Topology - (int)PrimitiveTopology.PatchList + 1; topology.Text = string.Format("PatchList ({0} Control Points)", numCPs); } switch (state.m_VtxIn.Topology) { case PrimitiveTopology.PointList: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_pointlist; break; case PrimitiveTopology.LineList: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linelist; break; case PrimitiveTopology.LineStrip: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linestrip; break; case PrimitiveTopology.TriangleList: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_trilist; break; case PrimitiveTopology.TriangleStrip: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_tristrip; break; case PrimitiveTopology.LineList_Adj: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linelist_adj; break; case PrimitiveTopology.LineStrip_Adj: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linestrip_adj; break; case PrimitiveTopology.TriangleList_Adj: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_trilist_adj; break; case PrimitiveTopology.TriangleStrip_Adj: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_tristrip_adj; break; default: topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_patch; break; } iabuffers.Nodes.Clear(); iabuffers.BeginUpdate(); bool ibufferUsed = draw != null && (draw.flags & DrawcallFlags.UseIBuffer) != 0; if (state.m_VtxIn.ibuffer != null) { if (ibufferUsed || showDisabled.Checked) { string ptr = "Buffer " + state.m_VtxIn.ibuffer.Buffer.ToString(); string name = ptr; UInt32 length = 1; if (!ibufferUsed) { length = 0; } for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == state.m_VtxIn.ibuffer.Buffer) { name = bufs[t].name; length = bufs[t].length; } } var node = iabuffers.Nodes.Add(new object[] { "Index", name, state.m_VtxIn.ibuffer.Format.compByteWidth, state.m_VtxIn.ibuffer.Offset, length }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = state.m_VtxIn.ibuffer.Buffer; if (!ibufferUsed) { InactiveRow(node); } if (state.m_VtxIn.ibuffer.Buffer == ResourceId.Null) { EmptyRow(node); } } } else { if (showEmpty.Checked && (ibufferUsed || showDisabled.Checked)) { var node = iabuffers.Nodes.Add(new object[] { "Index", "-", "-", "-", "-" }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = state.m_VtxIn.ibuffer.Buffer; EmptyRow(node); if (!ibufferUsed) { InactiveRow(node); } } } m_VBNodes.Clear(); if (state.m_VtxIn.vbuffers != null) { int i = 0; foreach (var v in state.m_VtxIn.vbuffers) { bool filledSlot = (v.Buffer != ResourceId.Null); bool usedSlot = (usedVBuffers[i]); // 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 = "Buffer " + v.Buffer.ToString(); UInt32 length = 1; if (!filledSlot) { name = "Empty"; length = 0; } for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == v.Buffer) { name = bufs[t].name; length = bufs[t].length; } } var node = iabuffers.Nodes.Add(new object[] { i, name, v.Stride, v.Offset, length }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = v.Buffer; if (!filledSlot) { EmptyRow(node); } if (!usedSlot) { InactiveRow(node); } m_VBNodes.Add(node); } i++; } } iabuffers.NodesSelection.Clear(); iabuffers.EndUpdate(); SetShaderState(texs, bufs, state, state.m_VS, vsShader, vsResources, vsSamplers, vsCBuffers, vsClasses); SetShaderState(texs, bufs, state, state.m_GS, gsShader, gsResources, gsSamplers, gsCBuffers, gsClasses); SetShaderState(texs, bufs, state, state.m_TES, tesShader, tesResources, tesSamplers, tesCBuffers, tesClasses); SetShaderState(texs, bufs, state, state.m_TCS, tcsShader, tcsResources, tcsSamplers, tcsCBuffers, tcsClasses); SetShaderState(texs, bufs, state, state.m_FS, fsShader, fsResources, fsSamplers, fsCBuffers, fsClasses); SetShaderState(texs, bufs, state, state.m_CS, csShader, csResources, csSamplers, csCBuffers, csClasses); fsResources.BeginUpdate(); fsResources.Nodes.Clear(); if (state.Textures != null) { var shaderDetails = state.m_FS.ShaderDetails; var mapping = state.m_FS.BindpointMapping; int i = 0; foreach (var r in state.Textures) { ShaderResource shaderInput = null; BindpointMap map = null; if (shaderDetails != null) { foreach (var bind in shaderDetails.Resources) { if (bind.IsSRV && mapping.Resources[bind.bindPoint].bind == i) { shaderInput = bind; map = mapping.Resources[bind.bindPoint]; } } } bool filledSlot = (r.Resource != ResourceId.Null); bool usedSlot = (shaderInput != null && map.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 slotname = i.ToString(); if (shaderInput != null && shaderInput.name != "") { slotname += ": " + shaderInput.name; } UInt32 w = 1, h = 1, d = 1; UInt32 a = 1; string format = "Unknown"; string name = "Shader Resource " + r.Resource.ToString(); string typename = "Unknown"; object tag = null; if (!filledSlot) { name = "Empty"; format = "-"; typename = "-"; w = h = d = a = 0; } // 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 = string.Format("Texture{0}D", texs[t].dimension); if (texs[t].cubemap) { typename = "TexCube"; } tag = texs[t]; } } // 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 = 0; d = 0; a = 0; format = ""; name = bufs[t].name; typename = "Buffer"; // for structured buffers, display how many 'elements' there are in the buffer if (bufs[t].structureSize > 0) { typename = "StructuredBuffer[" + (bufs[t].length / bufs[t].structureSize) + "]"; } tag = bufs[t]; } } var node = fsResources.Nodes.Add(new object[] { slotname, 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); } } i++; } } fsResources.EndUpdate(); fsResources.NodesSelection.Clear(); csUAVs.Nodes.Clear(); csUAVs.BeginUpdate(); csUAVs.NodesSelection.Clear(); csUAVs.EndUpdate(); gsStreams.BeginUpdate(); gsStreams.Nodes.Clear(); gsStreams.EndUpdate(); gsStreams.NodesSelection.Clear(); //////////////////////////////////////////////// // Rasterizer viewports.BeginUpdate(); viewports.Nodes.Clear(); viewports.NodesSelection.Clear(); viewports.EndUpdate(); scissors.BeginUpdate(); scissors.Nodes.Clear(); scissors.NodesSelection.Clear(); scissors.EndUpdate(); //////////////////////////////////////////////// // Output Merger bool[] targets = new bool[8]; for (int i = 0; i < 8; i++) { targets[i] = false; } targetOutputs.BeginUpdate(); targetOutputs.Nodes.Clear(); { int i = 0; foreach (var p in state.m_FB.Color) { if (p != ResourceId.Null || showEmpty.Checked) { UInt32 w = 1, h = 1, d = 1; UInt32 a = 1; string format = "Unknown"; string name = "Texture " + p.ToString(); string typename = "Unknown"; object tag = null; if (p == ResourceId.Null) { name = "Empty"; format = "-"; typename = "-"; w = h = d = a = 0; } for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == p) { 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 = string.Format("Texture{0}D", texs[t].dimension); if (texs[t].cubemap) { typename = "TexCube"; } tag = texs[t]; } } var node = targetOutputs.Nodes.Add(new object[] { i, 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 (p == ResourceId.Null) { EmptyRow(node); } else { targets[i] = true; } } i++; } } { int i = 0; foreach (ResourceId depthstencil in new ResourceId[] { state.m_FB.Depth, state.m_FB.Stencil }) { if (depthstencil != ResourceId.Null || showEmpty.Checked) { UInt32 w = 1, h = 1, d = 1; UInt32 a = 1; string format = "Unknown"; string name = "Depth Target " + depthstencil.ToString(); string typename = "Unknown"; object tag = null; if (depthstencil == ResourceId.Null) { name = "Empty"; format = "-"; typename = "-"; w = h = d = a = 0; } for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == depthstencil) { 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 = string.Format("Texture{0}D", texs[t].dimension); if (texs[t].cubemap) { typename = "TexCube"; } tag = texs[t]; } } string slot = "Depth"; if (i == 1) { slot = "Stencil"; } var node = targetOutputs.Nodes.Add(new object[] { slot, 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 (depthstencil == ResourceId.Null) { EmptyRow(node); } } i++; } } targetOutputs.EndUpdate(); targetOutputs.NodesSelection.Clear(); blendOperations.BeginUpdate(); blendOperations.Nodes.Clear(); blendOperations.NodesSelection.Clear(); blendOperations.EndUpdate(); stencilFuncs.BeginUpdate(); stencilFuncs.Nodes.Clear(); stencilFuncs.Nodes.Add(new object[] { "Front", "", "", "", "" }); stencilFuncs.Nodes.Add(new object[] { "Back", "", "", "", "" }); stencilFuncs.EndUpdate(); stencilFuncs.NodesSelection.Clear(); // highlight the appropriate stages in the flowchart if (draw == null) { pipeFlow.SetStagesEnabled(new bool[] { true, true, true, true, true, true, true, true, true }); } else if ((draw.flags & DrawcallFlags.Dispatch) != 0) { pipeFlow.SetStagesEnabled(new bool[] { false, false, false, false, false, false, false, false, true }); } else { pipeFlow.SetStagesEnabled(new bool[] { true, true, state.m_TES.Shader != ResourceId.Null, state.m_TCS.Shader != ResourceId.Null, state.m_GS.Shader != ResourceId.Null, true, state.m_FS.Shader != ResourceId.Null, true, false }); // if(streamout only) //{ // pipeFlow.Rasterizer = false; // pipeFlow.OutputMerger = false; //} } }
// Set a shader stage's resources and values private void SetShaderState(FetchTexture[] texs, FetchBuffer[] bufs, GLPipelineState state, GLPipelineState.ShaderStage stage, Label shader, TreelistView.TreeListView resources, TreelistView.TreeListView samplers, TreelistView.TreeListView cbuffers, TreelistView.TreeListView classes) { ShaderReflection shaderDetails = stage.ShaderDetails; if (stage.Shader == ResourceId.Null) { shader.Text = "Unbound"; } else { shader.Text = "Shader " + stage.Shader.ToString(); } if (shaderDetails != null && shaderDetails.DebugInfo.entryFunc != "" && shaderDetails.DebugInfo.files.Length > 0) { shader.Text = shaderDetails.DebugInfo.entryFunc + "()" + " - " + Path.GetFileName(shaderDetails.DebugInfo.files[0].filename); } cbuffers.BeginUpdate(); cbuffers.Nodes.Clear(); if (shaderDetails != null) { UInt32 i = 0; foreach (var shaderCBuf in shaderDetails.ConstantBlocks) { int bindPoint = stage.BindpointMapping.ConstantBlocks[i].bind; bool filledSlot = !shaderCBuf.bufferBacked || (bindPoint >= 0 && bindPoint < state.UniformBuffers.Length && state.UniformBuffers[bindPoint].Resource != ResourceId.Null); bool usedSlot = stage.BindpointMapping.ConstantBlocks[i].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 = shaderCBuf.name; int numvars = shaderCBuf.variables.Length; string slotname = i.ToString(); var node = cbuffers.Nodes.Add(new object[] { slotname, name, bindPoint, "", numvars, "" }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = i; if (!filledSlot) { EmptyRow(node); } if (!usedSlot) { InactiveRow(node); } } i++; } } cbuffers.EndUpdate(); cbuffers.NodesSelection.Clear(); }