PageRenderTime 109ms CodeModel.GetById 471ms app.highlight 190ms RepoModel.GetById 92ms app.codeStats 2ms

/renderdocui/Windows/PipelineState/D3D11PipelineStateViewer.cs

https://github.com/tgAncel/renderdoc
C# | 2139 lines | 1672 code | 391 blank | 76 comment | 530 complexity | 31845932758885b56cef523fa4637610 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/******************************************************************************
   2 * The MIT License (MIT)
   3 * 
   4 * Copyright (c) 2014 Crytek
   5 * 
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 * 
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 * 
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 ******************************************************************************/
  24
  25
  26using System;
  27using System.Collections.Generic;
  28using System.ComponentModel;
  29using System.Drawing;
  30using System.Linq;
  31using System.Text;
  32using System.IO;
  33using System.Windows.Forms;
  34using WeifenLuo.WinFormsUI.Docking;
  35using renderdocui.Code;
  36using renderdocui.Controls;
  37using renderdoc;
  38
  39namespace renderdocui.Windows.PipelineState
  40{
  41    public partial class D3D11PipelineStateViewer : UserControl, ILogViewerForm
  42    {
  43        private Core m_Core;
  44        private DockContent m_DockContent;
  45
  46        // keep track of the VB nodes (we want to be able to highlight them easily on hover)
  47        private List<TreelistView.Node> m_VBNodes = new List<TreelistView.Node>();
  48
  49        public D3D11PipelineStateViewer(Core core, DockContent c)
  50        {
  51            InitializeComponent();
  52
  53            m_DockContent = c;
  54
  55            pipeFlow.SetStages(new KeyValuePair<string, string>[] {
  56                new KeyValuePair<string,string>("IA", "Input Assembler"),
  57                new KeyValuePair<string,string>("VS", "Vertex Shader"),
  58                new KeyValuePair<string,string>("HS", "Hull Shader"),
  59                new KeyValuePair<string,string>("DS", "Domain Shader"),
  60                new KeyValuePair<string,string>("GS", "Geometry Shader"),
  61                new KeyValuePair<string,string>("RS", "Rasterizer"),
  62                new KeyValuePair<string,string>("PS", "Pixel Shader"),
  63                new KeyValuePair<string,string>("OM", "Output Merger"),
  64                new KeyValuePair<string,string>("CS", "Compute Shader"),
  65            });
  66
  67            pipeFlow.IsolateStage(8); // compute shader isolated
  68
  69            pipeFlow.SetStagesEnabled(new bool[] { true, true, true, true, true, true, true, true, true });
  70
  71            //Icon = global::renderdocui.Properties.Resources.icon;
  72
  73            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
  74
  75            iaBytecodeMismatch.Text = "";
  76            iaBytecodeMismatch.Visible = false;
  77
  78            toolTip.SetToolTip(vsShaderCog, "Open Shader Source");
  79            toolTip.SetToolTip(dsShaderCog, "Open Shader Source");
  80            toolTip.SetToolTip(hsShaderCog, "Open Shader Source");
  81            toolTip.SetToolTip(gsShaderCog, "Open Shader Source");
  82            toolTip.SetToolTip(psShaderCog, "Open Shader Source");
  83            toolTip.SetToolTip(csShaderCog, "Open Shader Source");
  84
  85            toolTip.SetToolTip(vsShader, "Open Shader Source");
  86            toolTip.SetToolTip(dsShader, "Open Shader Source");
  87            toolTip.SetToolTip(hsShader, "Open Shader Source");
  88            toolTip.SetToolTip(gsShader, "Open Shader Source");
  89            toolTip.SetToolTip(psShader, "Open Shader Source");
  90            toolTip.SetToolTip(csShader, "Open Shader Source");
  91
  92            OnLogfileClosed();
  93
  94            m_Core = core;
  95        }
  96
  97        public void OnLogfileClosed()
  98        {
  99            inputLayouts.Nodes.Clear();
 100            iabuffers.Nodes.Clear();
 101            topology.Text = "";
 102            topologyDiagram.Image = null;
 103
 104            iaBytecodeMismatch.Text = "";
 105            iaBytecodeMismatch.Visible = false;
 106            iaBytecode.Text = "";
 107
 108            ClearShaderState(vsShader, vsResources, vsSamplers, vsCBuffers, vsClasses);
 109            ClearShaderState(gsShader, gsResources, gsSamplers, gsCBuffers, gsClasses);
 110            ClearShaderState(hsShader, hsResources, hsSamplers, hsCBuffers, hsClasses);
 111            ClearShaderState(dsShader, dsResources, dsSamplers, dsCBuffers, dsClasses);
 112            ClearShaderState(psShader, psResources, psSamplers, psCBuffers, psClasses);
 113            ClearShaderState(csShader, csResources, csSamplers, csCBuffers, csClasses);
 114
 115            csUAVs.Nodes.Clear();
 116            gsStreams.Nodes.Clear();
 117
 118            var tick = global::renderdocui.Properties.Resources.tick;
 119            var cross = global::renderdocui.Properties.Resources.cross;
 120
 121            fillMode.Text = "Solid";
 122            cullMode.Text = "Front";
 123            frontCCW.Image = tick;
 124
 125            scissorEnable.Image = tick;
 126            lineAAEnable.Image = tick;
 127            multisampleEnable.Image = tick;
 128
 129            depthClip.Image = tick;
 130            depthBias.Text = "0";
 131            depthBiasClamp.Text = "0.0";
 132            slopeScaledBias.Text = "0.0";
 133
 134            viewports.Nodes.Clear();
 135            scissors.Nodes.Clear();
 136
 137            targetOutputs.Nodes.Clear();
 138            blendOperations.Nodes.Clear();
 139
 140            alphaToCoverage.Image = tick;
 141            independentBlend.Image = tick;
 142
 143            blendFactor.Text = "0.00, 0.00, 0.00, 0.00";
 144
 145            sampleMask.Text = "FFFFFFFF";
 146
 147            depthEnable.Image = tick;
 148            depthFunc.Text = "GREATER_EQUAL";
 149            depthWrite.Image = tick;
 150
 151            stencilEnable.Image = tick;
 152            stencilReadMask.Text = "FF";
 153            stencilWriteMask.Text = "FF";
 154            stencilRef.Text = "FF";
 155
 156            pipeFlow.SetStagesEnabled(new bool[] { true, true, true, true, true, true, true, true, true });
 157        }
 158        
 159        public void OnLogfileLoaded()
 160        {
 161            OnEventSelected(m_Core.CurFrame, m_Core.CurEvent);
 162        }
 163
 164        private void EmptyRow(TreelistView.Node node)
 165        {
 166            node.BackColor = Color.Firebrick;
 167        }
 168
 169        private void InactiveRow(TreelistView.Node node)
 170        {
 171            node.Italic = true;
 172        }
 173
 174        private void ClearShaderState(Label shader, TreelistView.TreeListView resources, TreelistView.TreeListView samplers,
 175                                      TreelistView.TreeListView cbuffers, TreelistView.TreeListView classes)
 176        {
 177            shader.Text = "Unbound";
 178            resources.Nodes.Clear();
 179            samplers.Nodes.Clear();
 180            cbuffers.Nodes.Clear();
 181            classes.Nodes.Clear();
 182        }
 183
 184        // Set a shader stage's resources and values
 185        private void SetShaderState(FetchTexture[] texs, FetchBuffer[] bufs,
 186                                    D3D11PipelineState.ShaderStage stage,
 187                                    Label shader, TreelistView.TreeListView resources, TreelistView.TreeListView samplers,
 188                                    TreelistView.TreeListView cbuffers, TreelistView.TreeListView classes)
 189        {
 190            ShaderReflection shaderDetails = stage.ShaderDetails;
 191
 192            if (stage.Shader == ResourceId.Null)
 193                shader.Text = "Unbound";
 194            else
 195                shader.Text = "Shader " + stage.Shader.ToString();
 196
 197            if (shaderDetails != null && shaderDetails.DebugInfo.entryFunc != "" && shaderDetails.DebugInfo.files.Length > 0)
 198                shader.Text = shaderDetails.DebugInfo.entryFunc + "()" + " - " + 
 199                                Path.GetFileName(shaderDetails.DebugInfo.files[0].filename);
 200
 201            resources.BeginUpdate();
 202            resources.Nodes.Clear();
 203            if (stage.SRVs != null)
 204            {
 205                int i = 0;
 206                foreach (var r in stage.SRVs)
 207                {
 208                    ShaderResource shaderInput = null;
 209
 210                    if (shaderDetails != null)
 211                    {
 212                        foreach (var bind in shaderDetails.Resources)
 213                        {
 214                            if (bind.IsSRV && bind.bindPoint == i)
 215                                shaderInput = bind;
 216                        }
 217                    }
 218
 219                    bool filledSlot = (r.Resource != ResourceId.Null);
 220                    bool usedSlot = (shaderInput != null);
 221
 222                    // show if
 223                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 224                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 225                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 226                        )
 227                    {
 228                        string slotname = i.ToString();
 229
 230                        if (shaderInput != null && shaderInput.name != "")
 231                            slotname += ": " + shaderInput.name;
 232
 233                        UInt32 w = 1, h = 1, d = 1;
 234                        UInt32 a = 1;
 235                        string format = "Unknown";
 236                        string name = "Shader Resource " + r.Resource.ToString();
 237                        string typename = "Unknown";
 238                        object tag = null;
 239
 240                        if (!filledSlot)
 241                        {
 242                            name = "Empty";
 243                            format = "-";
 244                            typename = "-";
 245                            w = h = d = a = 0;
 246                        }
 247
 248                        // check to see if it's a texture
 249                        for (int t = 0; t < texs.Length; t++)
 250                        {
 251                            if (texs[t].ID == r.Resource)
 252                            {
 253                                w = texs[t].width;
 254                                h = texs[t].height;
 255                                d = texs[t].depth;
 256                                a = texs[t].arraysize;
 257                                format = texs[t].format.ToString();
 258                                name = texs[t].name;
 259                                typename = string.Format("Texture{0}D", texs[t].dimension);
 260                                if(texs[t].cubemap)
 261                                    typename = "TexCube";
 262
 263                                tag = texs[t];
 264                            }
 265                        }
 266
 267                        // if not a texture, it must be a buffer
 268                        for (int t = 0; t < bufs.Length; t++)
 269                        {
 270                            if (bufs[t].ID == r.Resource)
 271                            {
 272                                w = bufs[t].length;
 273                                h = 0;
 274                                d = 0;
 275                                a = 0;
 276                                format = "";
 277                                name = bufs[t].name;
 278                                typename = "Buffer";
 279
 280                                // for structured buffers, display how many 'elements' there are in the buffer
 281                                if (bufs[t].structureSize > 0)
 282                                    typename = "StructuredBuffer[" + (bufs[t].length / bufs[t].structureSize) + "]";
 283
 284                                // get the buffer type, whether it's just a basic type or a complex struct
 285                                if (shaderInput != null && !shaderInput.IsTexture)
 286                                {
 287                                    if (r.Format.compType == FormatComponentType.None)
 288                                    {
 289                                        if (shaderInput.variableType.members.Length > 0)
 290                                            format = "struct " + shaderInput.variableType.Name;
 291                                        else
 292                                            format = shaderInput.variableType.Name;
 293                                    }
 294                                    else
 295                                    {
 296                                        format = r.Format.ToString();
 297                                    }
 298                                }
 299
 300                                tag = bufs[t];
 301                            }
 302                        }
 303
 304                        var node = resources.Nodes.Add(new object[] { slotname, name, typename, w, h, d, a, format });
 305
 306                        node.Image = global::renderdocui.Properties.Resources.action;
 307                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 308                        node.Tag = tag;
 309
 310                        if (!filledSlot)
 311                            EmptyRow(node);
 312
 313                        if (!usedSlot)
 314                            InactiveRow(node);
 315                    }
 316                    i++;
 317                }
 318            }
 319            resources.EndUpdate();
 320            resources.NodesSelection.Clear();
 321
 322            samplers.BeginUpdate();
 323            samplers.Nodes.Clear();
 324            if (stage.Samplers != null)
 325            {
 326                int i = 0;
 327                foreach (var s in stage.Samplers)
 328                {
 329                    ShaderResource shaderInput = null;
 330
 331                    if (shaderDetails != null)
 332                    {
 333                        foreach (var bind in shaderDetails.Resources)
 334                        {
 335                            if (bind.IsSampler && bind.bindPoint == i)
 336                                shaderInput = bind;
 337                        }
 338                    }
 339
 340                    bool filledSlot = (s.AddressU != "");
 341                    bool usedSlot = (shaderInput != null);
 342                    
 343                    // show if
 344                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 345                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 346                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 347                        )
 348                    {
 349                        string slotname = i.ToString();
 350
 351                        if (shaderInput != null && shaderInput.name != "")
 352                            slotname += ": " + shaderInput.name;
 353
 354                        string borderColor = s.BorderColor[0].ToString() + ", " +
 355                                                s.BorderColor[1].ToString() + ", " +
 356                                                s.BorderColor[2].ToString() + ", " +
 357                                                s.BorderColor[3].ToString();
 358
 359                        string addressing = "";
 360
 361                        string addPrefix = "";
 362                        string addVal = "";
 363
 364                        string[] addr = { s.AddressU, s.AddressV, s.AddressW };
 365
 366                        // arrange like either UVW: WRAP or UV: WRAP, W: CLAMP
 367                        for (int a = 0; a < 3; a++)
 368                        {
 369                            string prefix = "" + "UVW"[a];
 370
 371                            if (a == 0 || addr[a] == addr[a - 1])
 372                            {
 373                                addPrefix += prefix;
 374                            }
 375                            else
 376                            {
 377                                addressing += addPrefix + ": " + addVal + ", ";
 378
 379                                addPrefix = prefix;
 380                            }
 381                            addVal = addr[a];
 382                        }
 383
 384                        addressing += addPrefix + ": " + addVal;
 385
 386                        var node = samplers.Nodes.Add(new object[] { slotname, addressing, borderColor,
 387                                                            s.Comparison, s.Filter, s.MaxAniso.ToString(),
 388                                                            s.MinLOD == -float.MaxValue ? "-FLT_MAX" : s.MinLOD.ToString(),
 389                                                            s.MaxLOD == float.MaxValue ? "FLT_MAX" : s.MaxLOD.ToString(),
 390                                                            s.MipLODBias.ToString() });
 391
 392                        if (!filledSlot)
 393                            EmptyRow(node);
 394
 395                        if (!usedSlot)
 396                            InactiveRow(node);
 397                    }
 398
 399                    i++;
 400                }
 401            }
 402            samplers.EndUpdate();
 403            samplers.NodesSelection.Clear();
 404
 405            cbuffers.BeginUpdate();
 406            cbuffers.Nodes.Clear();
 407            if (stage.ConstantBuffers != null)
 408            {
 409                UInt32 i = 0;
 410                foreach (var b in stage.ConstantBuffers)
 411                {
 412                    ConstantBlock shaderCBuf = null;
 413
 414                    if (shaderDetails != null && i < shaderDetails.ConstantBlocks.Length && shaderDetails.ConstantBlocks[i].name != "")
 415                        shaderCBuf = shaderDetails.ConstantBlocks[i];
 416
 417                    bool filledSlot = (b.Buffer != ResourceId.Null);
 418                    bool usedSlot = (shaderCBuf != null);
 419
 420                    // show if
 421                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 422                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 423                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 424                        )
 425                    {
 426                        string name = "Constant Buffer " + b.Buffer.ToString();
 427                        UInt32 length = 1;
 428                        int numvars = shaderCBuf != null ? shaderCBuf.variables.Length : 0;
 429
 430                        if (!filledSlot)
 431                        {
 432                            name = "Empty";
 433                            length = 0;
 434                        }
 435
 436                        for (int t = 0; t < bufs.Length; t++)
 437                        {
 438                            if (bufs[t].ID == b.Buffer)
 439                            {
 440                                name = bufs[t].name;
 441                                length = bufs[t].length;
 442                            }
 443                        }
 444
 445                        string slotname = i.ToString();
 446
 447                        if (shaderCBuf != null && shaderCBuf.name != "")
 448                            slotname += ": " + shaderCBuf.name;
 449
 450                        var node = cbuffers.Nodes.Add(new object[] { slotname, name, b.VecOffset, b.VecCount, numvars, length });
 451
 452                        node.Image = global::renderdocui.Properties.Resources.action;
 453                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 454                        node.Tag = i;
 455
 456                        if (!filledSlot)
 457                            EmptyRow(node);
 458
 459                        if (!usedSlot)
 460                            InactiveRow(node);
 461                    }
 462                    i++;
 463                }
 464            }
 465            cbuffers.EndUpdate();
 466            cbuffers.NodesSelection.Clear();
 467
 468            classes.BeginUpdate();
 469            classes.Nodes.Clear();
 470            {
 471                UInt32 i = 0;
 472                foreach (var inst in stage.ClassInstances)
 473                {
 474                    string interfaceName = String.Format("Interface {0}", i);
 475
 476                    if (shaderDetails != null && i < shaderDetails.Interfaces.Length)
 477                        interfaceName = shaderDetails.Interfaces[i].Name;
 478
 479                    classes.Nodes.Add(new object[] { i.ToString(), interfaceName, inst });
 480
 481                    i++;
 482                }
 483            }
 484            classes.EndUpdate();
 485            classes.NodesSelection.Clear();
 486        }
 487
 488        // from https://gist.github.com/mjijackson/5311256
 489        private float CalcHue(float p, float q, float t)
 490        {
 491            if (t < 0) t += 1;
 492            if (t > 1) t -= 1;
 493
 494            if (t < 1.0f / 6.0f)
 495                return p + (q - p) * 6.0f * t;
 496
 497            if (t < 0.5f)
 498                return q;
 499
 500            if (t < 2.0f / 3.0f)
 501                return p + (q - p) * (2.0f / 3.0f - t) * 6.0f;
 502
 503            return p;
 504        }
 505
 506        private Color HSLColor(float h, float s, float l)
 507        {
 508            float r, g, b;
 509
 510            if (s == 0)
 511            {
 512                r = g = b = l; // achromatic
 513            }
 514            else
 515            {
 516                var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
 517                var p = 2 * l - q;
 518                r = CalcHue(p, q, h + 1.0f / 3.0f);
 519                g = CalcHue(p, q, h);
 520                b = CalcHue(p, q, h - 1.0f / 3.0f);
 521            }
 522
 523            return Color.FromArgb(255, (int)(r * 255), (int)(g * 255), (int)(b * 255));
 524        }
 525
 526        private void UpdateState()
 527        {
 528            if (!m_Core.LogLoaded)
 529                return;
 530
 531            FetchTexture[] texs = m_Core.CurTextures;
 532            FetchBuffer[] bufs = m_Core.CurBuffers;
 533            D3D11PipelineState state = m_Core.CurD3D11PipelineState;
 534            FetchDrawcall draw = m_Core.CurDrawcall;
 535
 536            var tick = global::renderdocui.Properties.Resources.tick;
 537            var cross = global::renderdocui.Properties.Resources.cross;
 538
 539            bool[] usedVBuffers = new bool[128];
 540            UInt32[] layoutOffs = new UInt32[128];
 541
 542            for (int i = 0; i < 128; i++)
 543            {
 544                usedVBuffers[i] = false;
 545                layoutOffs[i] = 0;
 546            }
 547
 548            ////////////////////////////////////////////////
 549            // Input Assembler
 550
 551            if(state.m_IA.Bytecode == null)
 552                iaBytecode.Text = "None";
 553            else if(state.m_IA.Bytecode.DebugInfo == null || state.m_IA.Bytecode.DebugInfo.entryFunc == "")
 554                iaBytecode.Text = "Layout " + state.m_IA.layout.ToString();
 555            else
 556                iaBytecode.Text = state.m_IA.Bytecode.DebugInfo.entryFunc;
 557
 558            iaBytecodeMismatch.Text = "";
 559            iaBytecodeMismatch.Visible = false;
 560            
 561            // check for IA-VS mismatches here.
 562            // This should be moved to a "Render Doctor" window reporting problems
 563            if (state.m_IA.Bytecode != null && state.m_VS.ShaderDetails != null)
 564            {
 565                string mismatchDetails = "";
 566
 567                // VS wants more elements
 568                if (state.m_IA.Bytecode.InputSig.Length < state.m_VS.ShaderDetails.InputSig.Length)
 569                    mismatchDetails += "IA bytecode provides fewer elements than VS wants.\n";
 570
 571                {
 572                    var IA = state.m_IA.Bytecode.InputSig;
 573                    var VS = state.m_VS.ShaderDetails.InputSig;
 574
 575                    int count = Math.Min(IA.Length, VS.Length);
 576
 577                    for (int i = 0; i < count; i++)
 578                    {
 579                        // misorder or misnamed semantics
 580                        if (IA[i].semanticIdxName.ToLowerInvariant() != VS[i].semanticIdxName.ToLowerInvariant())
 581                            mismatchDetails += String.Format("IA bytecode semantic {0}: {1} != VS bytecode semantic {0}: {2}\n", i,
 582                                                                IA[i].semanticIdxName, VS[i].semanticIdxName);
 583
 584                        // VS wants more components
 585                        if (IA[i].compCount < VS[i].compCount)
 586                            mismatchDetails += String.Format("IA bytecode semantic {0} ({1}) is {3}-wide, VS bytecode semantic {0} ({1}) {2} is {4}-wide\n", i,
 587                                                                IA[i].semanticIdxName, VS[i].semanticIdxName,
 588                                                                IA[i].compCount, VS[i].compCount);
 589                        
 590                        // VS wants different types
 591                        if (IA[i].compType != VS[i].compType)
 592                            mismatchDetails += String.Format("IA bytecode semantic {0} ({1}) is {3}, VS bytecode semantic {0} ({2}) is {4}\n", i,
 593                                                                IA[i].semanticIdxName, VS[i].semanticIdxName,
 594                                                                IA[i].compType, VS[i].compType);
 595                    }
 596                }
 597
 598                if (mismatchDetails.Length != 0)
 599                {
 600                    iaBytecodeMismatch.Text = "Warning: Mismatch detected between bytecode used to create IA and currently bound VS inputs";
 601                    toolTip.SetToolTip(iaBytecodeMismatch, mismatchDetails.Trim());
 602                    iaBytecodeMismatch.Visible = true;
 603                }
 604            }
 605
 606            inputLayouts.Nodes.Clear();
 607            inputLayouts.BeginUpdate();
 608            if (state.m_IA.layouts != null)
 609            {
 610                int i = 0;
 611                foreach (var l in state.m_IA.layouts)
 612                {
 613                    string byteOffs = l.ByteOffset.ToString();
 614
 615                    // D3D11 specific value
 616                    if (l.ByteOffset == uint.MaxValue)
 617                    {
 618                        byteOffs = String.Format("APPEND_ALIGNED ({0})", layoutOffs[l.InputSlot]);
 619                    }
 620                    else
 621                    {
 622                        layoutOffs[l.InputSlot] = l.ByteOffset;
 623                    }
 624
 625                    layoutOffs[l.InputSlot] += l.Format.compByteWidth * l.Format.compCount;
 626
 627                    var node = inputLayouts.Nodes.Add(new object[] {
 628                                              i, l.SemanticName, l.SemanticIndex.ToString(), l.Format, l.InputSlot.ToString(), byteOffs,
 629                                              l.PerInstance ? "PER_INSTANCE" : "PER_VERTEX", l.InstanceDataStepRate.ToString() });
 630
 631                    usedVBuffers[l.InputSlot] = true;
 632
 633                    node.Image = global::renderdocui.Properties.Resources.action;
 634                    node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 635
 636                    i++;
 637                }
 638            }
 639            inputLayouts.NodesSelection.Clear();
 640            inputLayouts.EndUpdate();
 641
 642            topology.Text = state.m_IA.Topology.ToString();
 643            if (state.m_IA.Topology > PrimitiveTopology.PatchList)
 644            {
 645                int numCPs = (int)state.m_IA.Topology - (int)PrimitiveTopology.PatchList + 1;
 646
 647                topology.Text = string.Format("PatchList ({0} Control Points)", numCPs);
 648            }
 649
 650            switch (state.m_IA.Topology)
 651            {
 652                case PrimitiveTopology.PointList:
 653                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_pointlist;
 654                    break;
 655                case PrimitiveTopology.LineList:
 656                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linelist;
 657                    break;
 658                case PrimitiveTopology.LineStrip:
 659                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linestrip;
 660                    break;
 661                case PrimitiveTopology.TriangleList:
 662                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_trilist;
 663                    break;
 664                case PrimitiveTopology.TriangleStrip:
 665                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_tristrip;
 666                    break;
 667                case PrimitiveTopology.LineList_Adj:
 668                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linelist_adj;
 669                    break;
 670                case PrimitiveTopology.LineStrip_Adj:
 671                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_linestrip_adj;
 672                    break;
 673                case PrimitiveTopology.TriangleList_Adj:
 674                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_trilist_adj;
 675                    break;
 676                case PrimitiveTopology.TriangleStrip_Adj:
 677                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_tristrip_adj;
 678                    break;
 679                default:
 680                    topologyDiagram.Image = global::renderdocui.Properties.Resources.topo_patch;
 681                    break;
 682            }
 683
 684            iabuffers.Nodes.Clear();
 685            iabuffers.BeginUpdate();
 686
 687            bool ibufferUsed = draw != null && (draw.flags & DrawcallFlags.UseIBuffer) != 0;
 688
 689            if (state.m_IA.ibuffer != null)
 690            {
 691                if (ibufferUsed || showDisabled.Checked)
 692                {
 693                    string ptr = "Buffer " + state.m_IA.ibuffer.Buffer.ToString();
 694                    string name = ptr;
 695                    UInt32 length = 1;
 696
 697                    if (!ibufferUsed)
 698                    {
 699                        length = 0;
 700                    }
 701
 702                    for (int t = 0; t < bufs.Length; t++)
 703                    {
 704                        if (bufs[t].ID == state.m_IA.ibuffer.Buffer)
 705                        {
 706                            name = bufs[t].name;
 707                            length = bufs[t].length;
 708                        }
 709                    }
 710
 711                    var node = iabuffers.Nodes.Add(new object[] { "Index", name, state.m_IA.ibuffer.Format.compByteWidth, state.m_IA.ibuffer.Offset, length });
 712
 713                    node.Image = global::renderdocui.Properties.Resources.action;
 714                    node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 715                    node.Tag = state.m_IA.ibuffer.Buffer;
 716
 717                    if (!ibufferUsed)
 718                        InactiveRow(node);
 719
 720                    if (state.m_IA.ibuffer.Buffer == ResourceId.Null)
 721                        EmptyRow(node);
 722                }
 723            }
 724            else
 725            {
 726                if (showEmpty.Checked &&
 727                    (ibufferUsed || showDisabled.Checked))
 728                {
 729                    var node = iabuffers.Nodes.Add(new object[] { "Index", "-", "-", "-", "-" });
 730
 731                    node.Image = global::renderdocui.Properties.Resources.action;
 732                    node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 733                    node.Tag = state.m_IA.ibuffer.Buffer;
 734
 735                    EmptyRow(node);
 736
 737                    if (!ibufferUsed)
 738                        InactiveRow(node);
 739                }
 740            }
 741
 742            m_VBNodes.Clear();
 743
 744            if (state.m_IA.vbuffers != null)
 745            {
 746                int i = 0;
 747                foreach (var v in state.m_IA.vbuffers)
 748                {
 749                    bool filledSlot = (v.Buffer != ResourceId.Null);
 750                    bool usedSlot = (usedVBuffers[i]);
 751
 752                    // show if
 753                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 754                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 755                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 756                        )
 757                    {
 758                        string name = "Buffer " + v.Buffer.ToString();
 759                        UInt32 length = 1;
 760
 761                        if (!filledSlot)
 762                        {
 763                            name = "Empty";
 764                            length = 0;
 765                        }
 766
 767                        for (int t = 0; t < bufs.Length; t++)
 768                        {
 769                            if (bufs[t].ID == v.Buffer)
 770                            {
 771                                name = bufs[t].name;
 772                                length = bufs[t].length;
 773                            }
 774                        }
 775
 776                        var node = iabuffers.Nodes.Add(new object[] { i, name, v.Stride, v.Offset, length });
 777
 778                        node.Image = global::renderdocui.Properties.Resources.action;
 779                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 780                        node.Tag = v.Buffer;
 781
 782                        if (!filledSlot)
 783                            EmptyRow(node);
 784
 785                        if (!usedSlot)
 786                            InactiveRow(node);
 787
 788                        m_VBNodes.Add(node);
 789                    }
 790
 791                    i++;
 792                }
 793            }
 794            iabuffers.NodesSelection.Clear();
 795            iabuffers.EndUpdate();
 796
 797            SetShaderState(texs, bufs, state.m_VS, vsShader, vsResources, vsSamplers, vsCBuffers, vsClasses);
 798            SetShaderState(texs, bufs, state.m_GS, gsShader, gsResources, gsSamplers, gsCBuffers, gsClasses);
 799            SetShaderState(texs, bufs, state.m_HS, hsShader, hsResources, hsSamplers, hsCBuffers, hsClasses);
 800            SetShaderState(texs, bufs, state.m_DS, dsShader, dsResources, dsSamplers, dsCBuffers, dsClasses);
 801            SetShaderState(texs, bufs, state.m_PS, psShader, psResources, psSamplers, psCBuffers, psClasses);
 802            SetShaderState(texs, bufs, state.m_CS, csShader, csResources, csSamplers, csCBuffers, csClasses);
 803
 804            csUAVs.Nodes.Clear();
 805            csUAVs.BeginUpdate();
 806
 807            if (state.m_CS.UAVs != null)
 808            {
 809                int i = 0;
 810                foreach (var r in state.m_CS.UAVs)
 811                {
 812                    ShaderResource shaderInput = null;
 813
 814                    if (state.m_CS.ShaderDetails != null)
 815                    {
 816                        foreach (var bind in state.m_CS.ShaderDetails.Resources)
 817                        {
 818                            if (bind.IsUAV && bind.bindPoint == i)
 819                                shaderInput = bind;
 820                        }
 821                    }
 822
 823                    bool filledSlot = (r.Resource != ResourceId.Null);
 824                    bool usedSlot = (shaderInput != null);
 825
 826                    // show if
 827                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 828                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 829                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 830                        )
 831                    {
 832                        UInt32 w = 1, h = 1, d = 1;
 833                        UInt32 a = 1;
 834                        string format = "Unknown";
 835                        string name = "UAV " + r.Resource.ToString();
 836                        string typename = "Unknown";
 837                        object tag = null;
 838
 839                        if (!filledSlot)
 840                        {
 841                            name = "Empty";
 842                            format = "-";
 843                            typename = "-";
 844                            w = h = d = a = 0;
 845                        }
 846
 847                        for (int t = 0; t < texs.Length; t++)
 848                        {
 849                            if (texs[t].ID == r.Resource)
 850                            {
 851                                w = texs[t].width;
 852                                h = texs[t].height;
 853                                d = texs[t].depth;
 854                                a = texs[t].arraysize;
 855                                format = texs[t].format.ToString();
 856                                name = texs[t].name;
 857                                typename = string.Format("Texture{0}D", texs[t].dimension);
 858                                if (texs[t].cubemap)
 859                                    typename = "TexCube";
 860
 861                                tag = texs[t];
 862                            }
 863                        }
 864
 865                        for (int t = 0; t < bufs.Length; t++)
 866                        {
 867                            if (bufs[t].ID == r.Resource)
 868                            {
 869                                w = bufs[t].length;
 870                                h = 0;
 871                                d = 0;
 872                                a = 0;
 873                                format = "";
 874                                name = bufs[t].name;
 875                                typename = "Buffer";
 876
 877                                if (bufs[t].structureSize > 0)
 878                                    typename = "StructuredBuffer[" + (bufs[t].length / bufs[t].structureSize) + "]";
 879
 880                                if (r.Structured)
 881                                {
 882                                    typename += " (Count: " + r.BufferStructCount + ")";
 883                                }
 884
 885                                if (shaderInput != null && !shaderInput.IsTexture)
 886                                {
 887                                    if (r.Format.compType == FormatComponentType.None)
 888                                    {
 889                                        if (shaderInput.variableType.members.Length > 0)
 890                                            format = "struct " + shaderInput.variableType.Name;
 891                                        else
 892                                            format = shaderInput.variableType.Name;
 893                                    }
 894                                    else
 895                                    {
 896                                        format = r.Format.ToString();
 897                                    }
 898                                }
 899
 900                                tag = bufs[t];
 901                            }
 902                        }
 903
 904                        var node = csUAVs.Nodes.Add(new object[] { i, name, typename, w, h, d, a, format });
 905
 906                        node.Tag = tag;
 907
 908                        node.Image = global::renderdocui.Properties.Resources.action;
 909                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 910
 911                        if (!filledSlot)
 912                            EmptyRow(node);
 913
 914                        if (!usedSlot)
 915                            InactiveRow(node);
 916                    }
 917
 918                    i++;
 919                }
 920            }
 921            csUAVs.NodesSelection.Clear();
 922            csUAVs.EndUpdate();
 923
 924            gsStreams.BeginUpdate();
 925            gsStreams.Nodes.Clear();
 926            if (state.m_SO.Outputs != null)
 927            {
 928                int i = 0;
 929                foreach (var s in state.m_SO.Outputs)
 930                {
 931                    bool filledSlot = (s.Buffer != ResourceId.Null);
 932                    bool usedSlot = (filledSlot);
 933
 934                    // show if
 935                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
 936                        (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled"
 937                        (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty"
 938                        )
 939                    {
 940                        string name = "Buffer " + s.Buffer.ToString();
 941                        uint length = 0;
 942
 943                        if (!filledSlot)
 944                        {
 945                            name = "Empty";
 946                        }
 947
 948                        FetchBuffer fetch = null;
 949
 950                        for (int t = 0; t < bufs.Length; t++)
 951                        {
 952                            if (bufs[t].ID == s.Buffer)
 953                            {
 954                                name = bufs[t].name;
 955                                length = bufs[t].length;
 956
 957                                fetch = bufs[t];
 958                            }
 959                        }
 960
 961                        var node = gsStreams.Nodes.Add(new object[] { i, name, length, s.Offset });
 962
 963                        node.Image = global::renderdocui.Properties.Resources.action;
 964                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
 965                        node.Tag = fetch;
 966
 967                        if (!filledSlot)
 968                            EmptyRow(node);
 969
 970                        if (!usedSlot)
 971                            InactiveRow(node);
 972                    }
 973                    i++;
 974                }
 975            }
 976            gsStreams.EndUpdate();
 977            gsStreams.NodesSelection.Clear();
 978
 979            ////////////////////////////////////////////////
 980            // Rasterizer
 981
 982            viewports.BeginUpdate();
 983            viewports.Nodes.Clear();
 984            if (state.m_RS.Viewports != null)
 985            {
 986                int i = 0;
 987                foreach (var v in state.m_RS.Viewports)
 988                {
 989                    if (v.Width != v.Height || v.Width != 0 || v.Height != 0 || showEmpty.Checked)
 990                    {
 991                        var node = viewports.Nodes.Add(new object[] { i, v.TopLeft[0], v.TopLeft[1], v.Width, v.Height, v.MinDepth, v.MaxDepth });
 992
 993                        if (v.Width == v.Height && v.Width == 0 && v.Height == 0)
 994                            EmptyRow(node);
 995                    }
 996
 997                    i++;
 998                }
 999            }
1000            viewports.NodesSelection.Clear();
1001            viewports.EndUpdate();
1002
1003            scissors.BeginUpdate();
1004            scissors.Nodes.Clear();
1005            if (state.m_RS.Scissors != null)
1006            {
1007                int i = 0;
1008                foreach (var s in state.m_RS.Scissors)
1009                {
1010                    if (s.right != 0 || s.bottom != 0 || showEmpty.Checked)
1011                    {
1012                        var node = scissors.Nodes.Add(new object[] { i, s.left, s.top, s.right - s.left, s.bottom - s.top });
1013
1014                        if (s.right == 0 && s.bottom == 0)
1015                            EmptyRow(node);
1016                    }
1017
1018                    i++;
1019                }
1020            }
1021            scissors.NodesSelection.Clear();
1022            scissors.EndUpdate();
1023
1024            fillMode.Text = state.m_RS.m_State.FillMode.ToString();
1025            cullMode.Text = state.m_RS.m_State.CullMode.ToString();
1026            frontCCW.Image = state.m_RS.m_State.FrontCCW ? tick : cross;
1027
1028            scissorEnable.Image = state.m_RS.m_State.ScissorEnable ? tick : cross;
1029            lineAAEnable.Image = state.m_RS.m_State.AntialiasedLineEnable ? tick : cross;
1030            multisampleEnable.Image = state.m_RS.m_State.MultisampleEnable ? tick : cross;
1031
1032            depthClip.Image = state.m_RS.m_State.DepthClip ? tick : cross;
1033            depthBias.Text = state.m_RS.m_State.DepthBias.ToString();
1034            depthBiasClamp.Text = Formatter.Format(state.m_RS.m_State.DepthBiasClamp);
1035            slopeScaledBias.Text = Formatter.Format(state.m_RS.m_State.SlopeScaledDepthBias);
1036            forcedSampleCount.Text = state.m_RS.m_State.ForcedSampleCount.ToString();
1037
1038            ////////////////////////////////////////////////
1039            // Output Merger
1040
1041            bool[] targets = new bool[8];
1042
1043            for (int i = 0; i < 8; i++)
1044                targets[i] = false;
1045
1046            targetOutputs.BeginUpdate();
1047            targetOutputs.Nodes.Clear();
1048            if (state.m_OM.RenderTargets != null)
1049            {
1050                int i = 0;
1051                foreach (var p in state.m_OM.RenderTargets)
1052                {
1053                    if (p.Resource != ResourceId.Null || showEmpty.Checked)
1054                    {
1055                        UInt32 w = 1, h = 1, d = 1;
1056                        UInt32 a = 1;
1057                        string format = "Unknown";
1058                        string name = "Texture " + p.ToString();
1059                        string typename = "Unknown";
1060                        object tag = null;
1061
1062                        if (p.Resource == ResourceId.Null)
1063                        {
1064                            name = "Empty";
1065                            format = "-";
1066                            typename = "-";
1067                            w = h = d = a = 0;
1068                        }
1069
1070                        for (int t = 0; t < texs.Length; t++)
1071                        {
1072                            if (texs[t].ID == p.Resource)
1073                            {
1074                                w = texs[t].width;
1075                                h = texs[t].height;
1076                                d = texs[t].depth;
1077                                a = texs[t].arraysize;
1078                                format = texs[t].format.ToString();
1079                                name = texs[t].name;
1080                                typename = string.Format("Texture{0}D", texs[t].dimension);
1081                                if (texs[t].cubemap)
1082                                    typename = "TexCube";
1083
1084                                tag = texs[t];
1085                            }
1086                        }
1087
1088                        var node = targetOutputs.Nodes.Add(new object[] { i, name, typename, w, h, d, a, format });
1089
1090                        node.Image = global::renderdocui.Properties.Resources.action;
1091                        node.HoverImage = global::renderdocui.Properties.Resources.action_hover;
1092                        node.Tag = tag;
1093
1094                        if (p.Resource == ResourceId.Null)
1095                        {
1096                            EmptyRow(node);
1097                        }
1098                        else
1099                        {
1100                            targets[i] = true;
1101                        }
1102                    }
1103
1104                    i++;
1105                }
1106            }
1107
1108            if (state.m_OM.UAVs != null)
1109            {
1110                int i = 0;
1111                foreach (var r in state.m_OM.UAVs)
1112                {
1113                    ShaderResource shaderInput = null;
1114
1115                    if (state.m_PS.ShaderDetails != null)
1116                    {
1117                        foreach (var bind in state.m_PS.ShaderDetails.Resources)
1118                        {
1119                            if (bind.IsUAV && bind.bindPoint == i + state.m_OM.UAVStartSlot)
1120                                shaderInput = bind;
1121                        }
1122                    }
1123
1124                    bool filledSlot = (r.Resource != ResourceId.Null);
1125                    bool usedSlot = (shaderInput != null);
1126
1127                    // note: we don't show empty UAVs as these "slots" are already showed as empty RTs.
1128
1129                    // show if
1130                    if (usedSlot || // it's referenced by the shader - regardless of empty or not
1131                        (showDisabled.Checked && !usedSlot && filledSlot) // it's bound, but not referenced, and we have "show disabled"
1132                        )
1133                    {
1134                        UInt32 w = 1, h = 1, d = 1;
1135                        UInt32 a = 1;
1136                        string format = "Unknown";
1137                        string name = "UAV " + r.Resource.ToString();
1138                        string typename = "Unknown";
1139                        object tag = null;
1140
1141                        if (!filledSlot)
1142                        {
1143                            name = "Empty";
1144                            format = "-";
1145                            typename = "-";
1146                            w = h = d = a = 0;
1147                        }
1148
1149                        for (int t = 0; t < texs.Length; t++)
1150                        {
1151                            if (texs[t].ID == r.Resource)
1152                            {
1153                                w = texs[t].width;
1154                                h = texs[t].height;
1155                                d = texs[t].depth;
1156                                a = texs[t].arraysize;
1157                                format = texs[t].format.ToString();
1158                                name = texs[t].name;
1159                                typename = string.Format("Texture{0}D", texs[t].dimension);
1160                                if (texs[t].cubemap)
1161                                    typename = "TexCube";
1162
1163                                tag = texs[t];
1164                            }
1165                        }
1166
1167                        for (int t = 0; t < bufs.Length; t++)
1168                        {
1169                            if (bufs[t].ID 

Large files files are truncated, but you can click here to view the full file