diff --git a/src/Avalonia.Base/Threading/ThreadSafeObjectPool.cs b/src/Avalonia.Base/Threading/ThreadSafeObjectPool.cs new file mode 100644 index 0000000000..c6845485dc --- /dev/null +++ b/src/Avalonia.Base/Threading/ThreadSafeObjectPool.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Avalonia.Threading +{ + public class ThreadSafeObjectPool where T : class, new() + { + private Stack _stack = new Stack(); + private object _lock = new object(); + public static ThreadSafeObjectPool Default { get; } = new ThreadSafeObjectPool(); + + public T Get() + { + lock (_lock) + { + if(_stack.Count == 0) + return new T(); + return _stack.Pop(); + } + } + + public void Return(T obj) + { + lock (_stack) + { + _stack.Push(obj); + } + } + } +} diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 6b19167381..9556cd9b26 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -2,23 +2,26 @@ using System; using System.Collections.Generic; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Threading; using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media { public sealed class DrawingContext : IDisposable { + private readonly bool _ownsImpl; private int _currentLevel; - static readonly Stack> StateStackPool = new Stack>(); - static readonly Stack> TransformStackPool = new Stack>(); + private static readonly ThreadSafeObjectPool> StateStackPool = + ThreadSafeObjectPool>.Default; - private Stack _states = StateStackPool.Count == 0 ? new Stack() : StateStackPool.Pop(); + private static readonly ThreadSafeObjectPool> TransformStackPool = + ThreadSafeObjectPool>.Default; - private Stack _transformContainers = TransformStackPool.Count == 0 - ? new Stack() - : TransformStackPool.Pop(); + private Stack _states = StateStackPool.Get(); + + private Stack _transformContainers = TransformStackPool.Get(); readonly struct TransformContainer { @@ -35,6 +38,13 @@ namespace Avalonia.Media public DrawingContext(IDrawingContextImpl impl) { PlatformImpl = impl; + _ownsImpl = true; + } + + public DrawingContext(IDrawingContextImpl impl, bool ownsImpl) + { + _ownsImpl = ownsImpl; + PlatformImpl = impl; } public IDrawingContextImpl PlatformImpl { get; } @@ -299,11 +309,14 @@ namespace Avalonia.Media { while (_states.Count != 0) _states.Peek().Dispose(); - StateStackPool.Push(_states); + StateStackPool.Return(_states); _states = null; - TransformStackPool.Push(_transformContainers); + if (_transformContainers.Count != 0) + throw new InvalidOperationException("Transform container stack is non-empty"); + TransformStackPool.Return(_transformContainers); _transformContainers = null; - PlatformImpl.Dispose(); + if (_ownsImpl) + PlatformImpl.Dispose(); } private static bool PenIsVisible(Pen pen)