private void PostMarshal() { if (_ptr_Bytecode != IntPtr.Zero) Bytecode = (ShaderReflection)CustomMarshal.PtrToStructure(_ptr_Bytecode, typeof(ShaderReflection), false); else Bytecode = null; _ptr_Bytecode = IntPtr.Zero; }
private void PostMarshal() { if (_ptr_ShaderDetails != IntPtr.Zero) ShaderDetails = (ShaderReflection)CustomMarshal.PtrToStructure(_ptr_ShaderDetails, typeof(ShaderReflection), false); else ShaderDetails = null; _ptr_ShaderDetails = IntPtr.Zero; }
public ShaderReflection GetShaderDetails(ResourceId shader) { IntPtr mem = ReplayRenderer_GetShaderDetails(m_Real, shader); ShaderReflection ret = null; if (mem != IntPtr.Zero) { ret = (ShaderReflection)CustomMarshal.PtrToStructure(mem, typeof(ShaderReflection), false); } return(ret); }
private object[] ExportViewHTML(D3D11PipelineState.ShaderStage.ResourceView view, int i, ShaderReflection refl, string extraParams) { FetchTexture[] texs = m_Core.CurTextures; FetchBuffer[] bufs = m_Core.CurBuffers; ShaderResource shaderInput = null; bool rw = false; if (refl != null) { foreach (var bind in refl.ReadOnlyResources) { if (bind.bindPoint == i) { shaderInput = bind; break; } } foreach (var bind in refl.ReadWriteResources) { if (bind.bindPoint == i) { shaderInput = bind; rw = true; break; } } } string name = "Empty"; string typename = "Unknown"; string format = "Unknown"; UInt64 w = 1; UInt32 h = 1, d = 1; UInt32 a = 0; string viewFormat = view.Format.ToString(); FetchTexture tex = null; FetchBuffer buf = null; // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == view.Resource) { w = texs[t].width; h = texs[t].height; d = texs[t].depth; a = texs[t].arraysize; format = texs[t].format.ToString(); name = texs[t].name; typename = texs[t].resType.ToString(); tex = texs[t]; } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == view.Resource) { w = bufs[t].length; h = 0; d = 0; a = 0; format = view.Format.ToString(); name = bufs[t].name; typename = "Buffer"; // for structured buffers, display how many 'elements' there are in the buffer if (view.ElementSize > 0) { typename = (rw ? "RWStructuredBuffer" : "StructuredBuffer") + "[" + (bufs[t].length / view.ElementSize) + "]"; } else if (view.Flags.HasFlag(D3D11BufferViewFlags.Raw)) { typename = rw ? "RWByteAddressBuffer" : "ByteAddressBuffer"; } if (view.Flags.HasFlag(D3D11BufferViewFlags.Append) || view.Flags.HasFlag(D3D11BufferViewFlags.Counter)) { typename += " (Count: " + view.BufferStructCount + ")"; } if (shaderInput != null && !shaderInput.IsTexture) { if (view.Format.compType == FormatComponentType.None) { if (shaderInput.variableType.members.Length > 0) viewFormat = format = "struct " + shaderInput.variableType.Name; else viewFormat = format = shaderInput.variableType.Name; } else { format = view.Format.ToString(); } } buf = bufs[t]; } } string viewParams = ""; if(buf != null) { viewParams = String.Format("First Element: {0}, Num Elements {1}, Flags {2}", view.FirstElement, view.NumElements, view.Flags); } if (tex != null) { if(tex.mips > 1) viewParams = String.Format("Highest Mip: {0}, Num Mips: {1}", view.HighestMip, view.NumMipLevels); if (tex.arraysize > 1) { if (viewParams.Length > 0) viewParams += ", "; viewParams += String.Format("First Slice: {0}, Array Size: {1}", view.FirstArraySlice, view.ArraySize); } } if (viewParams == "") viewParams = extraParams; else viewParams += ", " + extraParams; return new object[] { i, name, view.Type, typename, w, h, d, a, viewFormat, format, viewParams }; }
public ShaderViewer(Core core, ShaderReflection shader, ShaderStageType stage, ShaderDebugTrace trace, string debugContext) { InitializeComponent(); constantRegs.Font = variableRegs.Font = watchRegs.Font = inSig.Font = outSig.Font = core.Config.PreferredFont; Icon = global::renderdocui.Properties.Resources.icon; this.SuspendLayout(); mainLayout.Dock = DockStyle.Fill; constantRegs.Font = variableRegs.Font = watchRegs.Font = inSig.Font = outSig.Font = core.Config.PreferredFont; m_Core = core; m_ShaderDetails = shader; m_Trace = trace; m_Stage = null; switch (stage) { case ShaderStageType.Vertex: m_Stage = m_Core.CurD3D11PipelineState.m_VS; break; case ShaderStageType.Domain: m_Stage = m_Core.CurD3D11PipelineState.m_DS; break; case ShaderStageType.Hull: m_Stage = m_Core.CurD3D11PipelineState.m_HS; break; case ShaderStageType.Geometry: m_Stage = m_Core.CurD3D11PipelineState.m_GS; break; case ShaderStageType.Pixel: m_Stage = m_Core.CurD3D11PipelineState.m_PS; break; case ShaderStageType.Compute: m_Stage = m_Core.CurD3D11PipelineState.m_CS; break; } if (trace != null) Text = String.Format("Debugging {0} - {1}", m_Core.CurPipelineState.GetShaderName(stage), debugContext); else Text = m_Core.CurPipelineState.GetShaderName(stage); var disasm = shader.Disassembly; if (m_Core.Config.ShaderViewer_FriendlyNaming) { for (int i = 0; i < m_ShaderDetails.ConstantBlocks.Length; i++) { var stem = string.Format("cb{0}", i); var cbuf = m_ShaderDetails.ConstantBlocks[i]; if (cbuf.variables.Length == 0) continue; disasm = FriendlyName(disasm, stem, "", cbuf.variables); } foreach (var r in m_ShaderDetails.Resources) { if (r.IsSRV) { var needle = string.Format(", t{0}([^0-9])", r.bindPoint); var replacement = string.Format(", {0}$1", r.name); Regex rgx = new Regex(needle); disasm = rgx.Replace(disasm, replacement); } if (r.IsSampler) { var needle = string.Format(", s{0}([^0-9])", r.bindPoint); var replacement = string.Format(", {0}$1", r.name); Regex rgx = new Regex(needle); disasm = rgx.Replace(disasm, replacement); } if (r.IsReadWrite) { var needle = string.Format(", u{0}([^0-9])", r.bindPoint); var replacement = string.Format(", {0}$1", r.name); Regex rgx = new Regex(needle); disasm = rgx.Replace(disasm, replacement); } } } { m_DisassemblyView = MakeEditor("scintillaDisassem", disasm, false); m_DisassemblyView.IsReadOnly = true; m_DisassemblyView.TabIndex = 0; m_DisassemblyView.KeyDown += new KeyEventHandler(m_DisassemblyView_KeyDown); m_DisassemblyView.KeyDown += new KeyEventHandler(readonlyScintilla_KeyDown); m_DisassemblyView.Markers[CURRENT_MARKER].BackColor = System.Drawing.Color.LightCoral; m_DisassemblyView.Markers[CURRENT_MARKER].Symbol = ScintillaNET.MarkerSymbol.Background; m_DisassemblyView.Markers[CURRENT_MARKER+1].BackColor = System.Drawing.Color.LightCoral; m_DisassemblyView.Markers[CURRENT_MARKER+1].Symbol = ScintillaNET.MarkerSymbol.ShortArrow; CurrentLineMarkers.Add(CURRENT_MARKER); CurrentLineMarkers.Add(CURRENT_MARKER+1); m_DisassemblyView.Markers[FINISHED_MARKER].BackColor = System.Drawing.Color.LightSlateGray; m_DisassemblyView.Markers[FINISHED_MARKER].Symbol = ScintillaNET.MarkerSymbol.Background; m_DisassemblyView.Markers[FINISHED_MARKER + 1].BackColor = System.Drawing.Color.LightSlateGray; m_DisassemblyView.Markers[FINISHED_MARKER + 1].Symbol = ScintillaNET.MarkerSymbol.RoundRectangle; FinishedMarkers.Add(FINISHED_MARKER); FinishedMarkers.Add(FINISHED_MARKER + 1); m_DisassemblyView.Markers[BREAKPOINT_MARKER].BackColor = System.Drawing.Color.Red; m_DisassemblyView.Markers[BREAKPOINT_MARKER].Symbol = ScintillaNET.MarkerSymbol.Background; m_DisassemblyView.Markers[BREAKPOINT_MARKER+1].BackColor = System.Drawing.Color.Red; m_DisassemblyView.Markers[BREAKPOINT_MARKER+1].Symbol = ScintillaNET.MarkerSymbol.Circle; BreakpointMarkers.Add(BREAKPOINT_MARKER); BreakpointMarkers.Add(BREAKPOINT_MARKER + 1); if (trace != null) { m_DisassemblyView.ContextMenu = AssemblyContextMenu(); m_DisassemblyView.MouseDown += new MouseEventHandler(contextMouseDown); } m_Scintillas.Add(m_DisassemblyView); var w = Helpers.WrapDockContent(dockPanel, m_DisassemblyView, "Disassembly"); w.DockState = DockState.Document; w.Show(); w.CloseButton = false; w.CloseButtonVisible = false; } if (shader.DebugInfo.entryFunc.Length > 0 && shader.DebugInfo.files.Length > 0) { if(trace != null) Text = String.Format("Debug {0}() - {1}", shader.DebugInfo.entryFunc, debugContext); else Text = String.Format("{0}()", shader.DebugInfo.entryFunc); int fileIdx = 0; DockContent sel = null; foreach (var f in shader.DebugInfo.files) { var name = f.BaseFilename; ScintillaNET.Scintilla scintilla1 = MakeEditor("scintilla" + name, f.filetext, true); scintilla1.IsReadOnly = true; scintilla1.Tag = name; scintilla1.KeyDown += new KeyEventHandler(readonlyScintilla_KeyDown); var w = Helpers.WrapDockContent(dockPanel, scintilla1, name); w.CloseButton = false; w.CloseButtonVisible = false; w.Show(dockPanel); m_Scintillas.Add(scintilla1); if (shader.DebugInfo.entryFile >= 0 && shader.DebugInfo.entryFile < shader.DebugInfo.files.Length) { if (fileIdx == shader.DebugInfo.entryFile) sel = w; } else if (f.filetext.Contains(shader.DebugInfo.entryFunc)) { sel = w; } fileIdx++; } if (shader.DebugInfo.files.Length > 2) AddFileList(); if (trace != null || sel == null) sel = (DockContent)m_DisassemblyView.Parent; sel.Show(); } m_FindAll = new FindAllDialog(FindAllFiles); m_FindAll.Hide(); ShowConstants(); ShowVariables(); ShowWatch(); ShowErrors(); editStrip.Visible = false; m_ErrorsDock.Hide(); if (trace == null) { debuggingStrip.Visible = false; m_ConstantsDock.Hide(); m_VariablesDock.Hide(); m_WatchDock.Hide(); var insig = Helpers.WrapDockContent(dockPanel, inSigBox); insig.CloseButton = insig.CloseButtonVisible = false; var outsig = Helpers.WrapDockContent(dockPanel, outSigBox); outsig.CloseButton = outsig.CloseButtonVisible = false; insig.Show(dockPanel, DockState.DockBottom); outsig.Show(insig.Pane, DockAlignment.Right, 0.5); foreach (var s in m_ShaderDetails.InputSig) { string name = s.varName.Length == 0 ? s.semanticName : String.Format("{0} ({1})", s.varName, s.semanticName); if (s.semanticName.Length == 0) name = s.varName; inSig.Nodes.Add(new object[] { name, s.semanticIndex, s.regIndex, s.TypeString, s.systemValue.ToString(), SigParameter.GetComponentString(s.regChannelMask), SigParameter.GetComponentString(s.channelUsedMask) }); } bool multipleStreams = false; for (int i = 0; i < m_ShaderDetails.OutputSig.Length; i++) { if (m_ShaderDetails.OutputSig[i].stream > 0) { multipleStreams = true; break; } } foreach (var s in m_ShaderDetails.OutputSig) { string name = s.varName.Length == 0 ? s.semanticName : String.Format("{0} ({1})", s.varName, s.semanticName); if (s.semanticName.Length == 0) name = s.varName; if(multipleStreams) name = String.Format("Stream {0} : {1}", s.stream, name); outSig.Nodes.Add(new object[] { name, s.semanticIndex, s.regIndex, s.TypeString, s.systemValue.ToString(), SigParameter.GetComponentString(s.regChannelMask), SigParameter.GetComponentString(s.channelUsedMask) }); } } else { inSigBox.Visible = false; outSigBox.Visible = false; m_DisassemblyView.Margins.Margin1.Width = 20; m_DisassemblyView.Margins.Margin2.Width = 0; m_DisassemblyView.Margins.Margin3.Width = 20; m_DisassemblyView.Margins.Margin3.IsMarkerMargin = true; m_DisassemblyView.Margins.Margin3.IsFoldMargin = false; m_DisassemblyView.Margins.Margin3.Type = ScintillaNET.MarginType.Symbol; m_DisassemblyView.Margins.Margin1.Mask = (int)m_DisassemblyView.Markers[BREAKPOINT_MARKER + 1].Mask; m_DisassemblyView.Margins.Margin3.Mask &= ~((int)m_DisassemblyView.Markers[BREAKPOINT_MARKER + 1].Mask); m_DisassemblyView.MouseMove += new MouseEventHandler(scintilla1_MouseMove); m_DisassemblyView.Leave += new EventHandler(scintilla1_Leave); m_DisassemblyView.KeyDown += new KeyEventHandler(scintilla1_DebuggingKeyDown); watchRegs.Items.Add(new ListViewItem(new string[] { "", "", "" })); } CurrentStep = 0; this.ResumeLayout(false); }
private void AddResourceRow(ShaderReflection shaderDetails, VulkanPipelineState.ShaderStage stage, int bindset, int bind, VulkanPipelineState.Pipeline pipe, TreelistView.TreeListView resources, FetchTexture[] texs, FetchBuffer[] bufs, ref Dictionary<ResourceId, SamplerData> samplers) { ShaderResource shaderRes = null; BindpointMap bindMap = null; bool isrw = false; uint bindPoint = 0; if (shaderDetails != null) { for (int i = 0; i < shaderDetails.ReadOnlyResources.Length; i++) { var ro = shaderDetails.ReadOnlyResources[i]; if (stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset == bindset && stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind == bind) { bindPoint = (uint)i; shaderRes = ro; bindMap = stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; } } for (int i = 0; i < shaderDetails.ReadWriteResources.Length; i++) { var rw = shaderDetails.ReadWriteResources[i]; if (stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset == bindset && stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind == bind) { bindPoint = (uint)i; isrw = true; shaderRes = rw; bindMap = stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; } } } VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement[] slotBinds = null; ShaderBindType bindType = ShaderBindType.Unknown; ShaderStageBits stageBits = (ShaderStageBits)0; if (bindset < pipe.DescSets.Length && bind < pipe.DescSets[bindset].bindings.Length) { slotBinds = pipe.DescSets[bindset].bindings[bind].binds; bindType = pipe.DescSets[bindset].bindings[bind].type; stageBits = pipe.DescSets[bindset].bindings[bind].stageFlags; } else { if (shaderRes.IsSampler) bindType = ShaderBindType.Sampler; else if (shaderRes.IsSampler && shaderRes.IsTexture) bindType = ShaderBindType.ImageSampler; else if (shaderRes.resType == ShaderResourceType.Buffer) bindType = ShaderBindType.ReadOnlyTBuffer; else bindType = ShaderBindType.ReadOnlyImage; } bool usedSlot = bindMap != null && bindMap.used; bool stageBitsIncluded = stageBits.HasFlag((ShaderStageBits)(1 << (int)stage.stage)); // skip descriptors that aren't for this shader stage if (!usedSlot && !stageBitsIncluded) return; if (bindType == ShaderBindType.ConstantBuffer) return; // TODO - check compatibility between bindType and shaderRes.resType ? // consider it filled if any array element is filled bool filledSlot = false; for (int idx = 0; slotBinds != null && idx < slotBinds.Length; idx++) { filledSlot |= slotBinds[idx].res != ResourceId.Null; if (bindType == ShaderBindType.Sampler || bindType == ShaderBindType.ImageSampler) filledSlot |= slotBinds[idx].sampler != ResourceId.Null; } // if it's masked out by stage bits, act as if it's not filled, so it's marked in red if (!stageBitsIncluded) filledSlot = false; // show if if (usedSlot || // it's referenced by the shader - regardless of empty or not (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled" (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty" ) { TreelistView.NodeCollection parentNodes = resources.Nodes; string setname = bindset.ToString(); string slotname = bind.ToString(); if (shaderRes != null && shaderRes.name.Length > 0) slotname += ": " + shaderRes.name; int arrayLength = 0; if (slotBinds != null) arrayLength = slotBinds.Length; else arrayLength = (int)bindMap.arraySize; // for arrays, add a parent element that we add the real cbuffers below if (arrayLength > 1) { var node = parentNodes.Add(new object[] { "", setname, slotname, String.Format("Array[{0}]", arrayLength), "", "", "", "" }); node.TreeColumn = 0; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); parentNodes = node.Nodes; } for (int idx = 0; idx < arrayLength; idx++) { VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement descriptorBind = null; if (slotBinds != null) descriptorBind = slotBinds[idx]; if (arrayLength > 1) { slotname = String.Format("{0}[{1}]", bind, idx); if (shaderRes != null && shaderRes.name.Length > 0) slotname += ": " + shaderRes.name; } bool isbuf = false; UInt32 w = 1, h = 1, d = 1; UInt32 a = 1; UInt32 samples = 1; UInt64 len = 0; string format = "Unknown"; string name = "Empty"; ShaderResourceType restype = ShaderResourceType.None; object tag = null; bool viewDetails = false; if (filledSlot && descriptorBind != null) { name = "Object " + descriptorBind.res.ToString(); format = descriptorBind.viewfmt.ToString(); // check to see if it's a texture for (int t = 0; t < texs.Length; t++) { if (texs[t].ID == descriptorBind.res) { w = texs[t].width; h = texs[t].height; d = texs[t].depth; a = texs[t].arraysize; name = texs[t].name; restype = texs[t].resType; samples = texs[t].msSamp; if (HasImportantViewParams(descriptorBind, texs[t])) viewDetails = true; tag = new ViewTexTag( descriptorBind.viewfmt, descriptorBind.baseMip, descriptorBind.baseLayer, descriptorBind.numMip, descriptorBind.numLayer, texs[t] ); } } // if not a texture, it must be a buffer for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == descriptorBind.res) { len = bufs[t].length; w = 0; h = 0; d = 0; a = 0; name = bufs[t].name; restype = ShaderResourceType.Buffer; ulong descriptorLen = descriptorBind.size; if(descriptorLen == ulong.MaxValue) descriptorLen = len - descriptorBind.offset; tag = new BufferResTag(isrw, bindPoint, bufs[t].ID, descriptorBind.offset, descriptorLen); if (HasImportantViewParams(descriptorBind, bufs[t])) viewDetails = true; isbuf = true; } } } else { name = "Empty"; format = "-"; w = h = d = a = 0; } TreelistView.Node node = null; if (bindType == ShaderBindType.ReadWriteBuffer || bindType == ShaderBindType.ReadOnlyTBuffer || bindType == ShaderBindType.ReadWriteTBuffer ) { if (!isbuf) { node = parentNodes.Add(new object[] { "", bindset, slotname, bindType, "-", "-", "", }); EmptyRow(node); } else { string range = "-"; if (descriptorBind != null) range = String.Format("{0} - {1}", descriptorBind.offset, descriptorBind.size); node = parentNodes.Add(new object[] { "", bindset, slotname, bindType, name, String.Format("{0} bytes", len), range, }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = tag; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); } } else if (bindType == ShaderBindType.Sampler) { if (descriptorBind == null || descriptorBind.sampler == ResourceId.Null) { node = parentNodes.Add(new object[] { "", bindset, slotname, bindType, "-", "-", "", }); EmptyRow(node); } else { node = parentNodes.Add(MakeSampler(bindset.ToString(), slotname, descriptorBind)); if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); var data = new SamplerData(node); node.Tag = data; if (!samplers.ContainsKey(descriptorBind.sampler)) samplers.Add(descriptorBind.sampler, data); } } else { if (descriptorBind == null || descriptorBind.res == ResourceId.Null) { node = parentNodes.Add(new object[] { "", bindset, slotname, bindType, "-", "-", "", }); EmptyRow(node); } else { string typename = restype.Str() + " " + bindType.Str().Replace("&", "&&"); string dim; if (restype == ShaderResourceType.Texture3D) dim = String.Format("{0}x{1}x{2}", w, h, d); else if (restype == ShaderResourceType.Texture1D || restype == ShaderResourceType.Texture1DArray) dim = w.ToString(); else dim = String.Format("{0}x{1}", w, h); if (descriptorBind.swizzle[0] != TextureSwizzle.Red || descriptorBind.swizzle[1] != TextureSwizzle.Green || descriptorBind.swizzle[2] != TextureSwizzle.Blue || descriptorBind.swizzle[3] != TextureSwizzle.Alpha) { format += String.Format(" swizzle[{0}{1}{2}{3}]", descriptorBind.swizzle[0].Str(), descriptorBind.swizzle[1].Str(), descriptorBind.swizzle[2].Str(), descriptorBind.swizzle[3].Str()); } if (restype == ShaderResourceType.Texture1DArray || restype == ShaderResourceType.Texture2DArray || restype == ShaderResourceType.Texture2DMSArray || restype == ShaderResourceType.TextureCubeArray) { dim += String.Format(" {0}[{1}]", restype.Str(), a); } if (restype == ShaderResourceType.Texture2DMS || restype == ShaderResourceType.Texture2DMSArray) dim += String.Format(", {0}x MSAA", samples); node = parentNodes.Add(new object[] { "", bindset, slotname, typename, name, dim, format, }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = tag; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); ViewDetailsRow(node, viewDetails); } if (bindType == ShaderBindType.ImageSampler) { if (descriptorBind == null || descriptorBind.sampler == ResourceId.Null) { node = parentNodes.Add(new object[] { "", bindset, slotname, bindType, "-", "-", "", }); EmptyRow(node); } else { var texnode = node; if (!samplers.ContainsKey(descriptorBind.sampler)) { node = parentNodes.Add(MakeSampler("", "", descriptorBind)); if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); var data = new SamplerData(node); node.Tag = data; samplers.Add(descriptorBind.sampler, data); } if (texnode != null) { m_CombinedImageSamplers[texnode] = samplers[descriptorBind.sampler].node; samplers[descriptorBind.sampler].images.Add(texnode); } } } } } } }
private void AddConstantBlockRow(ShaderReflection shaderDetails, VulkanPipelineState.ShaderStage stage, int bindset, int bind, VulkanPipelineState.Pipeline pipe, TreelistView.TreeListView cbuffers, FetchBuffer[] bufs) { ConstantBlock cblock = null; BindpointMap bindMap = null; uint slot = uint.MaxValue; if (shaderDetails != null) { for (slot = 0; slot < (uint)shaderDetails.ConstantBlocks.Length; slot++) { ConstantBlock cb = shaderDetails.ConstantBlocks[slot]; if (stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bindset == bindset && stage.BindpointMapping.ConstantBlocks[cb.bindPoint].bind == bind) { cblock = cb; bindMap = stage.BindpointMapping.ConstantBlocks[cb.bindPoint]; break; } } if (slot >= (uint)shaderDetails.ConstantBlocks.Length) slot = uint.MaxValue; } VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement[] slotBinds = null; ShaderBindType bindType = ShaderBindType.ConstantBuffer; ShaderStageBits stageBits = (ShaderStageBits)0; if (bindset < pipe.DescSets.Length && bind < pipe.DescSets[bindset].bindings.Length) { slotBinds = pipe.DescSets[bindset].bindings[bind].binds; bindType = pipe.DescSets[bindset].bindings[bind].type; stageBits = pipe.DescSets[bindset].bindings[bind].stageFlags; } bool usedSlot = bindMap != null && bindMap.used; bool stageBitsIncluded = stageBits.HasFlag((ShaderStageBits)(1 << (int)stage.stage)); // skip descriptors that aren't for this shader stage if (!usedSlot && !stageBitsIncluded) return; if (bindType != ShaderBindType.ConstantBuffer) return; // consider it filled if any array element is filled (or it's push constants) bool filledSlot = cblock != null && !cblock.bufferBacked; for (int idx = 0; slotBinds != null && idx < slotBinds.Length; idx++) filledSlot |= slotBinds[idx].res != ResourceId.Null; // if it's masked out by stage bits, act as if it's not filled, so it's marked in red if (!stageBitsIncluded) filledSlot = false; // show if if (usedSlot || // it's referenced by the shader - regardless of empty or not (showDisabled.Checked && !usedSlot && filledSlot) || // it's bound, but not referenced, and we have "show disabled" (showEmpty.Checked && !filledSlot) // it's empty, and we have "show empty" ) { TreelistView.NodeCollection parentNodes = cbuffers.Nodes; string setname = bindset.ToString(); string slotname = bind.ToString(); if (cblock != null && cblock.name.Length > 0) slotname += ": " + cblock.name; int arrayLength = 0; if (slotBinds != null) arrayLength = slotBinds.Length; else arrayLength = (int)bindMap.arraySize; // for arrays, add a parent element that we add the real cbuffers below if (arrayLength > 1) { var node = parentNodes.Add(new object[] { "", setname, slotname, String.Format("Array[{0}]", arrayLength), "", "" }); node.TreeColumn = 0; if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); parentNodes = node.Nodes; } for (int idx = 0; idx < arrayLength; idx++) { VulkanPipelineState.Pipeline.DescriptorSet.DescriptorBinding.BindingElement descriptorBind = null; if(slotBinds != null) descriptorBind = slotBinds[idx]; if (arrayLength > 1) { slotname = String.Format("{0}[{1}]", bind, idx); if (cblock != null && cblock.name.Length > 0) slotname += ": " + cblock.name; } string name = "Empty"; UInt64 length = 0; int numvars = cblock != null ? cblock.variables.Length : 0; UInt64 byteSize = cblock != null ? cblock.byteSize : 0; string vecrange = "-"; if (filledSlot && descriptorBind != null) { name = ""; length = descriptorBind.size; for (int t = 0; t < bufs.Length; t++) { if (bufs[t].ID == descriptorBind.res) { name = bufs[t].name; if(length == ulong.MaxValue) length = bufs[t].length - descriptorBind.offset; } } if (name == "") name = "UBO " + descriptorBind.res.ToString(); vecrange = String.Format("{0} - {1}", descriptorBind.offset, descriptorBind.offset + length); } string sizestr; // push constants or specialization constants if (cblock != null && !cblock.bufferBacked) { setname = ""; slotname = cblock.name; name = "Push constants"; vecrange = ""; sizestr = String.Format("{0} Variables", numvars); // could maybe get range from ShaderVariable.reg if it's filled out // from SPIR-V side. } else { if (length == byteSize) sizestr = String.Format("{0} Variables, {1} bytes", numvars, length); else sizestr = String.Format("{0} Variables, {1} bytes needed, {2} provided", numvars, byteSize, length); if (length < byteSize) filledSlot = false; } var node = parentNodes.Add(new object[] { "", setname, slotname, name, vecrange, sizestr }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; node.Tag = new CBufferTag(slot, (uint)idx); if (!filledSlot) EmptyRow(node); if (!usedSlot) InactiveRow(node); } } }