Browse Source

Improved unmanaged memory allocation diagnostics. ref #1411

pull/1432/head
Nikita Tsukanov 9 years ago
parent
commit
77b74444ba
  1. 5
      src/Gtk/Avalonia.Gtk3/FramebufferManager.cs
  2. 10
      src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs
  3. 31
      src/Shared/PlatformSupport/StandardRuntimePlatform.cs
  4. 22
      src/Windows/Avalonia.Win32/WindowFramebuffer.cs

5
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@ -26,8 +26,9 @@ namespace Avalonia.Gtk3
{
// This method may be called from non-UI thread, don't touch anything that calls back to GTK/GDK
var s = _window.ClientSize;
var width = (int) s.Width;
var height = (int) s.Height;
var width = Math.Max(1, (int) s.Width);
var height = Math.Max(1, (int) s.Height);
if (!Dispatcher.UIThread.CheckAccess() && Gtk3Platform.DisplayClassName.ToLower().Contains("x11"))
{

10
src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs

@ -12,6 +12,7 @@ namespace Avalonia.MonoMac
private readonly TopLevelImpl.TopLevelView _view;
private readonly CGSize _logicalSize;
private readonly bool _isDeferred;
private readonly IUnmanagedBlob _blob;
[DllImport("libc")]
static extern void memset(IntPtr p, int c, IntPtr size);
@ -29,13 +30,13 @@ namespace Avalonia.MonoMac
Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height);
Format = PixelFormat.Rgba8888;
var size = Height * RowBytes;
Address = Marshal.AllocHGlobal(size);
_blob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(size);
memset(Address, 0, new IntPtr(size));
}
public void Dispose()
{
if (Address == IntPtr.Zero)
if (_blob.IsDisposed)
return;
var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast;
CGImage image = null;
@ -71,14 +72,13 @@ namespace Avalonia.MonoMac
else
_view.SetBackBufferImage(new SavedImage(image, _logicalSize));
}
Marshal.FreeHGlobal(Address);
Address = IntPtr.Zero;
_blob.Dispose();
}
}
public IntPtr Address { get; private set; }
public IntPtr Address => _blob.Address;
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }

31
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@ -28,11 +28,13 @@ namespace Avalonia.Shared.PlatformSupport
class UnmanagedBlob : IUnmanagedBlob
{
private readonly StandardRuntimePlatform _plat;
private IntPtr _address;
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread GCThread;
private readonly string _backtrace;
private readonly object _lock = new object();
private static readonly object _btlock = new object();
class GCThreadDetector
{
@ -55,28 +57,35 @@ namespace Avalonia.Shared.PlatformSupport
public UnmanagedBlob(StandardRuntimePlatform plat, int size)
{
if (size <= 0)
throw new ArgumentException("Positive number required", nameof(size));
_plat = plat;
Address = plat.Alloc(size);
_address = plat.Alloc(size);
GC.AddMemoryPressure(size);
Size = size;
#if DEBUG
_backtrace = Environment.StackTrace;
Backtraces.Add(_backtrace);
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
void DoDispose()
{
if (!IsDisposed)
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
Backtraces.Remove(_backtrace);
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
_plat.Free(Address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
Address = IntPtr.Zero;
Size = 0;
_plat.Free(_address, Size);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
_address = IntPtr.Zero;
Size = 0;
}
}
}
@ -102,7 +111,7 @@ namespace Avalonia.Shared.PlatformSupport
DoDispose();
}
public IntPtr Address { get; private set; }
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }
}

22
src/Windows/Avalonia.Win32/WindowFramebuffer.cs

@ -10,7 +10,7 @@ namespace Avalonia.Win32
public class WindowFramebuffer : ILockedFramebuffer
{
private readonly IntPtr _handle;
private IntPtr _pBitmap;
private IUnmanagedBlob _bitmapBlob;
private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo;
public WindowFramebuffer(IntPtr handle, int width, int height)
@ -27,7 +27,7 @@ namespace Avalonia.Win32
_bmpInfo.Init();
_bmpInfo.biWidth = width;
_bmpInfo.biHeight = -height;
_pBitmap = Marshal.AllocHGlobal(width * height * 4);
_bitmapBlob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(width * height * 4);
}
~WindowFramebuffer()
@ -35,7 +35,7 @@ namespace Avalonia.Win32
Deallocate();
}
public IntPtr Address => _pBitmap;
public IntPtr Address => _bitmapBlob.Address;
public int RowBytes => Width * 4;
public PixelFormat Format => PixelFormat.Bgra8888;
@ -70,21 +70,18 @@ namespace Avalonia.Win32
public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if(_pBitmap == IntPtr.Zero)
throw new ObjectDisposedException("Framebuffer");
if (width == -1)
width = Width;
if (height == -1)
height = Height;
UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY,
0, (uint)Height, _pBitmap, ref _bmpInfo, 0);
0, (uint)Height, _bitmapBlob.Address, ref _bmpInfo, 0);
}
public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
int height = -1)
{
if (_pBitmap == IntPtr.Zero)
if (_bitmapBlob.IsDisposed)
throw new ObjectDisposedException("Framebuffer");
if (hWnd == IntPtr.Zero)
return false;
@ -102,13 +99,6 @@ namespace Avalonia.Win32
DrawToWindow(_handle);
}
public void Deallocate()
{
if (_pBitmap != IntPtr.Zero)
{
Marshal.FreeHGlobal(_pBitmap);
_pBitmap = IntPtr.Zero;
}
}
public void Deallocate() => _bitmapBlob.Dispose();
}
}
Loading…
Cancel
Save