sharpdx / SharpDX

SharpDX GitHub Repository
http://sharpdx.org
MIT License
1.7k stars 639 forks source link

Memory Leak on WPF window size change event #826

Open insinfo opened 7 years ago

insinfo commented 7 years ago

I have created a WPF application on windows 10 64bit to test Direct2D and find out about this scenario. It is terrible because I wanted to use Direct2D to speed up the drawings on the canvas. With this bug, it is impossible, Just keep modifying the size of the window so the memory usage goes up absurdly. I saw that the problem is related to the dispose, it seems that the resources are not being destroyed.

Direct3D11Texture2D.Dispose ();              Direct3D11Texture2D = Null;              DXGISurface.Dispose ();              DXGISurface = null;              Direct2D1Factory.Dispose ();              Direct2D1Factory = null;              Direct2D1RenderTarget.Dispose ();              Direct2D1RenderTarget = null;

memory leak on wpf window size change event

xoofx commented 7 years ago

You have most likely allocations elsewhere un your program, where you don't release objects. You can try to diagnostic that by tweaking Configuration.EnableObjectTracking with ObjectTracker

insinfo commented 7 years ago

This is my code


using System;
using System.Collections.Generic;
using System.Windows.Interop;
using System.Windows;

//SharpDX
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;

namespace UIDesign
{
    class D2DCanvas : System.Windows.Controls.Grid
    {
        private SharpDX.Direct3D11.Device Direct3D11Device;
        private SharpDX.Direct3D11.Texture2D Direct3D11Texture2D;
        private SharpDX.Direct2D1.RenderTarget Direct2D1RenderTarget;
        private SharpDX.Direct2D1.Factory Direct2D1Factory;
        private SharpDX.Direct3D11.Texture2DDescription Direct3D11Texture2DDescription;
        private SharpDX.DXGI.Surface DXGISurface;
        private SharpDX.Direct2D1.PixelFormat Direct2D1PixelFormat;
        private SharpDX.Direct2D1.RenderTargetProperties Direct2D1RenderTargetProperties;
        private RawRectangleF rect;      

        private SharpDX.Direct3D9.DeviceEx Direct3D9DeviceEx;
        private SharpDX.Direct3D9.Texture Direct3D9Texture;
        private SharpDX.Direct3D9.Surface Direct3D9Surface;
        private SharpDX.Direct3D9.Direct3DEx D3DContext;
        private SharpDX.Direct3D9.PresentParameters presentParams;
        private SharpDX.Direct3D9.CreateFlags createFlags;
        private SharpDX.Direct3D9.Format direct3D9Format;
        private IntPtr sharedHandle;
        private D3DImage d3DImageSource;       
        private int textureWidth;
        private int textureHeight;

        private System.Windows.Controls.Image imageControl;

        public List<Element> ElementCollection;

        public D2DCanvas()
        {

        }      

        //Inicializa tudo
        public void Initialize()
        {
            //SharpDX.Configuration.EnableObjectTracking = true;
            imageControl = new System.Windows.Controls.Image();
            imageControl.Stretch = System.Windows.Media.Stretch.None;          
            imageControl.HorizontalAlignment = HorizontalAlignment.Stretch;
            imageControl.VerticalAlignment = VerticalAlignment.Stretch;

            textureWidth = (int)this.MinWidth;
            textureHeight = (int)this.MinHeight;

            this.Children.Add(imageControl);

            ElementCollection = new List<Element>();
            Direct2DStart();
            Draw();
            D3DImageSource();
            rect = new RawRectangleF();

        }

        public void Draw()
        {
            //Aqui inicia o desenho 
            Direct2D1RenderTarget.BeginDraw();
            //Limpa a tela
            Direct2D1RenderTarget.Clear(Util.RGBColorToRawColor4(0, 0, 255));

            foreach (Element element in ElementCollection)
            {
                if (element.GetType() == typeof(Rectangle))
                {
                    Rectangle retangle = (Rectangle)element;    

                    rect.Left = retangle.X;
                    rect.Top = retangle.Y;
                    rect.Right = retangle.X + retangle.Width;
                    rect.Bottom = retangle.Y + retangle.Height;

                    RawColor4 color = Util.RGBColorToRawColor4(255, 0, 0);
                    SolidColorBrush solidColorBrush = new SolidColorBrush(Direct2D1RenderTarget, color);

                    Direct2D1RenderTarget.FillRectangle(rect, solidColorBrush);

                    Util.SafeDispose(ref solidColorBrush);
                }
            }

            //Finaliza o desenho
            Direct2D1RenderTarget.EndDraw();
            //
            Direct3D11Device.ImmediateContext.Flush();

        }

        //Redesenha
        public void UpdateDraw()
        {
            Draw();
            d3DImageSource.Lock();
            d3DImageSource.AddDirtyRect(new System.Windows.Int32Rect(0, 0, d3DImageSource.PixelWidth, d3DImageSource.PixelHeight));
            d3DImageSource.Unlock();          
        }

        //Atualiza a tela apos Window Resize
        public void UpdateResize()
        {
            try
            {
                //Direct2D Reset
                Util.SafeDispose(ref Direct2D1RenderTarget);
                Util.SafeDispose(ref Direct2D1Factory);
                Util.SafeDispose(ref Direct3D11Texture2D);

                textureWidth = Math.Max((int)ActualWidth, 100);
                textureHeight = Math.Max((int)ActualHeight, 100);
                Direct3D11Texture2DDescription.Width = textureWidth;
                Direct3D11Texture2DDescription.Height = textureHeight;

                Direct2DConfig();

                //ImageSource Reset    
                Direct3D9Texture = null;
                d3DImageSource.Lock();
                d3DImageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, IntPtr.Zero);
                d3DImageSource.Unlock();
                D3DImageSourceConfig();

                UpdateDraw();

            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }           
        }

        /*---------------------------------- Direct2D -----------------------------------------*/
        private void Direct2DStart()
        {  
            //Inicialiso o dispositivo Direct2D
            Direct3D11Device = new SharpDX.Direct3D11.Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);

            //Defino as parametros da Textura 2D do Direct3D 11 
            Direct3D11Texture2DDescription = new Texture2DDescription();
            Direct3D11Texture2DDescription.BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource;
            Direct3D11Texture2DDescription.Format = Format.B8G8R8A8_UNorm;
            Direct3D11Texture2DDescription.MipLevels = 1;
            Direct3D11Texture2DDescription.SampleDescription = new SampleDescription(1, 0);
            Direct3D11Texture2DDescription.Usage = ResourceUsage.Default;
            Direct3D11Texture2DDescription.OptionFlags = ResourceOptionFlags.Shared;
            Direct3D11Texture2DDescription.CpuAccessFlags = CpuAccessFlags.None;
            Direct3D11Texture2DDescription.ArraySize = 1;
            Direct3D11Texture2DDescription.Width = textureWidth;
            Direct3D11Texture2DDescription.Height = textureHeight;

            //Inicialiso o PixelFormat do Direct2D
            Direct2D1PixelFormat = new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Premultiplied);

            //Inicialiso o RenderTargetProperties do Direct2D
            Direct2D1RenderTargetProperties = new RenderTargetProperties(Direct2D1PixelFormat);

            Direct2DConfig();
            //Direct3D11Device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height, 0.0f, 1.0f);
        }

        private void Direct2DConfig()
        {      
            //Cria uma textura 2D Direct3D 11 
            Direct3D11Texture2D = new Texture2D(Direct3D11Device, Direct3D11Texture2DDescription);

            //Inicialiso a superficie DXGI do Direct3D 11
            DXGISurface = Direct3D11Texture2D.QueryInterface<Surface>();           

            //Inicializo o Factory do Direct2D
            Direct2D1Factory = new SharpDX.Direct2D1.Factory();

            //Inicialiso o RenderTarget do Direct2D       
            Direct2D1RenderTarget = new RenderTarget(Direct2D1Factory, DXGISurface, Direct2D1RenderTargetProperties);

            //Direct3D11Device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height, 0.0f, 1.0f);
        }

        /*---------------------------------- ImageSorce -----------------------------------------*/
        private void D3DImageSource()
        {   
            //Cria uma Instancia da class WPF D3DImage
            d3DImageSource = new D3DImage();           

            // Cria o objeto D3D, que é necessário para criar o D3DDevice. 
            D3DContext = new SharpDX.Direct3D9.Direct3DEx();

            // Configurar a estrutura usada para criar o D3DDevice. 
            presentParams = new SharpDX.Direct3D9.PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
            presentParams.DeviceWindowHandle = NativeMethods.GetDesktopWindow();
            presentParams.PresentationInterval = SharpDX.Direct3D9.PresentInterval.Default;

            //Cria as Flags Direct3D 9
            createFlags = SharpDX.Direct3D9.CreateFlags.HardwareVertexProcessing | SharpDX.Direct3D9.CreateFlags.Multithreaded | SharpDX.Direct3D9.CreateFlags.FpuPreserve;

            // Criar o dispositivo Direct3D 9 
            Direct3D9DeviceEx = new SharpDX.Direct3D9.DeviceEx(D3DContext, 0, SharpDX.Direct3D9.DeviceType.Hardware, IntPtr.Zero, createFlags, presentParams);
            direct3D9Format = SharpDX.Direct3D9.Format.A8R8G8B8;

            D3DImageSourceConfig();

            imageControl.Source = d3DImageSource;

            d3DImageSource.Lock();
            d3DImageSource.AddDirtyRect(new System.Windows.Int32Rect(0, 0, d3DImageSource.PixelWidth, d3DImageSource.PixelHeight));
            d3DImageSource.Unlock();  
        }

        private void D3DImageSourceConfig()
        {
            sharedHandle = Direct3D11Texture2D.QueryInterface<SharpDX.DXGI.Resource>().SharedHandle;

            //Criar uma textura Direct3D 9 
            Direct3D9Texture = new SharpDX.Direct3D9.Texture(Direct3D9DeviceEx, Direct3D11Texture2D.Description.Width, Direct3D11Texture2D.Description.Height, 1, SharpDX.Direct3D9.Usage.RenderTarget, direct3D9Format, SharpDX.Direct3D9.Pool.Default, ref sharedHandle);

            //Criar uma superficie Direct3D 9 
            Direct3D9Surface = Direct3D9Texture.GetSurfaceLevel(0);

            d3DImageSource.Lock();
            d3DImageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, Direct3D9Surface.NativePointer);
            d3DImageSource.Unlock();

        }

        public void Release()
        {
            //Direct2D
            Util.SafeDispose(ref Direct2D1RenderTarget);
            Util.SafeDispose(ref Direct2D1Factory);
            Util.SafeDispose(ref d3DImageSource);
            Util.SafeDispose(ref Direct3D11Texture2D);
            Util.SafeDispose(ref Direct3D11Device);

            //ImageSource
            Util.SafeDispose(ref Direct3D9Texture);
            Util.SafeDispose(ref Direct3D9Surface);
            Util.SafeDispose(ref Direct3D9DeviceEx);  
            Util.SafeDispose(ref D3DContext);

        }
    }
}
xoofx commented 7 years ago

Hey, could you please give me a feedback at least on my previous comment. Have you tried the ObjectTracker? What are the results? I really cannot afford to debug this for you.