Files
renderdoc/renderdocui/Windows/DebugMessages.cs
T
baldurk 04f1d4a378 Centralise debug message processing, and allow adding custom warnings
* This will allow the adding of things like 'redundant api call' for calls
  that have no effect, as well as potential problems like drawing with an
  empty viewport, or similar things that are common problems. Reading out-
  of-bounds on buffers etc is a good example of 'defined' behaviour that
  is probably not desired.
* These heuristics could also identify potential performance problems.
* It also supports adding debug messages after log-load time, so you could
  do an additional extra-strength pass, or do a detailed check of one
  draw call (e.g. a broken draw, to try and figure out the problem). If
  there are any unread debug messages, the status bar will flash and the
  debug messages window will show a count as (N).
2015-01-11 00:20:50 +00:00

335 lines
10 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 WeifenLuo.WinFormsUI.Docking;
using renderdocui.Code;
using renderdoc;
namespace renderdocui.Windows
{
public partial class DebugMessages : DockContent, ILogViewerForm
{
private Core m_Core;
List<int> m_VisibleMessages = new List<int>();
int m_NumMessages = 0;
public DebugMessages(Core core)
{
InitializeComponent();
Icon = global::renderdocui.Properties.Resources.icon;
m_Core = core;
RefreshMessageList();
}
public void OnLogfileClosed()
{
m_VisibleMessages.Clear();
m_NumMessages = 0;
messages.RowCount = 0;
RefreshMessageList();
}
public void OnLogfileLoaded()
{
m_VisibleMessages.Clear();
m_NumMessages = 0;
messages.RowCount = 0;
messages.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
RefreshMessageList();
}
public void OnEventSelected(UInt32 frameID, UInt32 eventID)
{
}
private void DebugMessages_Shown(object sender, EventArgs e)
{
if (m_Core.LogLoaded)
OnLogfileLoaded();
}
private void messages_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < m_VisibleMessages.Count)
m_Core.SetEventID(null, 0, m_Core.DebugMessages[m_VisibleMessages[e.RowIndex]].eventID);
}
private bool m_SuppressRefresh = false;
public void RefreshMessageList()
{
if (m_SuppressRefresh) return;
// add any new messages as default visible
for (int i = m_NumMessages; i < m_Core.DebugMessages.Count; i++)
m_VisibleMessages.Add(i);
m_NumMessages = m_Core.DebugMessages.Count;
if (displayHidden.Checked)
{
messages.RowCount = 0;
messages.RowCount = m_Core.DebugMessages.Count;
}
else
{
messages.RowCount = 0;
messages.RowCount = m_VisibleMessages.Count;
}
if (m_Core.UnreadMessageCount > 0)
Text = String.Format("({0}) Errors and Warnings", m_Core.UnreadMessageCount);
else
Text = "Errors and Warnings";
}
bool IsRowVisible(int row)
{
return m_VisibleMessages.Contains(row);
}
void ShowRow(int row)
{
if (!IsRowVisible(row))
{
m_VisibleMessages.Add(row);
m_VisibleMessages.Sort();
RefreshMessageList();
}
}
void HideRow(int row)
{
if (IsRowVisible(row))
{
m_VisibleMessages.Remove(row);
RefreshMessageList();
}
}
void ToggleRow(int row)
{
if (IsRowVisible(row))
{
HideRow(row);
}
else
{
ShowRow(row);
}
}
private void displayHidden_CheckedChanged(object sender, EventArgs e)
{
RefreshMessageList();
}
int GetMessageIndex(int rowIndex)
{
if (displayHidden.Checked)
return rowIndex;
if (rowIndex < 0 || rowIndex >= m_VisibleMessages.Count)
return -1;
return m_VisibleMessages[rowIndex];
}
private void hideIndividual_Click(object sender, EventArgs e)
{
if (messages.SelectedRows.Count > 0)
{
m_SuppressRefresh = true;
foreach (DataGridViewRow row in messages.SelectedRows)
{
ToggleRow(GetMessageIndex(row.Index));
}
m_SuppressRefresh = false;
RefreshMessageList();
}
messages.ClearSelection();
}
private void hideType_Click(object sender, EventArgs e)
{
if (messages.SelectedRows.Count == 1)
{
DataGridViewRow typerow = messages.SelectedRows[0];
int msgIdx = GetMessageIndex(typerow.Index);
DebugMessage msg = m_Core.DebugMessages[msgIdx];
bool hiderows = IsRowVisible(msgIdx);
m_SuppressRefresh = true;
for(int i=0; i < m_Core.DebugMessages.Count; i++)
{
var message = m_Core.DebugMessages[i];
if (message.category == msg.category &&
message.severity == msg.severity &&
message.messageID == msg.messageID)
{
if (hiderows)
HideRow(i);
else
ShowRow(i);
}
}
m_SuppressRefresh = false;
RefreshMessageList();
messages.ClearSelection();
}
}
private void hideSource_Click(object sender, EventArgs e)
{
if (messages.SelectedRows.Count == 1)
{
DataGridViewRow typerow = messages.SelectedRows[0];
int msgIdx = GetMessageIndex(typerow.Index);
DebugMessage msg = m_Core.DebugMessages[msgIdx];
bool hiderows = IsRowVisible(msgIdx);
m_SuppressRefresh = true;
for (int i = 0; i < m_Core.DebugMessages.Count; i++)
{
var message = m_Core.DebugMessages[i];
if (message.source == msg.source)
{
if (hiderows)
HideRow(i);
else
ShowRow(i);
}
}
m_SuppressRefresh = false;
RefreshMessageList();
messages.ClearSelection();
}
}
private void rightClickMenu_Opening(object sender, CancelEventArgs e)
{
hideType.Enabled = (messages.SelectedRows.Count == 1);
}
private void messages_MouseDown(object sender, MouseEventArgs e)
{
if (messages.SelectedRows.Count == 0 && e.Button == MouseButtons.Right)
{
var hti = messages.HitTest(e.X, e.Y);
if(hti.RowIndex >= 0 && hti.RowIndex < messages.RowCount)
messages.Rows[hti.RowIndex].Selected = true;
}
if (e.Button == MouseButtons.Left)
{
var hti = messages.HitTest(e.X, e.Y);
if (hti.RowIndex < 0 || hti.RowIndex >= messages.RowCount)
messages.ClearSelection();
}
}
private void messages_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
int msgIdx = GetMessageIndex(e.RowIndex);
if (e.ColumnIndex < 0 || e.ColumnIndex >= messages.ColumnCount) return;
if (msgIdx < 0 || msgIdx >= m_Core.DebugMessages.Count) return;
if (e.ColumnIndex == 0) e.Value = m_Core.DebugMessages[msgIdx].eventID;
if (e.ColumnIndex == 1) e.Value = m_Core.DebugMessages[msgIdx].source.Str();
if (e.ColumnIndex == 2) e.Value = m_Core.DebugMessages[msgIdx].severity.ToString();
if (e.ColumnIndex == 3) e.Value = m_Core.DebugMessages[msgIdx].category.ToString();
if (e.ColumnIndex == 4) e.Value = m_Core.DebugMessages[msgIdx].messageID.ToString();
if (e.ColumnIndex == 5) e.Value = m_Core.DebugMessages[msgIdx].description;
}
private void messages_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
int msgIdx = GetMessageIndex(e.RowIndex);
if (e.ColumnIndex < 0 || e.ColumnIndex >= messages.ColumnCount) return;
if (msgIdx < 0 || msgIdx >= m_Core.DebugMessages.Count) return;
if (!IsRowVisible(msgIdx))
e.CellStyle.BackColor = Color.Salmon;
else if (m_Core.DebugMessages[msgIdx].source == DebugMessageSource.RuntimeWarning)
e.CellStyle.BackColor = Color.Aquamarine;
}
private void DebugMessages_FormClosed(object sender, FormClosedEventArgs e)
{
m_Core.RemoveLogViewer(this);
}
private void messages_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
// use BeginInvoke so we don't resize the messages mid-paint
this.BeginInvoke(new Action(() =>
{
if (m_Core.UnreadMessageCount > 0)
{
m_Core.UnreadMessageCount = 0;
RefreshMessageList();
}
}));
}
}
}