public GLPipelineState GetGLPipelineState() { IntPtr mem = CustomMarshal.Alloc(typeof(GLPipelineState)); bool success = ReplayRenderer_GetGLPipelineState(m_Real, mem); GLPipelineState ret = null; if (success) { ret = (GLPipelineState)CustomMarshal.PtrToStructure(mem, typeof(GLPipelineState), true); } CustomMarshal.Free(mem); return(ret); }
// 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 (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 = Helpers.NewThread(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 = Helpers.NewThread(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; } if (!temporary) { m_Config.AddRecentFile(m_Config.RecentLogFiles, logFile, 10); if (File.Exists(Core.ConfigFilename)) m_Config.Serialize(Core.ConfigFilename); } 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)); 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); UnreadMessageCount = 0; AddMessages(m_FrameInfo[0].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.", logFile), "Degraded support of log", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } m_LogLoaded = true; progressThread = false; 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); }
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); DebugMessages.Clear(); UnreadMessageCount = 0; 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(); } }
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); } }
// 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); }
public void SetStates(APIProperties props, D3D11PipelineState d3d11, GLPipelineState gl) { m_APIProps = props; m_D3D11 = d3d11; m_GL = gl; }
// Set a shader stage's resources and values private void SetShaderState(FetchTexture[] texs, FetchBuffer[] bufs, 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) { { string name = shaderCBuf.name; int numvars = shaderCBuf.variables.Length; string slotname = i.ToString(); var node = cbuffers.Nodes.Add(new object[] { slotname, name, "", "", numvars, "" }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = i; } i++; } } cbuffers.EndUpdate(); cbuffers.NodesSelection.Clear(); }
// Set a shader stage's resources and values private void SetShaderState(FetchTexture[] texs, FetchBuffer[] bufs, GLPipelineState state, GLPipelineState.ShaderStage stage, TableLayoutPanel table, Label shader, TreelistView.TreeListView textures, TreelistView.TreeListView samplers, TreelistView.TreeListView cbuffers, TreelistView.TreeListView subs, TreelistView.TreeListView readwrites) { ShaderReflection shaderDetails = stage.ShaderDetails; var mapping = stage.BindpointMapping; if (stage.Shader == ResourceId.Null) shader.Text = "Unbound"; else shader.Text = stage.stage.Str(APIPipelineStateType.OpenGL) + " Shader " + stage.Shader.ToString(); // disabled since entry function is always main, and filenames have no names, so this is useless. /* if (shaderDetails != null && shaderDetails.DebugInfo.entryFunc != "" && shaderDetails.DebugInfo.files.Length > 0) shader.Text = shaderDetails.DebugInfo.entryFunc + "()" + " - " + Path.GetFileName(shaderDetails.DebugInfo.files[0].filename); */ int vs = 0; int vs2 = 0; // simultaneous update of resources and samplers vs = textures.VScrollValue(); textures.BeginUpdate(); textures.Nodes.Clear(); vs2 = samplers.VScrollValue(); samplers.BeginUpdate(); samplers.Nodes.Clear(); if (state.Textures != null) { for (int i = 0; i < state.Textures.Length; i++) { var r = state.Textures[i]; var s = state.Samplers[i]; ShaderResource shaderInput = null; BindpointMap map = null; if (shaderDetails != null) { foreach (var bind in shaderDetails.Resources) { if (bind.IsSRV && !bind.IsReadWrite && 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" ) { // do texture { 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 = texs[t].resType.Str(); if (texs[t].format.special && (texs[t].format.specialFormat == SpecialFormat.D24S8 || texs[t].format.specialFormat == SpecialFormat.D32S8) ) { if (r.DepthReadChannel == 0) format += " Depth-Read"; else if (r.DepthReadChannel == 1) format += " Stencil-Read"; } else if ( r.Swizzle[0] != TextureSwizzle.Red || r.Swizzle[1] != TextureSwizzle.Green || r.Swizzle[2] != TextureSwizzle.Blue || r.Swizzle[3] != TextureSwizzle.Alpha) { format += String.Format(" swizzle[{0}{1}{2}{3}]", r.Swizzle[0].Str(), r.Swizzle[1].Str(), r.Swizzle[2].Str(), r.Swizzle[3].Str()); } tag = texs[t]; } } var node = textures.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); } // do sampler { string slotname = i.ToString(); if (shaderInput != null && shaderInput.name.Length > 0) slotname += ": " + shaderInput.name; string borderColor = s.BorderColor[0].ToString() + ", " + s.BorderColor[1].ToString() + ", " + s.BorderColor[2].ToString() + ", " + s.BorderColor[3].ToString(); string addressing = ""; string addPrefix = ""; string addVal = ""; string[] addr = { s.AddressS, s.AddressT, s.AddressR }; // arrange like either STR: WRAP or ST: WRAP, R: CLAMP for (int a = 0; a < 3; a++) { string prefix = "" + "STR"[a]; if (a == 0 || addr[a] == addr[a - 1]) { addPrefix += prefix; } else { addressing += addPrefix + ": " + addVal + ", "; addPrefix = prefix; } addVal = addr[a]; } addressing += addPrefix + ": " + addVal; if (s.UseBorder) addressing += String.Format("<{0}>", borderColor); if (r.ResType == ShaderResourceType.TextureCube || r.ResType == ShaderResourceType.TextureCubeArray) { addressing += s.SeamlessCube ? " Seamless" : " Non-Seamless"; } string minfilter = s.MinFilter; if (s.MaxAniso > 1) minfilter += String.Format(" Aniso{0}x", s.MaxAniso); if (s.UseComparison) minfilter = String.Format("{0}", s.Comparison); var node = samplers.Nodes.Add(new object[] { slotname, addressing, minfilter, s.MagFilter, (s.MinLOD == -float.MaxValue ? "0" : s.MinLOD.ToString()) + " - " + (s.MaxLOD == float.MaxValue ? "FLT_MAX" : s.MaxLOD.ToString()), s.MipLODBias.ToString() }); if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); } } } } textures.EndUpdate(); textures.NodesSelection.Clear(); textures.SetVScrollValue(vs); samplers.EndUpdate(); samplers.NodesSelection.Clear(); samplers.SetVScrollValue(vs2); vs = cbuffers.VScrollValue(); cbuffers.BeginUpdate(); cbuffers.Nodes.Clear(); if (shaderDetails != null) { UInt32 i = 0; foreach (var shaderCBuf in shaderDetails.ConstantBlocks) { int bindPoint = stage.BindpointMapping.ConstantBlocks[i].bind; GLPipelineState.Buffer b = null; if (bindPoint >= 0 && bindPoint < state.UniformBuffers.Length) b = state.UniformBuffers[bindPoint]; bool filledSlot = !shaderCBuf.bufferBacked || (b != null && b.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" ) { ulong offset = 0; ulong length = 0; int numvars = shaderCBuf.variables.Length; string slotname = "Uniforms"; string name = ""; string sizestr = String.Format("{0} Variables", numvars); string byterange = ""; if (!filledSlot) { name = "Empty"; length = 0; } if (b != null) { slotname = String.Format("{0}: {1}", bindPoint, shaderCBuf.name); name = "UBO " + b.Resource.ToString(); offset = b.Offset; length = b.Size; for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == b.Resource) { name = bufs[t].name; if (length == 0) length = bufs[t].length; } } sizestr = String.Format("{0} Variables, {1} bytes", numvars, length); byterange = String.Format("{0} - {1}", offset, offset + length); } var node = cbuffers.Nodes.Add(new object[] { slotname, name, byterange, sizestr }); 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(); cbuffers.SetVScrollValue(vs); vs = subs.VScrollValue(); subs.BeginUpdate(); subs.Nodes.Clear(); { UInt32 i = 0; foreach (var subval in stage.Subroutines) { subs.Nodes.Add(new object[] { i.ToString(), subval.ToString() }); i++; } } subs.EndUpdate(); subs.NodesSelection.Clear(); subs.SetVScrollValue(vs); { subs.Visible = subs.Parent.Visible = (stage.Subroutines.Length > 0); int row = table.GetRow(subs.Parent); if (row >= 0 && row < table.RowStyles.Count) { if (stage.Subroutines.Length > 0) table.RowStyles[row].Height = table.RowStyles[1].Height; else table.RowStyles[row].Height = 0; } } vs = readwrites.VScrollValue(); readwrites.BeginUpdate(); readwrites.Nodes.Clear(); if (shaderDetails != null) { UInt32 i = 0; foreach (var res in shaderDetails.Resources) { int bindPoint = stage.BindpointMapping.Resources[i].bind; bool atomic = false; bool ssbo = false; bool image = false; if (!res.IsReadWrite) { i++; continue; } GLPipelineState.Buffer bf = null; GLPipelineState.ImageLoadStore im = null; ResourceId id = ResourceId.Null; if (res.IsTexture) { image = true; if (bindPoint >= 0 && bindPoint < state.Images.Length) { im = state.Images[bindPoint]; id = state.Images[bindPoint].Resource; } } else { if (res.variableType.descriptor.rows == 1 && res.variableType.descriptor.cols == 1 && res.variableType.descriptor.type == VarType.UInt) { atomic = true; if (bindPoint >= 0 && bindPoint < state.AtomicBuffers.Length) { bf = state.AtomicBuffers[bindPoint]; id = state.AtomicBuffers[bindPoint].Resource; } } else { ssbo = true; if (bindPoint >= 0 && bindPoint < state.ShaderStorageBuffers.Length) { bf = state.ShaderStorageBuffers[bindPoint]; id = state.ShaderStorageBuffers[bindPoint].Resource; } } } bool filledSlot = id != ResourceId.Null; bool usedSlot = stage.BindpointMapping.Resources[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 binding = image ? "Image" : atomic ? "Atomic" : ssbo ? "SSBO" : "Unknown"; string slotname = String.Format("{0}: {1}", bindPoint, res.name); string name = ""; string dimensions = ""; string format = "-"; string access = "Read/Write"; if (im != null) { if (im.readAllowed && !im.writeAllowed) access = "Read-Only"; if (!im.readAllowed && im.writeAllowed) access = "Write-Only"; format = im.Format.ToString(); } object tag = null; // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == id) { if (texs[t].dimension == 1) { if(texs[t].arraysize > 1) dimensions = String.Format("{0}[{1}]", texs[t].width, texs[t].arraysize); else dimensions = String.Format("{0}", texs[t].width); } else if (texs[t].dimension == 2) { if (texs[t].arraysize > 1) dimensions = String.Format("{0}x{1}[{2}]", texs[t].width, texs[t].height, texs[t].arraysize); else dimensions = String.Format("{0}x{1}", texs[t].width, texs[t].height); } else if (texs[t].dimension == 3) { dimensions = String.Format("{0}x{1}x{2}", texs[t].width, texs[t].height, texs[t].depth); } name = texs[t].name; tag = texs[t]; } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == id) { ulong offset = 0; ulong length = bufs[t].length; if (bf != null && bf.Size > 0) { offset = bf.Offset; length = bf.Size; } if(offset > 0) dimensions = String.Format("{0} bytes at offset {1} bytes", length, offset); else dimensions = String.Format("{0} bytes", length); name = bufs[t].name; tag = new ReadWriteTag(i, bufs[t]); } } if (!filledSlot) { name = "Empty"; dimensions = "-"; access = "-"; } var node = readwrites.Nodes.Add(new object[] { binding, slotname, name, dimensions, format, access }); 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++; } } readwrites.EndUpdate(); readwrites.NodesSelection.Clear(); readwrites.SetVScrollValue(vs); { readwrites.Visible = readwrites.Parent.Visible = (readwrites.Nodes.Count > 0); int row = table.GetRow(readwrites.Parent); if (row >= 0 && row < table.RowStyles.Count) { if (readwrites.Nodes.Count > 0) table.RowStyles[row].Height = table.RowStyles[1].Height; else table.RowStyles[row].Height = 0; } } }
private void ExportHTML(XmlTextWriter writer, GLPipelineState pipe, GLPipelineState.VertexInputs vtx) { FetchBuffer[] bufs = m_Core.CurBuffers; { writer.WriteStartElement("h3"); writer.WriteString("Vertex Attributes"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var a in vtx.attributes) { string generic = ""; if (!a.Enabled) generic = MakeGenericValueString(a.Format.compCount, a.Format.compType, a.GenericValue); rows.Add(new object[] { i, a.Enabled, a.BufferSlot, a.Format, a.RelativeOffset, generic }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Enabled", "Vertex Buffer Slot", "Format", "Relative Offset", "Generic Value" }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Vertex Buffers"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var vb in vtx.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, vb.Divisor, length }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Buffer", "Stride", "Offset", "Instance Divisor", "Byte Length" }, rows.ToArray()); } { writer.WriteStartElement("h3"); writer.WriteString("Index Buffer"); writer.WriteEndElement(); string name = "Buffer " + vtx.ibuffer.ToString(); UInt64 length = 0; if (vtx.ibuffer == ResourceId.Null) { name = "Empty"; } else { for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == vtx.ibuffer) { 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", "Byte Length" }, new object[] { name, ifmt, length.ToString() }); } writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Primitive Topology" }, new object[] { m_Core.CurDrawcall.topology.Str() }); { writer.WriteStartElement("h3"); writer.WriteString("States"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Primitive Restart", "Restart Index", "Provoking Vertex Last" }, new object[] { vtx.primitiveRestart, vtx.restartIndex, vtx.provokingVertexLast ? "Yes" : "No" }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Rasterizer Discard", "Clip Origin Lower Left", "Clip Space Z" }, new object[] { pipe.m_VtxProcess.discard ? "Yes" : "No", pipe.m_VtxProcess.clipOriginLowerLeft ? "Yes" : "No", pipe.m_VtxProcess.clipNegativeOneToOne ? "-1 to 1" : "0 to 1" }); writer.WriteStartElement("p"); writer.WriteEndElement(); object[][] clipPlaneRows = new object[8][]; for (int i = 0; i < 8; i++) clipPlaneRows[i] = new object[] { i.ToString(), pipe.m_VtxProcess.clipPlanes[i] ? "Yes" : "No" }; ExportHTMLTable(writer, new string[] { "User Clip Plane", "Enabled", }, clipPlaneRows); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Default Inner Tessellation Level", "Default Outer Tessellation level", }, new object[] { String.Format("{0}, {1}", pipe.m_VtxProcess.defaultInnerLevel[0], pipe.m_VtxProcess.defaultInnerLevel[1]), String.Format("{0}, {1}, {2}, {3}", pipe.m_VtxProcess.defaultOuterLevel[0], pipe.m_VtxProcess.defaultOuterLevel[1], pipe.m_VtxProcess.defaultOuterLevel[2], pipe.m_VtxProcess.defaultOuterLevel[3]), }); } }
private string MakeGenericValueString(uint compCount, FormatComponentType compType, GLPipelineState.VertexInputs.VertexAttribute.GenericValueUnion val) { string fmtstr = ""; if (compCount == 1) fmtstr = "<{0}>"; else if (compCount == 2) fmtstr = "<{0}, {1}>"; else if (compCount == 3) fmtstr = "<{0}, {1}, {2}>"; else if (compCount == 4) fmtstr = "<{0}, {1}, {2}, {3}>"; if (compType == FormatComponentType.UInt) return String.Format(fmtstr, val.u[0], val.u[1], val.u[2], val.u[3]); else if (compType == FormatComponentType.SInt) return String.Format(fmtstr, val.i[0], val.i[1], val.i[2], val.i[3]); else return String.Format(fmtstr, val.f[0], val.f[1], val.f[2], val.f[3]); }
private void ExportHTML(XmlTextWriter writer, GLPipelineState pipe, GLPipelineState.FrameBuffer fb) { { writer.WriteStartElement("h3"); writer.WriteString("Blend State"); writer.WriteEndElement(); var blendFactor = fb.m_BlendState.BlendFactor[0].ToString("F2") + ", " + fb.m_BlendState.BlendFactor[1].ToString("F2") + ", " + fb.m_BlendState.BlendFactor[2].ToString("F2") + ", " + fb.m_BlendState.BlendFactor[3].ToString("F2"); ExportHTMLTable(writer, new string[] { "Framebuffer SRGB", "Blend Factor" }, new object[] { fb.FramebufferSRGB ? "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 fb.m_BlendState.Blends) { if (!b.Enabled) continue; rows.Add(new object[] { i, b.Enabled ? "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", "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", "Depth Bounds" }, new object[] { pipe.m_DepthState.DepthEnable ? "Yes" : "No", pipe.m_DepthState.DepthWrites ? "Yes" : "No", pipe.m_DepthState.DepthFunc, pipe.m_DepthState.DepthEnable ? String.Format("{0} - {1}", Formatter.Format(pipe.m_DepthState.NearBound), Formatter.Format(pipe.m_DepthState.FarBound)) : "Disabled", }); } { writer.WriteStartElement("h3"); writer.WriteString("Stencil State"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Stencil Test Enable" }, new object[] { pipe.m_StencilState.StencilEnable ? "Yes" : "No" } ); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Face", "Reference", "Value Mask", "Write Mask", "Function", "Pass Operation", "Fail Operation", "Depth Fail Operation" }, new object[][] { new object[] { "Front", pipe.m_StencilState.m_FrontFace.Ref.ToString("X2"), pipe.m_StencilState.m_FrontFace.ValueMask.ToString("X2"), pipe.m_StencilState.m_FrontFace.WriteMask.ToString("X2"), pipe.m_StencilState.m_FrontFace.Func, pipe.m_StencilState.m_FrontFace.PassOp, pipe.m_StencilState.m_FrontFace.FailOp, pipe.m_StencilState.m_FrontFace.DepthFailOp }, new object[] { "Back", pipe.m_StencilState.m_BackFace.Ref.ToString("X2"), pipe.m_StencilState.m_BackFace.ValueMask.ToString("X2"), pipe.m_StencilState.m_BackFace.WriteMask.ToString("X2"), pipe.m_StencilState.m_BackFace.Func, pipe.m_StencilState.m_BackFace.PassOp, pipe.m_StencilState.m_BackFace.FailOp, pipe.m_StencilState.m_BackFace.DepthFailOp }, }); } { writer.WriteStartElement("h3"); writer.WriteString("Draw FBO Attachments"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); List<GLPipelineState.FrameBuffer.Attachment> atts = new List<GLPipelineState.FrameBuffer.Attachment>(); atts.AddRange(fb.m_DrawFBO.Color); atts.Add(fb.m_DrawFBO.Depth); atts.Add(fb.m_DrawFBO.Stencil); int i = 0; foreach (var a in atts) { FetchTexture tex = m_Core.GetTexture(a.Obj); string name = "Image " + a.Obj; if (tex != null) name = tex.name; if (a.Obj == ResourceId.Null) name = "Empty"; string slotname = i.ToString(); if (i == atts.Count - 2) slotname = "Depth"; else if (i == atts.Count - 1) slotname = "Stencil"; rows.Add(new object[] { slotname, name, a.Mip, a.Layer }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Image", "First mip", "First array slice", }, rows.ToArray()); object[][] drawbuffers = new object[fb.m_DrawFBO.DrawBuffers.Length][]; for (i = 0; i < fb.m_DrawFBO.DrawBuffers.Length; i++) drawbuffers[i] = new object[] { fb.m_DrawFBO.DrawBuffers[i] }; writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Draw Buffers", }, drawbuffers); } { writer.WriteStartElement("h3"); writer.WriteString("Read FBO Attachments"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); List<GLPipelineState.FrameBuffer.Attachment> atts = new List<GLPipelineState.FrameBuffer.Attachment>(); atts.AddRange(fb.m_ReadFBO.Color); atts.Add(fb.m_ReadFBO.Depth); atts.Add(fb.m_ReadFBO.Stencil); int i = 0; foreach (var a in atts) { FetchTexture tex = m_Core.GetTexture(a.Obj); string name = "Image " + a.Obj; if (tex != null) name = tex.name; if (a.Obj == ResourceId.Null) name = "Empty"; string slotname = i.ToString(); if (i == atts.Count - 2) slotname = "Depth"; else if (i == atts.Count - 1) slotname = "Stencil"; rows.Add(new object[] { slotname, name, a.Mip, a.Layer }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Image", "First mip", "First array slice", }, rows.ToArray()); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Read Buffer", }, new object[] { fb.m_ReadFBO.ReadBuffer }); } }
private void ExportHTML(XmlTextWriter writer, GLPipelineState pipe, GLPipelineState.Rasterizer rs) { writer.WriteStartElement("h3"); writer.WriteString("Rasterizer"); writer.WriteEndElement(); { 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[] { "Multisample Enable", "Sample Shading", "Sample Mask", "Sample Coverage", "Sample Coverage Invert", "Alpha to Coverage", "Alpha to One", "Min Sample Shading Rate" }, new object[] { rs.m_State.MultisampleEnable ? "Yes" : "No", rs.m_State.SampleShading ? "Yes" : "No", rs.m_State.SampleMask ? rs.m_State.SampleMaskValue.ToString("X8") : "No", rs.m_State.SampleCoverage ? rs.m_State.SampleCoverageValue.ToString("X8") : "No", rs.m_State.SampleCoverageInvert ? "Yes" : "No", rs.m_State.SampleAlphaToCoverage ? "Yes" : "No", rs.m_State.SampleAlphaToOne ? "Yes" : "No", Formatter.Format(rs.m_State.MinSampleShadingRate), }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Programmable Point Size", "Fixed Point Size", "Line Width", "Point Fade Threshold", "Point Origin Upper Left", }, new object[] { rs.m_State.ProgrammablePointSize ? "Yes" : "No", Formatter.Format(rs.m_State.PointSize), Formatter.Format(rs.m_State.LineWidth), Formatter.Format(rs.m_State.PointFadeThreshold), rs.m_State.PointOriginUpperLeft ? "Yes" : "No", }); writer.WriteStartElement("p"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Depth Clamp", "Depth Bias", "Offset Clamp", "Slope Scaled Bias" }, new object[] { rs.m_State.DepthClamp ? "Yes" : "No", rs.m_State.DepthBias, Formatter.Format(rs.m_State.OffsetClamp), Formatter.Format(rs.m_State.SlopeScaledDepthBias)}); } { writer.WriteStartElement("h3"); writer.WriteString("Hints"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Derivatives", "Line Smooth", "Poly Smooth", "Tex Compression", }, new object[] { pipe.m_Hints.Derivatives.ToString(), pipe.m_Hints.LineSmoothEnabled ? pipe.m_Hints.LineSmooth.ToString() : "Disabled", pipe.m_Hints.PolySmoothEnabled ? pipe.m_Hints.PolySmooth.ToString() : "Disabled", pipe.m_Hints.TexCompression.ToString(), }); } { writer.WriteStartElement("h3"); writer.WriteString("Viewports"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); int i = 0; foreach (var v in rs.Viewports) { rows.Add(new object[] { i, v.Enabled, v.Left, v.Bottom, v.Width, v.Height, v.MinDepth, v.MaxDepth }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Enabled", "Left", "Bottom", "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) { rows.Add(new object[] { i, s.Enabled, s.Left, s.Bottom, s.Width, s.Height }); i++; } ExportHTMLTable(writer, new string[] { "Slot", "Enabled", "Left", "Bottom", "Width", "Height" }, rows.ToArray()); } }
public void SetStates(APIProperties props, D3D11PipelineState d3d11, GLPipelineState gl, VulkanPipelineState vk) { m_APIProps = props; m_D3D11 = d3d11; m_GL = gl; m_Vulkan = vk; }
// 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); } }
private void ShowCBuffer(GLPipelineState.ShaderStage stage, UInt32 slot) { var existing = ConstantBufferPreviewer.Has(stage.stage, slot); if (existing != null) { existing.Show(); return; } var prev = new ConstantBufferPreviewer(m_Core, stage.stage, slot); var dock = Helpers.WrapDockContent(m_DockContent.DockPanel, prev); dock.DockState = DockState.DockRight; dock.DockAreas |= DockAreas.Float; ConstantBufferPreviewer.ShowDock(dock, m_DockContent.Pane, DockAlignment.Right, 0.3); }
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 ShowCBuffer(GLPipelineState.ShaderStage stage, UInt32 slot) { var existing = ConstantBufferPreviewer.Has(stage.stage, slot); if (existing != null) { existing.Show(); return; } var prev = new ConstantBufferPreviewer(m_Core, stage.stage, slot); prev.ShowDock(m_DockContent.Pane, DockAlignment.Right, 0.3); }
private void ExportHTML(XmlTextWriter writer, GLPipelineState state, GLPipelineState.ShaderStage sh) { FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; ShaderReflection shaderDetails = sh.ShaderDetails; ShaderBindpointMapping mapping = sh.BindpointMapping; { writer.WriteStartElement("h3"); writer.WriteString("Shader"); writer.WriteEndElement(); string shadername = "Unknown"; if (sh.Shader == ResourceId.Null) shadername = "Unbound"; else shadername = sh.ShaderName; if (sh.Shader == ResourceId.Null) { shadername = "Unbound"; } else { string shname = sh.stage.Str(APIPipelineStateType.OpenGL) + " Shader"; if (!sh.customShaderName && !sh.customProgramName && !sh.customPipelineName) { shadername = shname + " " + sh.Shader.ToString(); } else { if (sh.customShaderName) shname = sh.ShaderName; if (sh.customProgramName) shname = sh.ProgramName + " - " + shname; if (sh.customPipelineName && sh.PipelineActive) shname = sh.PipelineName + " - " + shname; shadername = shname; } } writer.WriteStartElement("p"); writer.WriteString(shadername); writer.WriteEndElement(); if (sh.Shader == ResourceId.Null) return; } List<object[]> textureRows = new List<object[]>(); List<object[]> samplerRows = new List<object[]>(); List<object[]> cbufferRows = new List<object[]>(); List<object[]> readwriteRows = new List<object[]>(); List<object[]> subRows = new List<object[]>(); if (state.Textures != null) { for (int i = 0; i < state.Textures.Length; i++) { var r = state.Textures[i]; var s = state.Samplers[i]; ShaderResource shaderInput = null; BindpointMap map = null; if (shaderDetails != null) { foreach (var bind in shaderDetails.ReadOnlyResources) { if (bind.IsSRV && mapping.ReadOnlyResources[bind.bindPoint].bind == i) { shaderInput = bind; map = mapping.ReadOnlyResources[bind.bindPoint]; } } } bool filledSlot = (r.Resource != ResourceId.Null); bool usedSlot = (shaderInput != null && map.used); if (shaderInput != null) { // do texture { 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 = texs[t].resType.Str(); if (texs[t].format.special && (texs[t].format.specialFormat == SpecialFormat.D16S8 || texs[t].format.specialFormat == SpecialFormat.D24S8 || texs[t].format.specialFormat == SpecialFormat.D32S8) ) { if (r.DepthReadChannel == 0) format += " Depth-Repipead"; else if (r.DepthReadChannel == 1) format += " Stencil-Read"; } else if ( r.Swizzle[0] != TextureSwizzle.Red || r.Swizzle[1] != TextureSwizzle.Green || r.Swizzle[2] != TextureSwizzle.Blue || r.Swizzle[3] != TextureSwizzle.Alpha) { format += String.Format(" swizzle[{0}{1}{2}{3}]", r.Swizzle[0].Str(), r.Swizzle[1].Str(), r.Swizzle[2].Str(), r.Swizzle[3].Str()); } tag = texs[t]; } } textureRows.Add(new object[] { slotname, name, typename, w, h, d, a, format }); } // do sampler { string slotname = i.ToString(); if (shaderInput != null && shaderInput.name.Length > 0) slotname += ": " + shaderInput.name; string borderColor = s.BorderColor[0].ToString() + ", " + s.BorderColor[1].ToString() + ", " + s.BorderColor[2].ToString() + ", " + s.BorderColor[3].ToString(); string addressing = ""; string addPrefix = ""; string addVal = ""; string[] addr = { s.AddressS, s.AddressT, s.AddressR }; // arrange like either STR: WRAP or ST: WRAP, R: CLAMP for (int a = 0; a < 3; a++) { string prefix = "" + "STR"[a]; if (a == 0 || addr[a] == addr[a - 1]) { addPrefix += prefix; } else { addressing += addPrefix + ": " + addVal + ", "; addPrefix = prefix; } addVal = addr[a]; } addressing += addPrefix + ": " + addVal; if (s.UseBorder) addressing += String.Format("<{0}>", borderColor); if (r.ResType == ShaderResourceType.TextureCube || r.ResType == ShaderResourceType.TextureCubeArray) { addressing += s.SeamlessCube ? " Seamless" : " Non-Seamless"; } string minfilter = s.MinFilter; if (s.MaxAniso > 1) minfilter += String.Format(" Aniso{0}x", s.MaxAniso); if (s.UseComparison) minfilter = String.Format("{0}", s.Comparison); samplerRows.Add(new object[] { slotname, addressing, minfilter, s.MagFilter, (s.MinLOD == -float.MaxValue ? "0" : s.MinLOD.ToString()) + " - " + (s.MaxLOD == float.MaxValue ? "FLT_MAX" : s.MaxLOD.ToString()), s.MipLODBias.ToString() }); } } } } if (shaderDetails != null) { UInt32 i = 0; foreach (var shaderCBuf in shaderDetails.ConstantBlocks) { int bindPoint = mapping.ConstantBlocks[i].bind; GLPipelineState.Buffer b = null; if (bindPoint >= 0 && bindPoint < state.UniformBuffers.Length) b = state.UniformBuffers[bindPoint]; bool filledSlot = !shaderCBuf.bufferBacked || (b != null && b.Resource != ResourceId.Null); bool usedSlot = mapping.ConstantBlocks[i].used; // show if { ulong offset = 0; ulong length = 0; int numvars = shaderCBuf.variables.Length; ulong byteSize = (ulong)shaderCBuf.byteSize; string slotname = "Uniforms"; string name = ""; string sizestr = String.Format("{0} Variables", numvars); string byterange = ""; if (!filledSlot) { name = "Empty"; length = 0; } if (b != null) { slotname = String.Format("{0}: {1}", bindPoint, shaderCBuf.name); name = "UBO " + b.Resource.ToString(); offset = b.Offset; length = b.Size; for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == b.Resource) { name = bufs[t].name; if (length == 0) length = bufs[t].length; } } if (length == byteSize) sizestr = String.Format("{0} Variables, {1} bytes", numvars, length); else sizestr = String.Format("{0} Variables, {1} bytes needed, {2} provided", numvars, byteSize, length); byterange = String.Format("{0} - {1}", offset, offset + length); } cbufferRows.Add(new object[] { slotname, name, byterange, sizestr }); } i++; } } { UInt32 i = 0; foreach (var subval in sh.Subroutines) { subRows.Add(new object[] { i.ToString(), subval.ToString() }); i++; } } if (shaderDetails != null) { UInt32 i = 0; foreach (var res in shaderDetails.ReadWriteResources) { int bindPoint = mapping.ReadWriteResources[i].bind; GLReadWriteType readWriteType = GetGLReadWriteType(res); GLPipelineState.Buffer bf = null; GLPipelineState.ImageLoadStore im = null; ResourceId id = ResourceId.Null; if (readWriteType == GLReadWriteType.Image && bindPoint >= 0 && bindPoint < state.Images.Length) { im = state.Images[bindPoint]; id = state.Images[bindPoint].Resource; } if (readWriteType == GLReadWriteType.Atomic && bindPoint >= 0 && bindPoint < state.AtomicBuffers.Length) { bf = state.AtomicBuffers[bindPoint]; id = state.AtomicBuffers[bindPoint].Resource; } if (readWriteType == GLReadWriteType.SSBO && bindPoint >= 0 && bindPoint < state.ShaderStorageBuffers.Length) { bf = state.ShaderStorageBuffers[bindPoint]; id = state.ShaderStorageBuffers[bindPoint].Resource; } bool filledSlot = id != ResourceId.Null; bool usedSlot = mapping.ReadWriteResources[i].used; // show if { string binding = readWriteType == GLReadWriteType.Image ? "Image" : readWriteType == GLReadWriteType.Atomic ? "Atomic" : readWriteType == GLReadWriteType.SSBO ? "SSBO" : "Unknown"; string slotname = String.Format("{0}: {1}", bindPoint, res.name); string name = ""; string dimensions = ""; string format = "-"; string access = "Read/Write"; if (im != null) { if (im.readAllowed && !im.writeAllowed) access = "Read-Only"; if (!im.readAllowed && im.writeAllowed) access = "Write-Only"; format = im.Format.ToString(); } object tag = null; // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == id) { if (texs[t].dimension == 1) { if (texs[t].arraysize > 1) dimensions = String.Format("{0}[{1}]", texs[t].width, texs[t].arraysize); else dimensions = String.Format("{0}", texs[t].width); } else if (texs[t].dimension == 2) { if (texs[t].arraysize > 1) dimensions = String.Format("{0}x{1}[{2}]", texs[t].width, texs[t].height, texs[t].arraysize); else dimensions = String.Format("{0}x{1}", texs[t].width, texs[t].height); } else if (texs[t].dimension == 3) { dimensions = String.Format("{0}x{1}x{2}", texs[t].width, texs[t].height, texs[t].depth); } name = texs[t].name; tag = texs[t]; } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == id) { ulong offset = 0; ulong length = bufs[t].length; if (bf != null && bf.Size > 0) { offset = bf.Offset; length = bf.Size; } if (offset > 0) dimensions = String.Format("{0} bytes at offset {1} bytes", length, offset); else dimensions = String.Format("{0} bytes", length); name = bufs[t].name; tag = new ReadWriteTag(i, bufs[t]); } } if (!filledSlot) { name = "Empty"; dimensions = "-"; access = "-"; } readwriteRows.Add(new object[] { binding, slotname, name, dimensions, format, access }); } i++; } } { writer.WriteStartElement("h3"); writer.WriteString("Textures"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Slot", "Name", "Type", "Width", "Height", "Depth", "Array Size", "Format" }, textureRows.ToArray() ); } { writer.WriteStartElement("h3"); writer.WriteString("Samplers"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Slot", "Addressing", "Min Filter", "Mag Filter", "LOD Clamping", "LOD Bias" }, samplerRows.ToArray() ); } { writer.WriteStartElement("h3"); writer.WriteString("Uniform Buffers"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Slot", "Name", "Byte Range", "Size" }, cbufferRows.ToArray() ); } { writer.WriteStartElement("h3"); writer.WriteString("Subroutines"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Index", "Value" }, subRows.ToArray() ); } { writer.WriteStartElement("h3"); writer.WriteString("Read-write resources"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Binding", "Resource", "Name", "Dimensions", "Format", "Access", }, readwriteRows.ToArray() ); } }
private void ExportHTML(XmlTextWriter writer, GLPipelineState pipe, GLPipelineState.Feedback xfb) { FetchBuffer[] bufs = m_Core.CurBuffers; { writer.WriteStartElement("h3"); writer.WriteString("States"); writer.WriteEndElement(); ExportHTMLTable(writer, new string[] { "Active", "Paused" }, new object[] { xfb.Active ? "Yes" : "No", xfb.Paused ? "Yes" : "No" }); } { writer.WriteStartElement("h3"); writer.WriteString("Transform Feedback Targets"); writer.WriteEndElement(); List<object[]> rows = new List<object[]>(); for(int i=0; i < xfb.BufferBinding.Length; i++) { string name = "Buffer " + xfb.BufferBinding[i].ToString(); UInt64 length = 0; if (xfb.BufferBinding[i] == ResourceId.Null) { name = "Empty"; } else { for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == xfb.BufferBinding[i]) { name = bufs[t].name; length = bufs[t].length; } } } rows.Add(new object[] { i, name, xfb.Offset[i], xfb.Size[i], length }); } ExportHTMLTable(writer, new string[] { "Slot", "Buffer", "Offset", "Binding size", "Buffer byte Length" }, rows.ToArray()); } }
// 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(); }