Browse Source

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

Also fixes memory leak.
pull/880/head
Nikita Tsukanov 9 years ago
parent
commit
7fa329606e
  1. 1
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  2. 14
      src/Gtk/Avalonia.Gtk3/FramebufferManager.cs
  3. 23
      src/Gtk/Avalonia.Gtk3/ImageSurfaceFramebuffer.cs
  4. 20
      src/Gtk/Avalonia.Gtk3/Interop/CairoSurface.cs
  5. 12
      src/Gtk/Avalonia.Gtk3/Interop/Native.cs

1
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" />

14
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);
}
}
}

23
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
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;
}
}

12
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);

Loading…
Cancel
Save