Add (semi-experimental) highlight & info for non-trivial resource views

* For D3D11 and Vulkan, any views which don't just map to the whole
  buffer or image will be highlighted in a colour, and when mousing over
  that row a small tooltip will be displayed with the view parameters
  that differ.
This commit is contained in:
baldurk
2016-06-24 16:32:32 +02:00
parent 27bbbc39a4
commit 377e07374b
4 changed files with 494 additions and 87 deletions
@@ -351,6 +351,7 @@
this.scissorEnable = new System.Windows.Forms.PictureBox();
this.lineAAEnable = new System.Windows.Forms.PictureBox();
this.label23 = new System.Windows.Forms.Label();
this.conservativeRaster = new System.Windows.Forms.PictureBox();
this.groupBox32 = new System.Windows.Forms.GroupBox();
this.viewports = new TreelistView.TreeListView();
this.scissors = new TreelistView.TreeListView();
@@ -441,7 +442,6 @@
this.showEmpty = new System.Windows.Forms.ToolStripMenuItem();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.exportDialog = new System.Windows.Forms.SaveFileDialog();
this.conservativeRaster = new System.Windows.Forms.PictureBox();
toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
toolstripTable = new System.Windows.Forms.TableLayoutPanel();
groupBox2 = new System.Windows.Forms.GroupBox();
@@ -453,8 +453,8 @@
label15 = new System.Windows.Forms.Label();
label16 = new System.Windows.Forms.Label();
label17 = new System.Windows.Forms.Label();
groupBox42 = new System.Windows.Forms.GroupBox();
label25 = new System.Windows.Forms.Label();
groupBox42 = new System.Windows.Forms.GroupBox();
toolstripTable.SuspendLayout();
this.flowLayoutPanel6.SuspendLayout();
this.toolStrip1.SuspendLayout();
@@ -546,6 +546,7 @@
((System.ComponentModel.ISupportInitialize)(this.multisampleEnable)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.scissorEnable)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.lineAAEnable)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.conservativeRaster)).BeginInit();
this.groupBox32.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.viewports)).BeginInit();
groupBox42.SuspendLayout();
@@ -605,7 +606,6 @@
this.groupBox36.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.csCBuffers)).BeginInit();
this.rightclickMenu.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.conservativeRaster)).BeginInit();
this.SuspendLayout();
//
// toolStripLabel1
@@ -1253,6 +1253,8 @@
this.vsResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.vsResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.vsResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.vsResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.vsResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox8
//
@@ -1574,6 +1576,8 @@
this.hsResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.hsResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.hsResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.hsResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.hsResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox14
//
@@ -1895,6 +1899,8 @@
this.dsResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.dsResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.dsResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.dsResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.dsResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox20
//
@@ -2265,6 +2271,8 @@
this.gsResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.gsResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.gsResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.gsResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.gsResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox25
//
@@ -2435,7 +2443,7 @@
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 608F));
this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 610F));
this.tableLayoutPanel8.Controls.Add(this.forcedSampleCount, 7, 1);
this.tableLayoutPanel8.Controls.Add(this.label14, 6, 1);
this.tableLayoutPanel8.Controls.Add(this.frontCCW, 5, 0);
@@ -2479,7 +2487,7 @@
this.forcedSampleCount.Font = new System.Drawing.Font("Tahoma", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.forcedSampleCount.Location = new System.Drawing.Point(539, 28);
this.forcedSampleCount.Name = "forcedSampleCount";
this.forcedSampleCount.Size = new System.Drawing.Size(18, 19);
this.forcedSampleCount.Size = new System.Drawing.Size(32, 19);
this.forcedSampleCount.TabIndex = 24;
this.forcedSampleCount.Text = "0";
this.forcedSampleCount.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
@@ -2710,6 +2718,27 @@
this.label23.TabIndex = 12;
this.label23.Text = "Line AA:";
//
// label25
//
label25.Anchor = System.Windows.Forms.AnchorStyles.Right;
label25.AutoSize = true;
label25.Location = new System.Drawing.Point(426, 6);
label25.Name = "label25";
label25.Size = new System.Drawing.Size(106, 13);
label25.TabIndex = 25;
label25.Text = "Conservative Raster:";
//
// conservativeRaster
//
this.conservativeRaster.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.conservativeRaster.Image = ((System.Drawing.Image)(resources.GetObject("conservativeRaster.Image")));
this.conservativeRaster.Location = new System.Drawing.Point(539, 5);
this.conservativeRaster.Name = "conservativeRaster";
this.conservativeRaster.Size = new System.Drawing.Size(32, 16);
this.conservativeRaster.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.conservativeRaster.TabIndex = 26;
this.conservativeRaster.TabStop = false;
//
// groupBox32
//
this.groupBox32.Controls.Add(this.viewports);
@@ -3026,6 +3055,8 @@
this.psResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.psResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.psResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.psResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.psResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox29
//
@@ -3233,6 +3264,8 @@
this.targetOutputs.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.targetOutputs.Leave += new System.EventHandler(this.disableSelection_Leave);
this.targetOutputs.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.targetOutputs.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.targetOutputs.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox37
//
@@ -3834,6 +3867,8 @@
this.csUAVs.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.csUAVs.Leave += new System.EventHandler(this.disableSelection_Leave);
this.csUAVs.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.csUAVs.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.csUAVs.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox27
//
@@ -4111,6 +4146,8 @@
this.csResources.KeyDown += new System.Windows.Forms.KeyEventHandler(this.defaultCopyPaste_KeyDown);
this.csResources.Leave += new System.EventHandler(this.disableSelection_Leave);
this.csResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.hideDisabledEmpty_MouseClick);
this.csResources.MouseLeave += new System.EventHandler(this.textureCell_MouseLeave);
this.csResources.MouseMove += new System.Windows.Forms.MouseEventHandler(this.textureCell_MouseMove);
//
// groupBox35
//
@@ -4238,33 +4275,17 @@
this.showEmpty.Text = "Show Empty";
this.showEmpty.Click += new System.EventHandler(this.hideEmpty_Click);
//
// toolTip
//
this.toolTip.UseAnimation = false;
this.toolTip.UseFading = false;
//
// exportDialog
//
this.exportDialog.DefaultExt = "html";
this.exportDialog.Filter = "HTML Files (*.html)|*.html";
this.exportDialog.Title = "Export pipeline state as HTML";
//
// label25
//
label25.Anchor = System.Windows.Forms.AnchorStyles.Right;
label25.AutoSize = true;
label25.Location = new System.Drawing.Point(426, 6);
label25.Name = "label25";
label25.Size = new System.Drawing.Size(106, 13);
label25.TabIndex = 25;
label25.Text = "Conservative Raster:";
//
// conservativeRaster
//
this.conservativeRaster.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.conservativeRaster.Image = ((System.Drawing.Image)(resources.GetObject("conservativeRaster.Image")));
this.conservativeRaster.Location = new System.Drawing.Point(539, 5);
this.conservativeRaster.Name = "conservativeRaster";
this.conservativeRaster.Size = new System.Drawing.Size(32, 16);
this.conservativeRaster.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.conservativeRaster.TabIndex = 26;
this.conservativeRaster.TabStop = false;
//
// D3D11PipelineStateViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -4374,6 +4395,7 @@
((System.ComponentModel.ISupportInitialize)(this.multisampleEnable)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.scissorEnable)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.lineAAEnable)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.conservativeRaster)).EndInit();
this.groupBox32.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.viewports)).EndInit();
groupBox42.ResumeLayout(false);
@@ -4443,7 +4465,6 @@
this.groupBox36.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.csCBuffers)).EndInit();
this.rightclickMenu.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.conservativeRaster)).EndInit();
this.ResumeLayout(false);
}
@@ -48,6 +48,11 @@ namespace renderdocui.Windows.PipelineState
// keep track of the VB nodes (we want to be able to highlight them easily on hover)
private List<TreelistView.Node> m_VBNodes = new List<TreelistView.Node>();
// keep track of resource nodes that need view details
private List<TreelistView.Node> m_ViewDetailNodes = new List<TreelistView.Node>();
TreelistView.Node m_CurViewDetailNode = null;
private struct IABufferTag
{
public IABufferTag(ResourceId i, ulong offs)
@@ -60,6 +65,30 @@ namespace renderdocui.Windows.PipelineState
public ulong offset;
};
private class ViewTexTag
{
public ViewTexTag(D3D11PipelineState.ShaderStage.ResourceView v, FetchTexture t)
{
view = v;
tex = t;
}
public D3D11PipelineState.ShaderStage.ResourceView view;
public FetchTexture tex;
};
private class ViewBufTag
{
public ViewBufTag(D3D11PipelineState.ShaderStage.ResourceView v, FetchBuffer b)
{
view = v;
buf = b;
}
public D3D11PipelineState.ShaderStage.ResourceView view;
public FetchBuffer buf;
};
public D3D11PipelineStateViewer(Core core, DockContent c)
{
InitializeComponent();
@@ -135,6 +164,9 @@ namespace renderdocui.Windows.PipelineState
public void OnLogfileClosed()
{
HideViewDetailsTooltip();
m_ViewDetailNodes.Clear();
inputLayouts.Nodes.Clear();
iabuffers.Nodes.Clear();
topology.Text = "";
@@ -211,6 +243,34 @@ namespace renderdocui.Windows.PipelineState
node.Italic = true;
}
private void ViewDetailsRow(TreelistView.Node node)
{
node.BackColor = Color.Aquamarine;
m_ViewDetailNodes.Add(node);
}
private bool HasImportantViewParams(D3D11PipelineState.ShaderStage.ResourceView view, FetchTexture tex)
{
// we don't count 'upgrade typeless to typed' as important, we just display the typed format
// in the row since there's no real hidden important information there. The formats can't be
// different for any other reason (if the SRV format differs from the texture format, the
// texture must have been typeless.
if (view.HighestMip > 0 || view.FirstArraySlice > 0 ||
(view.NumMipLevels < tex.mips && tex.mips > 1) ||
(view.ArraySize < tex.arraysize && tex.arraysize > 1))
return true;
return false;
}
private bool HasImportantViewParams(D3D11PipelineState.ShaderStage.ResourceView view, FetchBuffer buf)
{
if (view.FirstElement > 0 || view.NumElements*view.ElementSize < buf.byteSize)
return true;
return false;
}
private void ClearShaderState(Label shader, TreelistView.TreeListView resources, TreelistView.TreeListView samplers,
TreelistView.TreeListView cbuffers, TreelistView.TreeListView classes)
{
@@ -291,6 +351,7 @@ namespace renderdocui.Windows.PipelineState
string name = "Shader Resource " + r.Resource.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (!filledSlot)
{
@@ -322,10 +383,13 @@ namespace renderdocui.Windows.PipelineState
// if it's a typeless format, show the format of the view
if (texs[t].format.compType == FormatComponentType.None)
{
format = r.Format.ToString();
format = "Viewed as " + r.Format.ToString();
}
tag = texs[t];
tag = new ViewTexTag(r, texs[t]);
if (HasImportantViewParams(r, texs[t]))
viewDetails = true;
}
}
@@ -373,7 +437,10 @@ namespace renderdocui.Windows.PipelineState
}
}
tag = bufs[t];
tag = new ViewBufTag(r, bufs[t]);
if (HasImportantViewParams(r, bufs[t]))
viewDetails = true;
}
}
@@ -388,6 +455,9 @@ namespace renderdocui.Windows.PipelineState
if (!usedSlot)
InactiveRow(node);
if (viewDetails)
ViewDetailsRow(node);
}
i++;
}
@@ -647,6 +717,9 @@ namespace renderdocui.Windows.PipelineState
D3D11PipelineState state = m_Core.CurD3D11PipelineState;
FetchDrawcall draw = m_Core.CurDrawcall;
HideViewDetailsTooltip();
m_ViewDetailNodes.Clear();
var tick = global::renderdocui.Properties.Resources.tick;
var cross = global::renderdocui.Properties.Resources.cross;
@@ -1005,6 +1078,7 @@ namespace renderdocui.Windows.PipelineState
string name = "UAV " + r.Resource.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (!filledSlot)
{
@@ -1035,10 +1109,13 @@ namespace renderdocui.Windows.PipelineState
// if it's a typeless format, show the format of the view
if (texs[t].format.compType == FormatComponentType.None)
{
format = r.Format.ToString();
format = "Viewed as " + r.Format.ToString();
}
tag = texs[t];
if (HasImportantViewParams(r, texs[t]))
viewDetails = true;
tag = new ViewTexTag(r, texs[t]);
}
}
@@ -1083,7 +1160,10 @@ namespace renderdocui.Windows.PipelineState
}
}
tag = bufs[t];
if (HasImportantViewParams(r, bufs[t]))
viewDetails = true;
tag = new ViewBufTag(r, bufs[t]);
}
}
@@ -1099,6 +1179,9 @@ namespace renderdocui.Windows.PipelineState
if (!usedSlot)
InactiveRow(node);
if (viewDetails)
ViewDetailsRow(node);
}
i++;
@@ -1268,6 +1351,7 @@ namespace renderdocui.Windows.PipelineState
string name = "Texture " + p.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (p.Resource == ResourceId.Null)
{
@@ -1298,10 +1382,13 @@ namespace renderdocui.Windows.PipelineState
// if it's a typeless format, show the format of the view
if (texs[t].format.compType == FormatComponentType.None)
{
format = p.Format.ToString();
format = "Viewed as " + p.Format.ToString();
}
tag = texs[t];
if (HasImportantViewParams(p, texs[t]))
viewDetails = true;
tag = new ViewTexTag(p, texs[t]);
}
}
@@ -1318,6 +1405,9 @@ namespace renderdocui.Windows.PipelineState
else
{
targets[i] = true;
if (viewDetails)
ViewDetailsRow(node);
}
}
@@ -1360,6 +1450,7 @@ namespace renderdocui.Windows.PipelineState
string name = "UAV " + r.Resource.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (!filledSlot)
{
@@ -1390,10 +1481,13 @@ namespace renderdocui.Windows.PipelineState
// if it's a typeless format, show the format of the view
if (texs[t].format.compType == FormatComponentType.None)
{
format = r.Format.ToString();
format = "Viewed as " + r.Format.ToString();
}
tag = texs[t];
if (HasImportantViewParams(r, texs[t]))
viewDetails = true;
tag = new ViewTexTag(r, texs[t]);
}
}
@@ -1438,7 +1532,10 @@ namespace renderdocui.Windows.PipelineState
}
}
tag = bufs[t];
if (HasImportantViewParams(r, bufs[t]))
viewDetails = true;
tag = new ViewBufTag(r, bufs[t]);
}
}
@@ -1450,6 +1547,9 @@ namespace renderdocui.Windows.PipelineState
if (r.Resource == ResourceId.Null)
EmptyRow(node);
if (viewDetails)
ViewDetailsRow(node);
}
i++;
@@ -1464,6 +1564,7 @@ namespace renderdocui.Windows.PipelineState
string name = "Depth Target " + state.m_OM.DepthTarget.Resource.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (state.m_OM.DepthTarget.Resource == ResourceId.Null)
{
@@ -1494,10 +1595,13 @@ namespace renderdocui.Windows.PipelineState
// if it's a typeless format, show the format of the view
if (texs[t].format.compType == FormatComponentType.None)
{
format = state.m_OM.DepthTarget.Format.ToString();
format = "Viewed as " + state.m_OM.DepthTarget.Format.ToString();
}
tag = texs[t];
if (HasImportantViewParams(state.m_OM.DepthTarget, texs[t]))
viewDetails = true;
tag = new ViewTexTag(state.m_OM.DepthTarget, texs[t]);
}
}
@@ -1507,6 +1611,9 @@ namespace renderdocui.Windows.PipelineState
node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
node.Tag = tag;
if (viewDetails)
ViewDetailsRow(node);
if (state.m_OM.DepthTarget.Resource == ResourceId.Null)
EmptyRow(node);
}
@@ -1652,6 +1759,96 @@ namespace renderdocui.Windows.PipelineState
UpdateState();
}
private void HideViewDetailsTooltip()
{
if (m_CurViewDetailNode != null)
toolTip.Hide(m_CurViewDetailNode.OwnerView);
m_CurViewDetailNode = null;
}
private void textureCell_MouseLeave(object sender, EventArgs e)
{
HideViewDetailsTooltip();
}
private void textureCell_MouseMove(object sender, MouseEventArgs e)
{
TreelistView.TreeListView view = sender as TreelistView.TreeListView;
if (view == null)
{
HideViewDetailsTooltip();
return;
}
TreelistView.Node node = view.GetHitNode();
if (node == null)
{
HideViewDetailsTooltip();
return;
}
if (m_ViewDetailNodes.Contains(node))
{
if (node != m_CurViewDetailNode)
{
// round y up to the next row
int y = (e.Location.Y - view.Columns.Options.HeaderHeight) / view.RowOptions.ItemHeight;
y = view.Columns.Options.HeaderHeight + (y + 1) * view.RowOptions.ItemHeight;
string text = "";
ViewTexTag tex = (node.Tag as ViewTexTag);
ViewBufTag buf = (node.Tag as ViewBufTag);
if (tex != null)
{
if (tex.tex.format != tex.view.Format)
text += String.Format("The texture is format {0}, the view treats it as {1}.\n",
tex.tex.format, tex.view.Format);
if (tex.tex.mips > 1 && (tex.tex.mips != tex.view.NumMipLevels || tex.view.HighestMip > 0))
{
if (tex.view.NumMipLevels == 1)
text += String.Format("The texture has {0} mips, the view covers mip {1}.\n",
tex.tex.mips, tex.view.HighestMip, tex.view.HighestMip);
else
text += String.Format("The texture has {0} mips, the view covers mips {1}-{2}.\n",
tex.tex.mips, tex.view.HighestMip, tex.view.HighestMip + tex.view.NumMipLevels - 1);
}
if (tex.tex.arraysize > 1 && (tex.tex.arraysize != tex.view.ArraySize || tex.view.FirstArraySlice > 0))
{
if (tex.view.ArraySize == 1)
text += String.Format("The texture has {0} array slices, the view covers slice {1}.\n",
tex.tex.arraysize, tex.view.FirstArraySlice, tex.view.FirstArraySlice);
else
text += String.Format("The texture has {0} array slices, the view covers slices {1}-{2}.\n",
tex.tex.arraysize, tex.view.FirstArraySlice, tex.view.FirstArraySlice + tex.view.ArraySize);
}
}
else if (buf != null)
{
text += String.Format("The view covers bytes {0}-{1} ({2} elements).\nThe buffer is {3} bytes in length ({4} elements).",
buf.view.FirstElement * buf.view.ElementSize,
(buf.view.FirstElement + buf.view.NumElements) * buf.view.ElementSize,
buf.view.NumElements,
buf.buf.byteSize,
buf.buf.byteSize / buf.view.ElementSize);
}
toolTip.Show(text.TrimEnd(), view, e.Location.X + Cursor.Size.Width, y);
m_CurViewDetailNode = node;
}
}
else
{
HideViewDetailsTooltip();
}
}
// launch the appropriate kind of viewer, depending on the type of resource that's in this node
private void textureCell_CellDoubleClick(TreelistView.Node node)
{
@@ -1661,6 +1858,19 @@ namespace renderdocui.Windows.PipelineState
if (stage == null) return;
D3D11PipelineState.ShaderStage.ResourceView view = null;
if (tag is ViewTexTag)
{
view = (tag as ViewTexTag).view;
tag = (tag as ViewTexTag).tex;
}
if (tag is ViewBufTag)
{
view = (tag as ViewBufTag).view;
tag = (tag as ViewBufTag).buf;
}
if (tag is FetchTexture)
{
FetchTexture tex = (FetchTexture)tag;
@@ -1668,7 +1878,7 @@ namespace renderdocui.Windows.PipelineState
if (tex.resType == ShaderResourceType.Buffer)
{
var viewer = new BufferViewer(m_Core, false);
viewer.ViewRawBuffer(false, 0, ulong.MaxValue, tex.ID);
viewer.ViewRawBuffer(false, view.FirstElement, view.NumElements*view.ElementSize, tex.ID);
viewer.Show(m_DockContent.DockPanel);
}
else
@@ -1682,7 +1892,6 @@ namespace renderdocui.Windows.PipelineState
else if(tag is FetchBuffer)
{
FetchBuffer buf = (FetchBuffer)tag;
D3D11PipelineState.ShaderStage.ResourceView view = null;
string format = "";
@@ -3359,6 +3359,11 @@
this.showEmpty.Text = "Show Empty";
this.showEmpty.Click += new System.EventHandler(this.hideEmpty_Click);
//
// toolTip
//
this.toolTip.UseAnimation = false;
this.toolTip.UseFading = false;
//
// exportDialog
//
this.exportDialog.DefaultExt = "html";
@@ -49,6 +49,11 @@ namespace renderdocui.Windows.PipelineState
private List<TreelistView.Node> m_VBNodes = new List<TreelistView.Node>();
private List<TreelistView.Node> m_BindNodes = new List<TreelistView.Node>();
// keep track of resource nodes that need view details
private List<TreelistView.Node> m_ViewDetailNodes = new List<TreelistView.Node>();
TreelistView.Node m_CurViewDetailNode = null;
private struct IABufferTag
{
public IABufferTag(ResourceId i, ulong offs)
@@ -86,6 +91,26 @@ namespace renderdocui.Windows.PipelineState
public ulong size;
};
private class ViewTexTag
{
public ViewTexTag(ResourceFormat f, UInt32 bm, UInt32 bl, UInt32 nm, UInt32 nl, FetchTexture t)
{
fmt = f;
baseMip = bm;
baseLayer = bl;
numMip = nm;
numLayer = nl;
tex = t;
}
public ResourceFormat fmt;
public UInt32 baseMip;
public UInt32 baseLayer;
public UInt32 numMip;
public UInt32 numLayer;
public FetchTexture tex;
};
private Dictionary<TreelistView.Node, TreelistView.Node> m_CombinedImageSamplers = new Dictionary<TreelistView.Node, TreelistView.Node>();
public VulkanPipelineStateViewer(Core core, DockContent c)
@@ -157,6 +182,9 @@ namespace renderdocui.Windows.PipelineState
public void OnLogfileClosed()
{
HideViewDetailsTooltip();
m_ViewDetailNodes.Clear();
viAttrs.Nodes.Clear();
viBuffers.Nodes.Clear();
topology.Text = "";
@@ -225,6 +253,47 @@ namespace renderdocui.Windows.PipelineState
node.Italic = true;
}
private void ViewDetailsRow(TreelistView.Node node)
{
node.BackColor = Color.Aquamarine;
m_ViewDetailNodes.Add(node);
}
private bool HasImportantViewParams(VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement view, FetchTexture tex)
{
// Since mutable formats are more unclear in vulkan (it allows casting between any
// similar format, and the underlying texture still has a valid format), we consider
// a format difference to be important even though we display the view's format in
// the row data itself
if (view.viewfmt != tex.format ||
view.baseMip > 0 || view.baseLayer > 0 ||
(view.numMip < tex.mips && tex.mips > 1) ||
(view.numLayer < tex.arraysize && tex.arraysize > 1))
return true;
return false;
}
private bool HasImportantViewParams(VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement view, FetchBuffer buf)
{
if (view.offset > 0 || view.size < buf.byteSize)
return true;
return false;
}
private bool HasImportantViewParams(VulkanPipelineState.CurrentPass.Framebuffer.Attachment att, FetchTexture tex)
{
// see above in BindingElement overload for justification for comparing formats
if (att.viewfmt != tex.format ||
att.baseMip > 0 || att.baseLayer > 0 ||
(att.numMip < tex.mips && tex.mips > 1) ||
(att.numLayer < tex.arraysize && tex.arraysize > 1))
return true;
return false;
}
private void ClearShaderState(Label shader, TreelistView.TreeListView resources,
TreelistView.TreeListView cbuffers)
{
@@ -459,6 +528,7 @@ namespace renderdocui.Windows.PipelineState
string name = "Empty";
ShaderResourceType restype = ShaderResourceType.None;
object tag = null;
bool viewDetails = false;
if (filledSlot && descriptorBind != null)
{
@@ -479,7 +549,15 @@ namespace renderdocui.Windows.PipelineState
restype = texs[t].resType;
samples = texs[t].msSamp;
tag = texs[t];
if (HasImportantViewParams(descriptorBind, texs[t]))
viewDetails = true;
tag = new ViewTexTag(
descriptorBind.viewfmt,
descriptorBind.baseMip, descriptorBind.baseLayer,
descriptorBind.numMip, descriptorBind.numLayer,
texs[t]
);
}
}
@@ -498,6 +576,9 @@ namespace renderdocui.Windows.PipelineState
tag = new BufferResTag(isrw, bindPoint, bufs[t].ID, descriptorBind.offset, descriptorBind.size);
if (HasImportantViewParams(descriptorBind, bufs[t]))
viewDetails = true;
isbuf = true;
}
}
@@ -649,6 +730,9 @@ namespace renderdocui.Windows.PipelineState
if (!usedSlot)
InactiveRow(node);
if (viewDetails)
ViewDetailsRow(node);
}
if (bindType == ShaderBindType.ImageSampler)
@@ -1470,6 +1554,7 @@ namespace renderdocui.Windows.PipelineState
string name = "Texture " + p.ToString();
string typename = "Unknown";
object tag = null;
bool viewDetails = false;
if (p.img == ResourceId.Null)
{
@@ -1503,7 +1588,10 @@ namespace renderdocui.Windows.PipelineState
}
}
tag = texs[t];
if (HasImportantViewParams(p, texs[t]))
viewDetails = true;
tag = new ViewTexTag(p.viewfmt, p.baseMip, p.baseLayer, p.numMip, p.numLayer, texs[t]);
}
}
@@ -1526,11 +1614,20 @@ namespace renderdocui.Windows.PipelineState
node.Tag = tag;
if (p.img == ResourceId.Null)
{
EmptyRow(node);
}
else if (!usedSlot)
{
InactiveRow(node);
}
else
{
targets[i] = true;
if (viewDetails)
ViewDetailsRow(node);
}
}
i++;
@@ -1692,6 +1789,117 @@ namespace renderdocui.Windows.PipelineState
UpdateState();
}
private void HideViewDetailsTooltip()
{
if (m_CurViewDetailNode != null)
toolTip.Hide(m_CurViewDetailNode.OwnerView);
m_CurViewDetailNode = null;
}
private void MakeNodesTransparent(TreelistView.TreeListView treeview)
{
foreach (var n in treeview.Nodes)
{
foreach (var n2 in n.Nodes)
n2.DefaultBackColor = Color.Transparent;
n.DefaultBackColor = Color.Transparent;
}
treeview.Invalidate();
}
private void resource_MouseLeave(object sender, EventArgs e)
{
MakeNodesTransparent((TreelistView.TreeListView)sender);
HideViewDetailsTooltip();
}
private void resource_MouseMove(object sender, MouseEventArgs e)
{
TreelistView.TreeListView treeview = (TreelistView.TreeListView)sender;
if (m_Core.CurVulkanPipelineState == null) return;
Point mousePoint = treeview.PointToClient(Cursor.Position);
var hoverNode = treeview.CalcHitNode(mousePoint);
MakeNodesTransparent(treeview);
if (hoverNode != null)
{
if (hoverNode.Tag is SamplerData)
{
SamplerData data = (SamplerData)hoverNode.Tag;
foreach (var imgnode in data.images)
imgnode.DefaultBackColor = Color.Wheat;
}
else if (m_CombinedImageSamplers.ContainsKey(hoverNode))
{
m_CombinedImageSamplers[hoverNode].DefaultBackColor = Color.LightCyan;
}
if (m_ViewDetailNodes.Contains(hoverNode))
{
if (hoverNode != m_CurViewDetailNode)
{
// round y up to the next row
int y = (e.Location.Y - treeview.Columns.Options.HeaderHeight) / treeview.RowOptions.ItemHeight;
y = treeview.Columns.Options.HeaderHeight + (y + 1) * treeview.RowOptions.ItemHeight;
string text = "";
ViewTexTag tex = (hoverNode.Tag as ViewTexTag);
BufferResTag buf = (hoverNode.Tag as BufferResTag);
if (tex != null)
{
if (tex.tex.format != tex.fmt)
text += String.Format("The texture is format {0}, the view treats it as {1}.\n",
tex.tex.format, tex.fmt);
if (tex.tex.mips > 1 && (tex.tex.mips != tex.numMip || tex.baseMip > 0))
{
if (tex.numMip == 1)
text += String.Format("The texture has {0} mips, the view covers mip {1}.\n",
tex.tex.mips, tex.baseMip);
else
text += String.Format("The texture has {0} mips, the view covers mips {1}-{2}.\n",
tex.tex.mips, tex.baseMip, tex.baseMip + tex.numMip - 1);
}
if (tex.tex.arraysize > 1 && (tex.tex.arraysize != tex.numLayer || tex.baseLayer > 0))
{
if (tex.numLayer == 1)
text += String.Format("The texture has {0} array slices, the view covers slice {1}.\n",
tex.tex.arraysize, tex.baseLayer);
else
text += String.Format("The texture has {0} array slices, the view covers slices {1}-{2}.\n",
tex.tex.arraysize, tex.baseLayer, tex.baseLayer + tex.numLayer);
}
}
else if (buf != null)
{
text += String.Format("The view covers bytes {0}-{1}.\nThe buffer is {3} bytes in length.",
buf.offset, buf.size,
m_Core.GetBuffer(buf.ID).byteSize);
}
toolTip.Show(text.TrimEnd(), treeview, e.Location.X + Cursor.Size.Width, y);
m_CurViewDetailNode = hoverNode;
}
}
else // node is not in view details list
{
HideViewDetailsTooltip();
}
}
else
{
HideViewDetailsTooltip();
}
}
// launch the appropriate kind of viewer, depending on the type of resource that's in this node
private void textureCell_CellDoubleClick(TreelistView.Node node)
{
@@ -1701,6 +1909,9 @@ namespace renderdocui.Windows.PipelineState
if (stage == null) return;
if (tag is ViewTexTag)
tag = (tag as ViewTexTag).tex;
if (tag is FetchTexture)
{
FetchTexture tex = (FetchTexture)tag;
@@ -2583,13 +2794,13 @@ namespace renderdocui.Windows.PipelineState
name = tex.name;
if (tex.mips > 1)
viewParams = String.Format("Highest Mip: {0}", descriptorBind.baseMip);
viewParams = String.Format("Mips: {0}-{1}", descriptorBind.baseMip, descriptorBind.baseMip+descriptorBind.numMip - 1);
if (tex.arraysize > 1)
{
if (viewParams.Length > 0)
viewParams += ", ";
viewParams += String.Format("First array slice: {0}", descriptorBind.baseLayer);
viewParams += String.Format("Layers: {0}-{1}", descriptorBind.baseLayer, descriptorBind.baseLayer + descriptorBind.numLayer - 1);
}
}
@@ -2943,7 +3154,7 @@ namespace renderdocui.Windows.PipelineState
rows.Add(new object[] {
i,
name, a.baseMip, a.baseArray });
name, a.baseMip, a.numMip, a.baseLayer, a.numLayer });
i++;
}
@@ -2951,7 +3162,7 @@ namespace renderdocui.Windows.PipelineState
ExportHTMLTable(writer,
new string[] {
"Slot",
"Image", "First mip", "First array slice",
"Image", "First mip", "Number of mips", "First array layer", "Number of layers",
},
rows.ToArray());
}
@@ -3193,44 +3404,5 @@ div.stage table tr td { border-right: 1px solid #AAAAAA; background-color: #EEEE
}
}
private void resource_MouseLeave(object sender, EventArgs e)
{
TreelistView.TreeListView treeview = (TreelistView.TreeListView)sender;
foreach (var n in treeview.Nodes)
{
foreach (var n2 in n.Nodes)
n2.DefaultBackColor = Color.Transparent;
n.DefaultBackColor = Color.Transparent;
}
treeview.Invalidate();
}
private void resource_MouseMove(object sender, MouseEventArgs e)
{
TreelistView.TreeListView treeview = (TreelistView.TreeListView)sender;
if (m_Core.CurVulkanPipelineState == null) return;
Point mousePoint = treeview.PointToClient(Cursor.Position);
var hoverNode = treeview.CalcHitNode(mousePoint);
resource_MouseLeave(sender, e);
if (hoverNode != null)
{
if (hoverNode.Tag is SamplerData)
{
SamplerData data = (SamplerData)hoverNode.Tag;
foreach (var imgnode in data.images)
imgnode.DefaultBackColor = Color.Wheat;
}
else if (m_CombinedImageSamplers.ContainsKey(hoverNode))
{
m_CombinedImageSamplers[hoverNode].DefaultBackColor = Color.LightCyan;
}
}
}
}
}