ImGuiNET / ImGui.NET

An ImGui wrapper for .NET.
MIT License
1.9k stars 305 forks source link

Having a problem with SharpDX #232

Closed BarisUckardes closed 3 years ago

BarisUckardes commented 3 years ago

I have been trying to implement a imgui solution for my SharpDX project and bumped along the way.

I checked the samples and made attempt according to those sample(s).

I get no errors if i invoke ImGui.ShowDemoWindow() but get nothing on my screen while i got an error if i try to display a text "Attempted to read or write protected memory"

Here is my code path

I start with initializing my ImGui renderer object like this

RImGuiRenderer uiRenderer = new RImGuiRenderer(device);
uiRenderer.Initialize();

this is my Initialize() method

 public void Initialize()
        {
            /*
             * Create and set context current
             */
            Resources.ContextPtr = ImGui.CreateContext();
            ImGui.SetCurrentContext(Resources.ContextPtr);

            /*
             * Cache font atlas and add default font
             */
            Resources.IO = ImGui.GetIO();
            Resources.FontAtlasPtr = Resources.IO.Fonts;
            Resources.FontAtlasPtr.AddFontDefault();

            /*
             * Create initial data
             */
            CreateRendererResources();
            SetKeyMappings();

            /*
             * Input delta
             */
            SetPerFrameData(1f / 60f);

            ImGui.NewFrame();

            _frameBegun = true;
        }

First my CreateRendererResources() method

 private void CreateRendererResources()
        {
            /*
             * Create shaders
             */
            Resources.ShaderGroup = new RShaderGroup();
            InputElement[] imguiVertexLayout = new InputElement[]
            {
                new InputElement()
                {
                    SemanticName = "POSITION",
                    SemanticIndex = 0,
                    Format =Format.R32G32_Float,
                    Slot = 0,
                    AlignedByteOffset = 0,
                    Classification = InputClassification.PerVertexData,
                    InstanceDataStepRate =0
                }
                ,
                new InputElement()
                {
                    SemanticName = "TEXCOORD",
                    SemanticIndex = 0,
                    Format =Format.R32G32_Float,
                    Slot = 0,
                    AlignedByteOffset = InputElement.AppendAligned,
                    Classification = InputClassification.PerVertexData,
                    InstanceDataStepRate =0
                }
                ,
                new InputElement()
                {
                    SemanticName = "COLOR",
                    SemanticIndex = 0,
                    Format =Format.R32G32B32A32_Float,
                    Slot = 0,
                    AlignedByteOffset = InputElement.AppendAligned,
                    Classification = InputClassification.PerVertexData,
                    InstanceDataStepRate =0
                }
            };

            /*
             * Load shaders from file
             */
            Resources.ShaderGroup.VertexShader = RImGuiShaderUtility.LoadImGuiVertexShaderFromFile(@"D:\REngine\EngineResources\ImGui\Renderer\Shaders\ImguiVertexShader.bvs", imguiVertexLayout);
            Resources.ShaderGroup.FragmentShader = RShaderFileUtility.LoadFragmentShaderFormFile(@"D:\REngine\EngineResources\ImGui\Renderer\Shaders\ImguiFragmentShader.bfs");

            /*
             * Create vertex&index buffer descriptions
             */
            BufferDescription vertexDesc = new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags  = CpuAccessFlags.Write,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = 10000,
                Usage = ResourceUsage.Dynamic

            };
            BufferDescription indexDesc = new BufferDescription()
            {
                BindFlags = BindFlags.IndexBuffer,
                CpuAccessFlags = CpuAccessFlags.Write,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = 2000,
                Usage = ResourceUsage.Dynamic
            };

            /*
             * Create buffers
             */
            Resources.VertexBuffer = new Buffer(Device.TargetDevice, vertexDesc);
            Resources.IndexBuffer = new Buffer(Device.TargetDevice, indexDesc);

            /*
             * Create constant buffer
             */
            BufferDescription constantBufferDesc = new BufferDescription()
            {
                Usage = ResourceUsage.Dynamic,
                SizeInBytes = 64,
                BindFlags = BindFlags.ConstantBuffer,
                CpuAccessFlags = CpuAccessFlags.Write,
                OptionFlags = ResourceOptionFlags.None,
                StructureByteStride = 0
            };

            Resources.ProjectionConstantBuffer = new Buffer(Device.TargetDevice, constantBufferDesc);
            /*
             * Create font texture data
             */
            RecreateFontDeviceTexture();
        }

Thus i create font texture using RecreateFontDeviceTexture() method

  private void RecreateFontDeviceTexture()
        {
            /*
             * Get Font texture
             */
            Resources.IO.Fonts.GetTexDataAsRGBA32(out IntPtr pixels, out int width, out int height, out int bytesPerPixel);

            /*
             * Create engine texture2D
             */
            Resources.FontTexture = RTexture2D.Create(width,height);

            /*
             * Update texture file
             */
            DataBox fontStream = Device.TargetContext.MapSubresource(Resources.FontTexture.Texture,0,MapMode.WriteDiscard,SharpDX.Direct3D11.MapFlags.None,out DataStream stream);
            stream.Write(pixels, 0, width * height);
            Device.TargetContext.UnmapSubresource(Resources.FontTexture.Texture,0);

            /*
             * Set texture (IS THIS HOW WO DO IT in sharpDX ????)
             */
            Resources.IO.Fonts.SetTexID((IntPtr)Resources.FontTexture.Texture);

            Resources.IO.Fonts.ClearTexData();

        }

How i create my FontTexture

public static RTexture2D CreateTexture(int w,int h)
        {
            RTexture2D tex = new RTexture2D();
            Texture2DDescription texDesc = new Texture2DDescription()
            {
                ArraySize = 1,
                CpuAccessFlags = CpuAccessFlags.Write,
                BindFlags = BindFlags.ShaderResource,
                Format = Format.R32G32B32A32_Float,
                Width = w,
                Height = h,
                MipLevels = 1,
                Usage = ResourceUsage.Dynamic,
                SampleDescription = new SampleDescription(1, 0)

            };
            Texture2D deviceTexture = new Texture2D(TargetDevice.TargetDevice, texDesc);
            ShaderResourceViewDescription resourceViewDescription = new ShaderResourceViewDescription()
            {
                Format = deviceTexture.Description.Format,
                Dimension = ShaderResourceViewDimension.Texture2D,

            };
            resourceViewDescription.Texture2D.MostDetailedMip = 0;
            resourceViewDescription.Texture2D.MipLevels = 1;

            ShaderResourceView resourceView = new ShaderResourceView(TargetDevice.TargetDevice, deviceTexture, resourceViewDescription);
            TargetDevice.TargetContext.GenerateMips(resourceView);

            /*
             * Create sampler state
             */
            SamplerStateDescription samplerDescription = new SamplerStateDescription()
            {
                Filter = Filter.MinMagMipLinear,
                AddressU = TextureAddressMode.Wrap,
                AddressV = TextureAddressMode.Wrap,
                AddressW = TextureAddressMode.Wrap,
                MipLodBias = 0,
                MaximumAnisotropy = 1,
                ComparisonFunction = Comparison.Always,
                BorderColor = new SharpDX.Mathematics.Interop.RawColor4(0, 0, 0, 0),
                MinimumLod = 0,
                MaximumLod = float.MaxValue

            };

            /*
             * Create texture object
             */
            RTexture2D rTexture = new RTexture2D();
            rTexture.Resource = resourceView;
            rTexture.Texture = deviceTexture;
            rTexture.SamplerState = new SamplerState(TargetDevice.TargetDevice, samplerDescription);

            return rTexture;
        }

In case of you are wondering key mapping

 private void SetKeyMappings()
        {
            ImGuiIOPtr io = ImGui.GetIO();
            io.KeyMap[(int)ImGuiKey.Tab] = (int)Keys.Tab;
            io.KeyMap[(int)ImGuiKey.LeftArrow] = (int)Keys.Left;
            io.KeyMap[(int)ImGuiKey.RightArrow] = (int)Keys.Right;
            io.KeyMap[(int)ImGuiKey.UpArrow] = (int)Keys.Up;
            io.KeyMap[(int)ImGuiKey.DownArrow] = (int)Keys.Down;
            io.KeyMap[(int)ImGuiKey.PageUp] = (int)Keys.PageUp;
            io.KeyMap[(int)ImGuiKey.PageDown] = (int)Keys.PageDown;
            io.KeyMap[(int)ImGuiKey.Home] = (int)Keys.Home;
            io.KeyMap[(int)ImGuiKey.End] = (int)Keys.End;
            io.KeyMap[(int)ImGuiKey.Delete] = (int)Keys.Delete;
            io.KeyMap[(int)ImGuiKey.Backspace] = (int)Keys.Back;
            io.KeyMap[(int)ImGuiKey.Enter] = (int)Keys.Enter;
            io.KeyMap[(int)ImGuiKey.Escape] = (int)Keys.Escape;
            io.KeyMap[(int)ImGuiKey.A] = (int)Keys.A;
            io.KeyMap[(int)ImGuiKey.C] = (int)Keys.C;
            io.KeyMap[(int)ImGuiKey.V] = (int)Keys.V;
            io.KeyMap[(int)ImGuiKey.X] = (int)Keys.X;
            io.KeyMap[(int)ImGuiKey.Y] = (int)Keys.Y;
            io.KeyMap[(int)ImGuiKey.Z] = (int)Keys.Z;
        }

Finally my render method RenderUIData

private void RenderUIData(ImDrawDataPtr dataPtr)
        {
            if(dataPtr.CmdListsCount == 0)
            {
                return;
            }

            Matrix4x4 mvp = Matrix4x4.CreateOrthographicOffCenter(
                0f,
                Resources.IO.DisplaySize.X,
                Resources.IO.DisplaySize.Y,
                0f,
                -1.0f,
                1.0f);

            Device.TargetContext.VertexShader.Set(Resources.ShaderGroup.VertexShader.Shader);
            Device.TargetContext.PixelShader.Set(Resources.ShaderGroup.FragmentShader.Shader);

            DataStream mvpResources;
            Device.TargetContext.MapSubresource(Resources.ProjectionConstantBuffer, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out mvpResources);
            mvpResources.Write(mvp);
            Device.TargetContext.UnmapSubresource(Resources.ProjectionConstantBuffer, 0);

            Device.TargetContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(Resources.VertexBuffer, 32, 0));
            Device.TargetContext.InputAssembler.SetIndexBuffer(Resources.IndexBuffer, Format.R32_UInt, 0);
            Device.TargetContext.InputAssembler.InputLayout = Resources.ShaderGroup.VertexShader.VertexLayout;

            Device.TargetContext.VertexShader.SetConstantBuffer(0, Resources.ProjectionConstantBuffer);
            Device.TargetContext.PixelShader.SetShaderResource(0, Resources.FontTexture.Resource);
            Device.TargetContext.PixelShader.SetSampler(0, Resources.FontTexture.SamplerState);

            dataPtr.ScaleClipRects(Resources.IO.DisplayFramebufferScale);

            for (int i = 0; i < dataPtr.CmdListsCount; i++)
            {
                ImDrawListPtr commandList = dataPtr.CmdListsRange[i];

                /*
                 * Update vertex data
                 */
                DataStream vertexStream;
                Device.TargetContext.MapSubresource(Resources.VertexBuffer, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out vertexStream);
                vertexStream.Write(commandList.VtxBuffer);
                Device.TargetContext.UnmapSubresource(Resources.VertexBuffer, 0);

                /*
                 * Update index data
                 */

                DataStream indexStream;
                Device.TargetContext.MapSubresource(Resources.IndexBuffer, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None, out indexStream);
                indexStream.Write(commandList.IdxBuffer);
                Device.TargetContext.UnmapSubresource(Resources.IndexBuffer, 0);

                for (int p = 0; p < commandList.CmdBuffer.Size; p++)
                {
                    ImDrawCmdPtr commandPtr = commandList.CmdBuffer[p];

                    if(commandPtr.UserCallback != IntPtr.Zero)
                    {
                        throw new NotImplementedException();
                    }
                    else
                    {
                        Device.TargetContext.DrawIndexed((int)commandPtr.ElemCount, 0, 0);
                        RConsoleLog.DropLog("ImGui Triangle Count  : " + commandPtr.ElemCount.ToString());
                    }
                }
            }
        }

Here's some findings

mellinoe commented 3 years ago

That's a ton of code there, so I won't be able to read through all of it to find the exact issue. However, I do notice that you have declared the third vertex element incorrectly. imgui uses a single packed 32-bit RGBA color format for the third vertex element, not a 4-float format. This alone is likely screwing up all of your vertex data when you go to render it. Apart from that, there is a similar issue in your texture creation -- you are using the wrong texture format. These details are a little tricky to get right.

If you would like to build a D3D11-based renderer yourself, I'd suggest basing it off the official D3D11 renderer in the imgui repo. For instance, here is the part where vertex inputs are described. Given how close SharpDX is to native D3D11, it should be fairly simple to copy the C++ implementation and slowly adapt it into normal C#.

BarisUckardes commented 3 years ago

Oh boy,i forgot this post even existing. I moved on from SharpDX,currently using OpenTKdue to SharpDXis abandoned. Thanks for input but i no longer require it, however you recently helped me with this https://github.com/mellinoe/ImGui.NET/issues/239 .You can see i try to find my way through OpenTKand ImGui.Net

So this issue is satisfied