Browse Source

More thread safety and ownsImpl argument for DrawingContext

pull/2185/head
Nikita Tsukanov 7 years ago
parent
commit
23c40e1278
  1. 29
      src/Avalonia.Base/Threading/ThreadSafeObjectPool.cs
  2. 31
      src/Avalonia.Visuals/Media/DrawingContext.cs

29
src/Avalonia.Base/Threading/ThreadSafeObjectPool.cs

@ -0,0 +1,29 @@
using System.Collections.Generic;
namespace Avalonia.Threading
{
public class ThreadSafeObjectPool<T> where T : class, new()
{
private Stack<T> _stack = new Stack<T>();
private object _lock = new object();
public static ThreadSafeObjectPool<T> Default { get; } = new ThreadSafeObjectPool<T>();
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);
}
}
}
}

31
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<Stack<PushedState>> StateStackPool = new Stack<Stack<PushedState>>();
static readonly Stack<Stack<TransformContainer>> TransformStackPool = new Stack<Stack<TransformContainer>>();
private static readonly ThreadSafeObjectPool<Stack<PushedState>> StateStackPool =
ThreadSafeObjectPool<Stack<PushedState>>.Default;
private Stack<PushedState> _states = StateStackPool.Count == 0 ? new Stack<PushedState>() : StateStackPool.Pop();
private static readonly ThreadSafeObjectPool<Stack<TransformContainer>> TransformStackPool =
ThreadSafeObjectPool<Stack<TransformContainer>>.Default;
private Stack<TransformContainer> _transformContainers = TransformStackPool.Count == 0
? new Stack<TransformContainer>()
: TransformStackPool.Pop();
private Stack<PushedState> _states = StateStackPool.Get();
private Stack<TransformContainer> _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)

Loading…
Cancel
Save