From 377e07374b104d2b201457009e9d7ea4e1e1f2e0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 24 Jun 2016 16:32:32 +0200 Subject: [PATCH] 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. --- .../D3D11PipelineStateViewer.Designer.cs | 75 +++-- .../PipelineState/D3D11PipelineStateViewer.cs | 239 +++++++++++++++- .../VulkanPipelineStateViewer.Designer.cs | 5 + .../VulkanPipelineStateViewer.cs | 262 +++++++++++++++--- 4 files changed, 494 insertions(+), 87 deletions(-) diff --git a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.Designer.cs b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.Designer.cs index b8ee2ecb8..7f37d4f7c 100644 --- a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.Designer.cs +++ b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.Designer.cs @@ -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); } diff --git a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs index d5fac56e5..81fd1d554 100644 --- a/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs +++ b/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs @@ -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 m_VBNodes = new List(); + // keep track of resource nodes that need view details + private List m_ViewDetailNodes = new List(); + + 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 = ""; diff --git a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.Designer.cs b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.Designer.cs index 9c2e5c957..998897aa5 100644 --- a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.Designer.cs +++ b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.Designer.cs @@ -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"; diff --git a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs index 9f628acdf..e5e80db51 100644 --- a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs +++ b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs @@ -49,6 +49,11 @@ namespace renderdocui.Windows.PipelineState private List m_VBNodes = new List(); private List m_BindNodes = new List(); + // keep track of resource nodes that need view details + private List m_ViewDetailNodes = new List(); + + 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 m_CombinedImageSamplers = new Dictionary(); 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; - } - } - } } } \ No newline at end of file