mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
354 lines
11 KiB
C#
354 lines
11 KiB
C#
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2014 Crytek
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Text.RegularExpressions;
|
|
using System.Runtime.InteropServices;
|
|
using WeifenLuo.WinFormsUI.Docking;
|
|
using renderdocui.Code;
|
|
using renderdoc;
|
|
|
|
namespace renderdocui.Windows
|
|
{
|
|
public partial class APIInspector : DockContent, ILogViewerForm
|
|
{
|
|
private Core m_Core;
|
|
|
|
public APIInspector(Core core)
|
|
{
|
|
InitializeComponent();
|
|
|
|
Icon = global::renderdocui.Properties.Resources.icon;
|
|
|
|
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
|
|
|
m_Core = core;
|
|
|
|
callstack.Font =
|
|
apiEvents.Font =
|
|
core.Config.PreferredFont;
|
|
|
|
panelSplitter.Collapsed = true;
|
|
}
|
|
|
|
public void OnLogfileLoaded()
|
|
{
|
|
}
|
|
|
|
public void OnLogfileClosed()
|
|
{
|
|
apiEvents.BeginUpdate();
|
|
apiEvents.Nodes.Clear();
|
|
apiEvents.EndUpdate();
|
|
|
|
if (!callstack.IsDisposed)
|
|
{
|
|
callstack.BeginUpdate();
|
|
callstack.Items.Clear();
|
|
callstack.EndUpdate();
|
|
}
|
|
}
|
|
|
|
public void FillAPIView()
|
|
{
|
|
apiEvents.BeginUpdate();
|
|
apiEvents.Nodes.Clear();
|
|
|
|
Regex rgxopen = new Regex("^\\s*{");
|
|
Regex rgxclose = new Regex("^\\s*}");
|
|
|
|
FetchDrawcall draw = m_Core.CurDrawcall;
|
|
|
|
if (draw != null && draw.events != null && draw.events.Length > 0)
|
|
{
|
|
foreach (var ev in draw.events)
|
|
{
|
|
// hack until I have a proper interface. Skip events associated with this draw that
|
|
// come from another context (means they will just be completely omitted/invisible).
|
|
if (ev.context != draw.context)
|
|
continue;
|
|
|
|
string[] lines = ev.eventDesc.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
|
|
|
|
TreelistView.Node root = new TreelistView.Node(new object[] { ev.eventID, lines[0] });
|
|
|
|
int i=1;
|
|
|
|
if (i < lines.Length && lines[i].Trim() == "{")
|
|
i++;
|
|
|
|
List<TreelistView.Node> nodestack = new List<TreelistView.Node>();
|
|
nodestack.Add(root);
|
|
|
|
for (; i < lines.Length; i++)
|
|
{
|
|
if (rgxopen.IsMatch(lines[i]))
|
|
nodestack.Add(nodestack.Last().Nodes.LastNode);
|
|
else if (rgxclose.IsMatch(lines[i]))
|
|
nodestack.RemoveAt(nodestack.Count - 1);
|
|
else if(lines[i].Trim().Length > 0 && nodestack.Count > 0)
|
|
nodestack.Last().Nodes.Add(new TreelistView.Node(new object[] { "", lines[i].Trim() }));
|
|
}
|
|
|
|
if (ev.eventID == draw.eventID)
|
|
root.Bold = true;
|
|
|
|
root.Tag = (object)ev;
|
|
|
|
apiEvents.Nodes.Add(root);
|
|
}
|
|
|
|
if (apiEvents.Nodes.Count > 0)
|
|
apiEvents.NodesSelection.Add(apiEvents.Nodes[0]);
|
|
}
|
|
|
|
apiEvents.EndUpdate();
|
|
}
|
|
|
|
public void OnEventSelected(UInt32 frameID, UInt32 eventID)
|
|
{
|
|
FillAPIView();
|
|
|
|
apiEvents.NodesSelection.Clear();
|
|
apiEvents.FocusedNode = apiEvents.Nodes.LastNode;
|
|
}
|
|
|
|
private void AddCallstack(String[] calls)
|
|
{
|
|
if (callstack.InvokeRequired)
|
|
{
|
|
this.BeginInvoke(new Action(() =>
|
|
{
|
|
AddCallstack(calls);
|
|
}));
|
|
return;
|
|
}
|
|
|
|
/*
|
|
String commonRoot = calls[0];
|
|
|
|
for (int i = 1; i < calls.Length - m_Core.Config.CallstackLevelSkip; i++)
|
|
{
|
|
int len = Math.Min(commonRoot.Length, calls[i].Length);
|
|
|
|
int commonLen = 0;
|
|
for (;commonLen < len; commonLen++)
|
|
{
|
|
if (commonRoot[commonLen] != calls[i][commonLen])
|
|
break;
|
|
}
|
|
|
|
if (commonLen == 0)
|
|
{
|
|
commonRoot = "";
|
|
break;
|
|
}
|
|
|
|
commonRoot = commonRoot.Substring(0, commonLen);
|
|
}
|
|
*/
|
|
|
|
callstack.Items.Clear();
|
|
|
|
if (calls.Length == 1 && calls[0].Length == 0)
|
|
{
|
|
callstack.Items.Add("Symbols not loaded. Tools -> Resolve Symbols.");
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < calls.Length - m_Core.Config.CallstackLevelSkip; i++)
|
|
{
|
|
//callstack.Items.Add(calls[i].Substring(commonRoot.Length));
|
|
callstack.Items.Add(calls[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
|
|
{
|
|
if (IsDisposed || apiEvents.IsDisposed)
|
|
return;
|
|
|
|
FillCallstack();
|
|
}
|
|
|
|
public void FillCallstack()
|
|
{
|
|
if(apiEvents.SelectedNode == null)
|
|
return;
|
|
|
|
FetchAPIEvent ev = (FetchAPIEvent)apiEvents.SelectedNode.Tag;
|
|
|
|
if(ev == null)
|
|
ev = (FetchAPIEvent)apiEvents.SelectedNode.Parent.Tag;
|
|
|
|
if (ev == null)
|
|
return;
|
|
|
|
if (ev.callstack != null && ev.callstack.Length > 0)
|
|
{
|
|
m_Core.Renderer.BeginInvoke((ReplayRenderer r) => { AddCallstack(r.GetResolve(ev.callstack)); });
|
|
}
|
|
else
|
|
{
|
|
callstack.Items.Clear();
|
|
callstack.Items.Add("No Callstack available.");
|
|
}
|
|
}
|
|
|
|
private void APIEvents_Shown(object sender, EventArgs e)
|
|
{
|
|
if (m_Core.LogLoaded)
|
|
OnLogfileLoaded();
|
|
|
|
panelSplitter.Collapsed = true;
|
|
}
|
|
|
|
private void UpdateSettings()
|
|
{
|
|
bool changed = false;
|
|
|
|
if (int.TryParse(callSkip.Text, out m_Core.Config.CallstackLevelSkip))
|
|
{
|
|
if (m_Core.Config.CallstackLevelSkip < 0)
|
|
m_Core.Config.CallstackLevelSkip = 0;
|
|
callSkip.Text = m_Core.Config.CallstackLevelSkip.ToString();
|
|
changed = true;
|
|
}
|
|
|
|
if (changed)
|
|
FillCallstack();
|
|
}
|
|
|
|
private void callstack_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Right)
|
|
contextMenu.Show(callstack.PointToScreen(e.Location));
|
|
|
|
if (e.Button == MouseButtons.Left && contextMenu.Visible)
|
|
UpdateSettings();
|
|
}
|
|
|
|
private void callSkip_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (e.KeyChar == '\r' || e.KeyChar == '\n')
|
|
{
|
|
UpdateSettings();
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void dirSkip_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
if (e.KeyChar == '\r' || e.KeyChar == '\n')
|
|
{
|
|
UpdateSettings();
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
|
|
private void apiEvents_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (!m_Core.LogLoaded) return;
|
|
|
|
if (e.KeyCode == Keys.C && e.Control)
|
|
{
|
|
string text = "";
|
|
foreach (var n in apiEvents.NodesSelection)
|
|
{
|
|
text += string.Format("{0,-5} {1}" + Environment.NewLine, n[0].ToString(), n[1].ToString());
|
|
}
|
|
|
|
try
|
|
{
|
|
if (text.Length > 0)
|
|
Clipboard.SetText(text);
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
try
|
|
{
|
|
if (text.Length > 0)
|
|
Clipboard.SetDataObject(text);
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
// give up!
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void callstack_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (!m_Core.LogLoaded) return;
|
|
|
|
if (e.KeyCode == Keys.C && e.Control)
|
|
{
|
|
string text = "";
|
|
foreach (var n in callstack.SelectedItems)
|
|
{
|
|
text += n.ToString() + Environment.NewLine;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (text.Length > 0)
|
|
Clipboard.SetText(text);
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
try
|
|
{
|
|
if (text.Length > 0)
|
|
Clipboard.SetDataObject(text);
|
|
}
|
|
catch (System.Exception)
|
|
{
|
|
// give up!
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void callstacklabel_DoubleClick(object sender, EventArgs e)
|
|
{
|
|
panelSplitter.Collapsed = !panelSplitter.Collapsed;
|
|
}
|
|
|
|
private void APIInspector_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
m_Core.RemoveLogViewer(this);
|
|
}
|
|
}
|
|
}
|