From 0909a613f2be4aa005152265651721392b2faccb Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 21 Oct 2017 17:36:02 +0300 Subject: [PATCH] [MONOMAC] Fixed rendering artifacts on resize with DeferredRenderer --- .../Avalonia.MonoMac/EmulatedFramebuffer.cs | 87 ++++++++++--------- src/OSX/Avalonia.MonoMac/TopLevelImpl.cs | 2 +- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs index 02ead65281..713d4b0d18 100644 --- a/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs +++ b/src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs @@ -11,20 +11,29 @@ namespace Avalonia.MonoMac { private readonly TopLevelImpl.TopLevelView _view; private readonly CGSize _logicalSize; + private bool _isDeferred; - public EmulatedFramebuffer(TopLevelImpl.TopLevelView view, CGSize logicalSize, CGSize pixelSize) + [DllImport("libc")] + static extern void memset(IntPtr p, int c, IntPtr size); + + public EmulatedFramebuffer(TopLevelImpl.TopLevelView view) { _view = view; - _logicalSize = logicalSize; + + _isDeferred = !Dispatcher.UIThread.CheckAccess(); + _logicalSize = _view.LogicalSize; + var pixelSize = _view.PixelSize; Width = (int)pixelSize.Width; Height = (int)pixelSize.Height; RowBytes = Width * 4; Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height); Format = PixelFormat.Rgba8888; - Address = Marshal.AllocHGlobal(Height * RowBytes); + var size = Height * RowBytes; + Address = Marshal.AllocHGlobal(size); + memset(Address, 0, new IntPtr(size)); } - class DeferredRenderingHelper : IDisposable + class CocoaDrawLock : IDisposable { private readonly NSView _view; public void Dispose() @@ -32,17 +41,17 @@ namespace Avalonia.MonoMac _view.NonUIUnlockFocus(); } - public DeferredRenderingHelper(NSView view) + public CocoaDrawLock(NSView view) { _view = view; } } - DeferredRenderingHelper SetupWindowContext() + CocoaDrawLock LockCocoaDrawing() { if (!_view.NonUILockFocusIfCanDraw()) return null; - return new DeferredRenderingHelper(_view); + return new CocoaDrawLock(_view); } public void Dispose() @@ -50,51 +59,45 @@ namespace Avalonia.MonoMac if (Address == IntPtr.Zero) return; var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast; - - DeferredRenderingHelper deferred = null; - var isDeferred = !Dispatcher.UIThread.CheckAccess(); - if (!isDeferred || (deferred = SetupWindowContext()) != null) + IDisposable drawLock = LockCocoaDrawing(); + CGImage image = null; + try { - CGImage image = null; - try + using (var colorSpace = CGColorSpace.CreateDeviceRGB()) + using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, + colorSpace, (CGImageAlphaInfo)nfo)) + image = bContext.ToImage(); + lock (_view.SyncRoot) { - lock (_view.SyncRoot) + if (!_isDeferred || drawLock != null) { - using (deferred) - using (var colorSpace = CGColorSpace.CreateDeviceRGB()) - using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4, - colorSpace, (CGImageAlphaInfo) nfo)) + using (var nscontext = NSGraphicsContext.CurrentContext) + using (var context = nscontext.GraphicsPort) { - if (!isDeferred || deferred != null) - { - using (var nscontext = NSGraphicsContext.CurrentContext) - using (var context = nscontext.GraphicsPort) - { - image = bContext.ToImage(); - context.SetFillColor(255, 255, 255, 255); - context.FillRect(new CGRect(default(CGPoint), _view.LogicalSize)); - context.TranslateCTM(0, _view.LogicalSize.Height - _logicalSize.Height); - context.DrawImage(new CGRect(default(CGPoint), _logicalSize), image); - context.Flush(); - nscontext.FlushGraphics(); - } - } + context.SetFillColor(255, 255, 255, 255); + context.FillRect(new CGRect(default(CGPoint), _view.LogicalSize)); + context.TranslateCTM(0, _view.LogicalSize.Height - _logicalSize.Height); + context.DrawImage(new CGRect(default(CGPoint), _logicalSize), image); + context.Flush(); + nscontext.FlushGraphics(); } } } - finally + } + finally + { + if (image != null) { - if (image != null) - { - if (deferred == null) - image.Dispose(); - else - _view.SetBackBufferImage(new SavedImage(image, _logicalSize)); - } + if (!_isDeferred) + image.Dispose(); + else + _view.SetBackBufferImage(new SavedImage(image, _logicalSize)); } + Marshal.FreeHGlobal(Address); + Address = IntPtr.Zero; + drawLock?.Dispose(); } - Marshal.FreeHGlobal(Address); - Address = IntPtr.Zero; + } diff --git a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs index ce30deea88..37b6b16793 100644 --- a/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs +++ b/src/OSX/Avalonia.MonoMac/TopLevelImpl.cs @@ -413,6 +413,6 @@ namespace Avalonia.MonoMac public void SetInputRoot(IInputRoot inputRoot) => InputRoot = inputRoot; - public ILockedFramebuffer Lock() => new EmulatedFramebuffer(View, View.LogicalSize, View.PixelSize); + public ILockedFramebuffer Lock() => new EmulatedFramebuffer(View); } } \ No newline at end of file