public BufferFormatSpecifier(BufferViewer viewer, ResourceId buff, string format)
        {
            InitializeComponent();

            // WHY THE HELL do you require \r\n in text boxes?
            formatText.Text = format.Replace("\r\n", "\n").Replace("\n", Environment.NewLine);

            m_Viewer = viewer;
            m_Buffer = buff;
        }
Example #2
0
        public BufferViewer GetMeshViewer()
        {
            if (m_MeshViewer == null || m_MeshViewer.IsDisposed)
            {
                m_MeshViewer = new BufferViewer(this, true);
                AddLogViewer(m_MeshViewer);
            }

            return(m_MeshViewer);
        }
        public BufferFormatSpecifier(BufferViewer viewer, ResourceId buff, string format)
        {
            InitializeComponent();

            // WHY THE HELL do you require \r\n in text boxes?
            formatText.Text = format.Replace("\r\n", "\n").Replace("\n", Environment.NewLine);

            m_Viewer = viewer;
            m_Buffer = buff;
        }
Example #4
0
        static void Main(string[] args)
        {
            int buffSize = 300;
            var buffer   = new ushort[buffSize];

            for (int index = 0; index < buffSize; index++)
            {
                buffer[index] = (ushort)index;
            }
            var viewr = new BufferViewer();

            viewr.ShowBuff(buffer);
        }
Example #5
0
        private void iabuffers_NodeDoubleClicked(TreelistView.Node node)
        {
            if (node.Tag is ResourceId)
            {
                ResourceId id = (ResourceId)node.Tag;

                if (id != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(id);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            D3D11PipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            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;

                if (tex.resType == ShaderResourceType.Buffer)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(false, view.FirstElement, view.NumElements*view.ElementSize, tex.ID);
                    viewer.Show(m_DockContent.DockPanel);
                }
                else
                {
                    var viewer = m_Core.GetTextureViewer();
                    viewer.Show(m_DockContent.DockPanel);
                    if (!viewer.IsDisposed)
                        viewer.ViewTexture(tex.ID, true);
                }
            }
            else if(tag is FetchBuffer)
            {
                FetchBuffer buf = (FetchBuffer)tag;

                string format = "";

                var deets = stage.ShaderDetails;

                int bind = -1;
                bool uav = false;

                for (int i = 0; i < stage.SRVs.Length; i++)
                {
                    if (stage.SRVs[i].Resource == buf.ID)
                    {
                        bind = i;
                        view = stage.SRVs[i];
                        break;
                    }
                }

                for (int i = 0; i < stage.UAVs.Length; i++)
                {
                    if (stage.UAVs[i].Resource == buf.ID)
                    {
                        bind = i;
                        uav = true;
                        view = stage.UAVs[i];
                        break;
                    }
                    if (stage == m_Core.CurD3D11PipelineState.m_PS &&
                        m_Core.CurD3D11PipelineState.m_OM.UAVs[i].Resource == buf.ID)
                    {
                        bind = i + (int)m_Core.CurD3D11PipelineState.m_OM.UAVStartSlot;
                        uav = true;
                        view = m_Core.CurD3D11PipelineState.m_OM.UAVs[i];
                        break;
                    }
                }

                if (deets != null)
                {
                    ShaderResource[] resources = uav ? deets.ReadWriteResources : deets.ReadOnlyResources;
                    foreach (var r in resources)
                    {
                        if (r.IsTexture)
                            continue;

                        if (r.bindPoint == bind)
                        {
                            if (r.variableType.members.Length == 0)
                            {
                                if (view != null)
                                {
                                    if (view.Format.special && view.Format.specialFormat == SpecialFormat.R10G10B10A2)
                                    {
                                        if (view.Format.compType == FormatComponentType.UInt) format = "uintten";
                                        if (view.Format.compType == FormatComponentType.UNorm) format = "unormten";
                                    }
                                    else if (!view.Format.special)
                                    {
                                        switch (view.Format.compByteWidth)
                                        {
                                            case 1:
                                            {
                                                if (view.Format.compType == FormatComponentType.UNorm) format = "unormb";
                                                if (view.Format.compType == FormatComponentType.SNorm) format = "snormb";
                                                if (view.Format.compType == FormatComponentType.UInt) format = "ubyte";
                                                if (view.Format.compType == FormatComponentType.SInt) format = "byte";
                                                break;
                                            }
                                            case 2:
                                            {
                                                if (view.Format.compType == FormatComponentType.UNorm) format = "unormh";
                                                if (view.Format.compType == FormatComponentType.SNorm) format = "snormh";
                                                if (view.Format.compType == FormatComponentType.UInt) format = "ushort";
                                                if (view.Format.compType == FormatComponentType.SInt) format = "short";
                                                if (view.Format.compType == FormatComponentType.Float) format = "half";
                                                break;
                                            }
                                            case 4:
                                            {
                                                if (view.Format.compType == FormatComponentType.UNorm) format = "unormf";
                                                if (view.Format.compType == FormatComponentType.SNorm) format = "snormf";
                                                if (view.Format.compType == FormatComponentType.UInt) format = "uint";
                                                if (view.Format.compType == FormatComponentType.SInt) format = "int";
                                                if (view.Format.compType == FormatComponentType.Float) format = "float";
                                                break;
                                            }
                                        }

                                        if (view.Flags.HasFlag(D3D11BufferViewFlags.Raw))
                                            format = "xint";

                                        format += view.Format.compCount;
                                    }
                                }

                                // if view format is unknown, use the variable type
                                if (!view.Format.special && view.Format.compCount == 0 &&
                                    view.Format.compByteWidth == 0 && r.variableType.Name.Length > 0)
                                    format = r.variableType.Name;

                                format += " " + r.name + ";";
                            }
                            else
                            {
                                format = "// struct " + r.variableType.Name + Environment.NewLine +
                                            "{" + Environment.NewLine + FormatMembers(1, "", r.variableType.members) + "}";
                            }
                            break;
                        }
                    }
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    if (format.Length == 0)
                        viewer.ViewRawBuffer(true, view.FirstElement * view.ElementSize, view.NumElements * view.ElementSize, buf.ID);
                    else
                        viewer.ViewRawBuffer(true, view.FirstElement * view.ElementSize, view.NumElements * view.ElementSize, buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        private void ShowCBuffer(D3D11PipelineState.ShaderStage stage, UInt32 slot)
        {
            if (stage.ShaderDetails != null &&
                (stage.ShaderDetails.ConstantBlocks.Length <= slot ||
                 stage.ShaderDetails.ConstantBlocks[slot].name.Length == 0)
               )
            {
                // unused cbuffer, open regular buffer viewer
                var viewer = new BufferViewer(m_Core, false);

                if (stage.ConstantBuffers.Length < slot)
                    return;

                var buf = stage.ConstantBuffers[slot];
                viewer.ViewRawBuffer(true, buf.VecOffset * 4 * sizeof(float), buf.VecCount * 4 * sizeof(float), buf.Buffer);
                viewer.Show(m_DockContent.DockPanel);

                return;
            }

            var existing = ConstantBufferPreviewer.Has(stage.stage, slot, 0);
            if (existing != null)
            {
                existing.Show();
                return;
            }

            var prev = new ConstantBufferPreviewer(m_Core, stage.stage, slot, 0);

            prev.ShowDock(m_DockContent.Pane, DockAlignment.Right, 0.3);
        }
        private void iabuffers_NodeDoubleClicked(TreelistView.Node node)
        {
            if (node.Tag is IABufferTag)
            {
                IABufferTag tag = (IABufferTag)node.Tag;

                if (tag.id != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(true, tag.offset, ulong.MaxValue, tag.id);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        private void iabuffers_NodeDoubleClicked(TreelistView.Node node)
        {
            if (node.Tag is ResourceId)
            {
                ResourceId id = (ResourceId)node.Tag;

                if (id != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(true, id);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            GLPipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            if (stage == null) return;

            if (tag is FetchTexture)
            {
                FetchTexture tex = (FetchTexture)tag;

                if (tex.resType == ShaderResourceType.Buffer)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(false, tex.ID);
                    viewer.Show(m_DockContent.DockPanel);
                }
                else
                {
                    var viewer = m_Core.GetTextureViewer();
                    viewer.Show(m_DockContent.DockPanel);
                    if (!viewer.IsDisposed)
                        viewer.ViewTexture(tex.ID, true);
                }
            }
            else if(tag is ReadWriteTag)
            {
                ReadWriteTag rwtag = (ReadWriteTag)tag;
                FetchBuffer buf = rwtag.buf;

                string format = "";

                var deets = stage.ShaderDetails;

                ShaderResource r = deets.Resources[rwtag.idx];

                if (deets != null)
                {
                    if (r.variableType.members.Length == 0)
                    {
                        if (format == "" && r.variableType.Name.Length > 0)
                            format = r.variableType.Name + " " + r.name + ";";
                    }
                    else
                    {
                        format = FormatMembers(0, "", r.variableType.members);
                    }
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    if (format.Length == 0)
                        viewer.ViewRawBuffer(true, buf.ID);
                    else
                        viewer.ViewRawBuffer(true, buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            D3D11PipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            if (stage == null) return;

            if (tag is FetchTexture)
            {
                FetchTexture tex = (FetchTexture)tag;

                var viewer = m_Core.GetTextureViewer();

                viewer.Show(m_DockContent.DockPanel);
                if (!viewer.IsDisposed)
                    viewer.ViewTexture(tex.ID, true);
            }
            else if(tag is FetchBuffer)
            {
                FetchBuffer buf = (FetchBuffer)tag;

                string format = "";

                var deets = stage.ShaderDetails;

                int bind = -1;
                bool uav = false;

                for (int i = 0; i < stage.SRVs.Length; i++)
                {
                    if (stage.SRVs[i].Resource == buf.ID)
                    {
                        bind = i;
                        break;
                    }
                }

                for (int i = 0; i < stage.UAVs.Length; i++)
                {
                    if (stage.UAVs[i].Resource == buf.ID)
                    {
                        bind = i;
                        uav = true;
                        break;
                    }
                    if (stage == m_Core.CurD3D11PipelineState.m_PS &&
                        m_Core.CurD3D11PipelineState.m_OM.UAVs[i].Resource == buf.ID)
                    {
                        bind = i + (int)m_Core.CurD3D11PipelineState.m_OM.UAVStartSlot;
                        uav = true;
                        break;
                    }
                }

                if (deets != null)
                {
                    foreach (var r in deets.Resources)
                    {
                        if(r.IsTexture)
                            continue;

                        if ( (r.IsSRV && !uav) || (r.IsUAV && uav) )
                        {
                            if (r.bindPoint == bind)
                            {
                                if (r.variableType.members.Length == 0)
                                {
                                    if (r.variableType.Name != "")
                                        format = r.variableType.Name + " " + r.name + ";";
                                }
                                else
                                {
                                    format = "// struct " + r.variableType.Name + Environment.NewLine +
                                                "{" + Environment.NewLine + FormatMembers(1, "", r.variableType.members) + "}";
                                }
                                break;
                            }
                        }
                    }
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    if (format == "")
                        viewer.ViewRawBuffer(buf.ID);
                    else
                        viewer.ViewRawBuffer(buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        private void ShowCBuffer(D3D11PipelineState.ShaderStage stage, UInt32 bindPoint)
        {
            bool found = false;
            UInt32 slot = UInt32.MaxValue;

            if (stage.ShaderDetails != null)
            {
                UInt32 i = 0;
                foreach (var cb in stage.ShaderDetails.ConstantBlocks)
                {
                    if (cb.bindPoint == bindPoint)
                    {
                        slot = i;
                        found = true;
                        break;
                    }

                    i++;
                }
            }

            if (!found)
            {
                // unused cbuffer, open regular buffer viewer
                var viewer = new BufferViewer(m_Core, false);

                if (stage.ConstantBuffers.Length < bindPoint)
                    return;

                var buf = stage.ConstantBuffers[bindPoint];
                viewer.ViewRawBuffer(true, buf.VecOffset * 4 * sizeof(float), buf.VecCount * 4 * sizeof(float), buf.Buffer);
                viewer.Show(m_DockContent.DockPanel);

                return;
            }

            var existing = ConstantBufferPreviewer.Has(stage.stage, slot, 0);
            if (existing != null)
            {
                existing.Show();
                return;
            }

            var prev = new ConstantBufferPreviewer(m_Core, stage.stage, slot, 0);

            prev.ShowDock(m_DockContent.Pane, DockAlignment.Right, 0.3);
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            VulkanPipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            if (stage == null) return;

            if (tag is ViewTexTag)
                tag = (tag as ViewTexTag).tex;

            if (tag is FetchTexture)
            {
                FetchTexture tex = (FetchTexture)tag;

                if (tex.resType == ShaderResourceType.Buffer)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(false, 0, ulong.MaxValue, tex.ID);
                    viewer.Show(m_DockContent.DockPanel);
                }
                else
                {
                    var viewer = m_Core.GetTextureViewer();
                    viewer.Show(m_DockContent.DockPanel);
                    if (!viewer.IsDisposed)
                        viewer.ViewTexture(tex.ID, true);
                }
            }
            else if (tag is BufferResTag)
            {
                BufferResTag buf = (BufferResTag)tag;

                ShaderResource shaderRes = buf.rwRes
                    ? stage.ShaderDetails.ReadWriteResources[buf.bindPoint]
                    : stage.ShaderDetails.ReadOnlyResources[buf.bindPoint];

                string format = "// struct " + shaderRes.variableType.Name + Environment.NewLine;

                if (shaderRes.variableType.members.Length > 1)
                {
                    format += "// members skipped as they are fixed size:" + Environment.NewLine;
                    for (int i = 0; i < shaderRes.variableType.members.Length - 1; i++)
                    {
                        format += shaderRes.variableType.members[i].type.descriptor.name + " " + shaderRes.variableType.members[i].name + ";" + Environment.NewLine;
                    }
                }

                if (shaderRes.variableType.members.Length > 0)
                {
                    format += "{" + Environment.NewLine + FormatMembers(1, "", shaderRes.variableType.members.Last().type.members) + "}";
                }
                else
                {
                    var desc = shaderRes.variableType.descriptor;

                    format = "";
                    if (desc.rowMajorStorage)
                        format += "row_major ";

                    format += desc.type.Str();
                    if (desc.rows > 1 && desc.cols > 1)
                        format += String.Format("{0}x{1}", desc.rows, desc.cols);
                    else if (desc.cols > 1)
                        format += desc.cols;

                    if (desc.name.Length > 0)
                        format += " " + desc.name;

                    if (desc.elements > 1)
                        format += String.Format("[{0}]", desc.elements);
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(true, buf.offset, buf.size, buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            D3D12PipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            if (stage == null) return;

            D3D12PipelineState.ResourceView view = null;
            ShaderResource shaderResource = null;
            bool uav = false;

            ViewTexTag texTag = tag as ViewTexTag;
            ViewBufTag bufTag = tag as ViewBufTag;

            if (texTag != null)
            {
                view = texTag.view;
                uav = texTag.uav;
                shaderResource = texTag.res;

                FetchTexture tex = texTag.tex;

                if (tex.resType == ShaderResourceType.Buffer)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(false, view.FirstElement, view.NumElements*view.ElementSize, tex.ID);
                    viewer.Show(m_DockContent.DockPanel);
                }
                else
                {
                    var viewer = m_Core.GetTextureViewer();
                    viewer.Show(m_DockContent.DockPanel);
                    if (!viewer.IsDisposed)
                        viewer.ViewTexture(tex.ID, true);
                }
            }
            else if(bufTag != null)
            {
                view = bufTag.view;
                uav = bufTag.uav;
                shaderResource = bufTag.res;

                FetchBuffer buf = bufTag.buf;

                string format = "";

                ulong offs = 0;
                ulong size = buf.length;

                if (view != null)
                {
                    offs = view.FirstElement * view.ElementSize;
                    size = view.NumElements * view.ElementSize;
                }
                else
                {
                    // last thing, see if it's a streamout buffer

                    if (stage == m_Core.CurD3D12PipelineState.m_GS)
                    {
                        for(int i=0; i < m_Core.CurD3D12PipelineState.m_SO.Outputs.Length; i++)
                        {
                            if(buf.ID == m_Core.CurD3D12PipelineState.m_SO.Outputs[i].Buffer)
                            {
                                size -= m_Core.CurD3D12PipelineState.m_SO.Outputs[i].Offset;
                                offs += m_Core.CurD3D12PipelineState.m_SO.Outputs[i].Offset;
                                break;
                            }
                        }
                    }
                }

                if (shaderResource != null)
                {
                    if (shaderResource.variableType.members.Length == 0)
                    {
                        if (view != null)
                        {
                            if (view.Format.special && view.Format.specialFormat == SpecialFormat.R10G10B10A2)
                            {
                                if (view.Format.compType == FormatComponentType.UInt) format = "uintten";
                                if (view.Format.compType == FormatComponentType.UNorm) format = "unormten";
                            }
                            else if (!view.Format.special)
                            {
                                switch (view.Format.compByteWidth)
                                {
                                    case 1:
                                        {
                                            if (view.Format.compType == FormatComponentType.UNorm) format = "unormb";
                                            if (view.Format.compType == FormatComponentType.SNorm) format = "snormb";
                                            if (view.Format.compType == FormatComponentType.UInt) format = "ubyte";
                                            if (view.Format.compType == FormatComponentType.SInt) format = "byte";
                                            break;
                                        }
                                    case 2:
                                        {
                                            if (view.Format.compType == FormatComponentType.UNorm) format = "unormh";
                                            if (view.Format.compType == FormatComponentType.SNorm) format = "snormh";
                                            if (view.Format.compType == FormatComponentType.UInt) format = "ushort";
                                            if (view.Format.compType == FormatComponentType.SInt) format = "short";
                                            if (view.Format.compType == FormatComponentType.Float) format = "half";
                                            break;
                                        }
                                    case 4:
                                        {
                                            if (view.Format.compType == FormatComponentType.UNorm) format = "unormf";
                                            if (view.Format.compType == FormatComponentType.SNorm) format = "snormf";
                                            if (view.Format.compType == FormatComponentType.UInt) format = "uint";
                                            if (view.Format.compType == FormatComponentType.SInt) format = "int";
                                            if (view.Format.compType == FormatComponentType.Float) format = "float";
                                            break;
                                        }
                                }

                                if (view.BufferFlags.HasFlag(D3DBufferViewFlags.Raw))
                                    format = "xint";

                                format += view.Format.compCount;
                            }
                        }

                        // if view format is unknown, use the variable type
                        if (!view.Format.special && view.Format.compCount == 0 &&
                            view.Format.compByteWidth == 0 && shaderResource.variableType.Name.Length > 0)
                            format = shaderResource.variableType.Name;

                        format += " " + shaderResource.name + ";";
                    }
                    else
                    {
                        format = "// struct " + shaderResource.variableType.Name + Environment.NewLine +
                                    "{" + Environment.NewLine + FormatMembers(1, "", shaderResource.variableType.members) + "}";
                    }
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    if (format.Length == 0)
                        viewer.ViewRawBuffer(true, offs, size, buf.ID);
                    else
                        viewer.ViewRawBuffer(true, offs, size, buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }
        private void ShowCBuffer(D3D12PipelineState.ShaderStage stage, CBufTag tag)
        {
            if (tag.idx == uint.MaxValue)
            {
                // unused cbuffer, open regular buffer viewer
                var viewer = new BufferViewer(m_Core, false);

                var buf = stage.Spaces[tag.space].ConstantBuffers[tag.reg];
                viewer.ViewRawBuffer(true, buf.Offset, buf.ByteSize, buf.Buffer);
                viewer.Show(m_DockContent.DockPanel);

                return;
            }

            var existing = ConstantBufferPreviewer.Has(stage.stage, tag.idx, 0);
            if (existing != null)
            {
                existing.Show();
                return;
            }

            var prev = new ConstantBufferPreviewer(m_Core, stage.stage, tag.idx, 0);

            prev.ShowDock(m_DockContent.Pane, DockAlignment.Right, 0.3);
        }
        // launch the appropriate kind of viewer, depending on the type of resource that's in this node
        private void textureCell_CellDoubleClick(TreelistView.Node node)
        {
            object tag = node.Tag;

            GLPipelineState.ShaderStage stage = GetStageForSender(node.OwnerView);

            if (stage == null) return;

            if (tag is FetchTexture)
            {
                FetchTexture tex = (FetchTexture)tag;

                if (tex.resType == ShaderResourceType.Buffer)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    viewer.ViewRawBuffer(false, 0, ulong.MaxValue, tex.ID);
                    viewer.Show(m_DockContent.DockPanel);
                }
                else
                {
                    var viewer = m_Core.GetTextureViewer();
                    viewer.Show(m_DockContent.DockPanel);
                    if (!viewer.IsDisposed)
                        viewer.ViewTexture(tex.ID, true);
                }
            }
            else if (tag is FetchBuffer)
            {
                FetchBuffer buf = (FetchBuffer)tag;

                var viewer = new BufferViewer(m_Core, false);
                viewer.ViewRawBuffer(true, 0, ulong.MaxValue, buf.ID);
                viewer.Show(m_DockContent.DockPanel);
            }
            else if (tag is ReadWriteTag)
            {
                ReadWriteTag rwtag = (ReadWriteTag)tag;
                FetchBuffer buf = rwtag.buf;

                string format = "";

                var deets = stage.ShaderDetails;

                ShaderResource r = deets.ReadWriteResources[rwtag.idx];
                var bindpoint = stage.BindpointMapping.ReadWriteResources[rwtag.idx];

                GLReadWriteType readWriteType = GetGLReadWriteType(r);

                ulong offset = 0;
                ulong size = ulong.MaxValue;
                if (readWriteType == GLReadWriteType.SSBO)
                {
                    offset = m_Core.CurGLPipelineState.ShaderStorageBuffers[bindpoint.bind].Offset;
                    size = m_Core.CurGLPipelineState.ShaderStorageBuffers[bindpoint.bind].Size;
                }
                if (readWriteType == GLReadWriteType.Atomic)
                {
                    offset = m_Core.CurGLPipelineState.AtomicBuffers[bindpoint.bind].Offset;
                    size = m_Core.CurGLPipelineState.AtomicBuffers[bindpoint.bind].Size;
                }

                if (deets != null)
                {
                    if (r.variableType.members.Length == 0)
                    {
                        if (format == "" && r.variableType.Name.Length > 0)
                            format = r.variableType.Name + " " + r.name + ";";
                    }
                    else
                    {
                        format = FormatMembers(0, "", r.variableType.members);
                    }
                }

                if (buf.ID != ResourceId.Null)
                {
                    var viewer = new BufferViewer(m_Core, false);
                    if (format.Length == 0)
                        viewer.ViewRawBuffer(true, offset, size, buf.ID);
                    else
                        viewer.ViewRawBuffer(true, offset, size, buf.ID, format);
                    viewer.Show(m_DockContent.DockPanel);
                }
            }
        }