Browse Source

Use SafeHandle for cairo surface and don't reuse ImageSurfaceFramebuffer to conserve RAM.

Also fixes memory leak.
Nikita Tsukanov 8 years ago
parent
commit
7fa329606e

+ 1 - 0
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@@ -44,6 +44,7 @@
     <Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
       <Link>KeyTransform.cs</Link>
     </Compile>
+    <Compile Include="Interop\CairoSurface.cs" />
     <Compile Include="ClipboardImpl.cs" />
     <Compile Include="CursorFactory.cs" />
     <Compile Include="FramebufferManager.cs" />

+ 2 - 12
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@@ -10,7 +10,6 @@ namespace Avalonia.Gtk3
     class FramebufferManager : IFramebufferPlatformSurface, IDisposable
     {
         private readonly TopLevelImpl _window;
-        private ImageSurfaceFramebuffer _fb;
         public FramebufferManager(TopLevelImpl window)
         {
             _window = window;
@@ -18,25 +17,16 @@ namespace Avalonia.Gtk3
 
         public void Dispose()
         {
-            _fb?.Deallocate();
+            //
         }
 
         public ILockedFramebuffer Lock()
         {
             if(_window.CurrentCairoContext == IntPtr.Zero)
                 throw new InvalidOperationException("Window is not in drawing state");
-
-            var ctx = _window.CurrentCairoContext;
             var width = (int) _window.ClientSize.Width;
             var height = (int) _window.ClientSize.Height;
-            if (_fb == null || _fb.Width != width ||
-                _fb.Height != height)
-            {
-                _fb?.Dispose();
-                _fb = new ImageSurfaceFramebuffer(width, height);
-            }
-            _fb.Prepare(ctx);
-            return _fb;
+            return new ImageSurfaceFramebuffer(_window.CurrentCairoContext, width, height);
         }
     }
 }

+ 7 - 16
src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs

@@ -13,10 +13,11 @@ namespace Avalonia.Gtk3
     class ImageSurfaceFramebuffer : ILockedFramebuffer
     {
         private IntPtr _context;
-        private IntPtr _surface;
+        private CairoSurface _surface;
 
-        public ImageSurfaceFramebuffer(int width, int height)
+        public ImageSurfaceFramebuffer(IntPtr context, int width, int height)
         {
+            _context = context;
             _surface = Native.CairoImageSurfaceCreate(1, width, height);
             Width = width;
             Height = height;
@@ -24,27 +25,17 @@ namespace Avalonia.Gtk3
             RowBytes = Native.CairoImageSurfaceGetStride(_surface);
             Native.CairoSurfaceFlush(_surface);
         }
-
-        public void Prepare(IntPtr context)
-        {
-            _context = context;
-        }
-
-        public void Deallocate()
-        {
-            Native.CairoSurfaceDestroy(_surface);
-            _surface = IntPtr.Zero;
-        }
-
+        
         public void Dispose()
         {
-            if(_context == IntPtr.Zero || _surface == IntPtr.Zero)
+            if(_context == IntPtr.Zero || _surface == null)
                 return;
             Native.CairoSurfaceMarkDirty(_surface);
             Native.CairoSetSourceSurface(_context, _surface, 0, 0);
             Native.CairoPaint(_context);
             _context = IntPtr.Zero;
-
+            _surface.Dispose();
+            _surface = null;
         }
 
         public IntPtr Address { get; }

+ 20 - 0
src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Gtk3.Interop
+{
+    class CairoSurface : SafeHandle
+    {
+        public CairoSurface() : base(IntPtr.Zero, true)
+        {
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            Native.CairoSurfaceDestroy(handle);
+            return true;
+        }
+
+        public override bool IsInvalid => handle == IntPtr.Zero;
+    }
+}

+ 6 - 6
src/Gtk/Avalonia.Gtk3/Interop/Native.cs

@@ -110,25 +110,25 @@ namespace Avalonia.Gtk3.Interop
 
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate IntPtr cairo_image_surface_create(int format, int width, int height);
+            public delegate CairoSurface cairo_image_surface_create(int format, int width, int height);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate IntPtr cairo_image_surface_get_data(IntPtr surface);
+            public delegate IntPtr cairo_image_surface_get_data(CairoSurface surface);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate int cairo_image_surface_get_stride(IntPtr surface);
+            public delegate int cairo_image_surface_get_stride(CairoSurface surface);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_mark_dirty(IntPtr surface);
+            public delegate void cairo_surface_mark_dirty(CairoSurface surface);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_surface_flush(IntPtr surface);
+            public delegate void cairo_surface_flush(CairoSurface surface);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
             public delegate void cairo_surface_destroy(IntPtr surface);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
-            public delegate void cairo_set_source_surface(IntPtr cr, IntPtr surface, double x, double y);
+            public delegate void cairo_set_source_surface(IntPtr cr, CairoSurface surface, double x, double y);
 
             [UnmanagedFunctionPointer(CallingConvention.Cdecl), GtkImport(GtkDll.Cairo)]
             public delegate void cairo_paint(IntPtr context);