diff --git a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs b/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs index a673047e8c..82dbf53579 100644 --- a/src/Gtk/Avalonia.Gtk3/FramebufferManager.cs +++ b/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")) { diff --git a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs index 935ab53432..6cd2b16afa 100644 --- a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs +++ b/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().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; } diff --git a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs b/src/Shared/PlatformSupport/StandardRuntimePlatform.cs index b777736f06..d352a588e0 100644 --- a/src/Shared/PlatformSupport/StandardRuntimePlatform.cs +++ b/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 Backtraces = new List(); 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; } } diff --git a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs b/src/Windows/Avalonia.Win32/WindowFramebuffer.cs index df238c919e..83ab288c54 100644 --- a/src/Windows/Avalonia.Win32/WindowFramebuffer.cs +++ b/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().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(); } } \ No newline at end of file