Browse Source

Pool collections used by VisualNode. Ensure that when cloning we initialize collection sizes to avoid reallocations.

pull/3775/head
Dariusz Komosinski 6 years ago
parent
commit
f8c8098ad5
  1. 17
      src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs
  2. 20
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs
  3. 43
      src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

17
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

@ -12,7 +12,7 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary> /// </summary>
public class Scene : IDisposable public class Scene : IDisposable
{ {
private Dictionary<IVisual, IVisualNode> _index; private readonly Dictionary<IVisual, IVisualNode> _index;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Scene"/> class. /// Initializes a new instance of the <see cref="Scene"/> class.
@ -83,7 +83,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <returns>The cloned scene.</returns> /// <returns>The cloned scene.</returns>
public Scene CloneScene() public Scene CloneScene()
{ {
var index = new Dictionary<IVisual, IVisualNode>(); var index = new Dictionary<IVisual, IVisualNode>(_index.Count);
var root = Clone((VisualNode)Root, null, index); var root = Clone((VisualNode)Root, null, index);
var result = new Scene(root, index, Layers.Clone(), Generation + 1) var result = new Scene(root, index, Layers.Clone(), Generation + 1)
@ -162,9 +162,18 @@ namespace Avalonia.Rendering.SceneGraph
index.Add(result.Visual, result); index.Add(result.Visual, result);
foreach (var child in source.Children) int childCount = source.Children.Count;
if (childCount > 0)
{ {
result.AddChild(Clone((VisualNode)child, result, index)); Span<IVisualNode> children = result.AddChildrenSpan(childCount);
for (var i = 0; i < childCount; i++)
{
var child = source.Children[i];
children[i] = Clone((VisualNode)child, result, index);
}
} }
return result; return result;

20
src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs

@ -11,16 +11,28 @@ namespace Avalonia.Rendering.SceneGraph
public class SceneLayers : IEnumerable<SceneLayer> public class SceneLayers : IEnumerable<SceneLayer>
{ {
private readonly IVisual _root; private readonly IVisual _root;
private readonly List<SceneLayer> _inner = new List<SceneLayer>(); private readonly List<SceneLayer> _inner;
private readonly Dictionary<IVisual, SceneLayer> _index = new Dictionary<IVisual, SceneLayer>(); private readonly Dictionary<IVisual, SceneLayer> _index;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SceneLayers"/> class. /// Initializes a new instance of the <see cref="SceneLayers"/> class.
/// </summary> /// </summary>
/// <param name="root">The scene's root visual.</param> /// <param name="root">The scene's root visual.</param>
public SceneLayers(IVisual root) public SceneLayers(IVisual root) : this(root, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SceneLayers"/> class.
/// </summary>
/// <param name="root">The scene's root visual.</param>
/// <param name="capacity">Initial layer capacity.</param>
public SceneLayers(IVisual root, int capacity)
{ {
_root = root; _root = root;
_inner = new List<SceneLayer>(capacity);
_index = new Dictionary<IVisual, SceneLayer>(capacity);
} }
/// <summary> /// <summary>
@ -84,7 +96,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <returns>The cloned layers.</returns> /// <returns>The cloned layers.</returns>
public SceneLayers Clone() public SceneLayers Clone()
{ {
var result = new SceneLayers(_root); var result = new SceneLayers(_root, Count);
foreach (var src in _inner) foreach (var src in _inner)
{ {

43
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Collections.Pooled;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -19,8 +20,8 @@ namespace Avalonia.Rendering.SceneGraph
private Rect? _bounds; private Rect? _bounds;
private double _opacity; private double _opacity;
private List<IVisualNode> _children; private PooledList<IVisualNode> _children;
private List<IRef<IDrawOperation>> _drawOperations; private PooledList<IRef<IDrawOperation>> _drawOperations;
private IRef<IDisposable> _drawOperationsRefCounter; private IRef<IDisposable> _drawOperationsRefCounter;
private bool _drawOperationsCloned; private bool _drawOperationsCloned;
private Matrix transformRestore; private Matrix transformRestore;
@ -349,6 +350,18 @@ namespace Avalonia.Rendering.SceneGraph
context.Transform = transformRestore; context.Transform = transformRestore;
} }
/// <summary>
/// Inserts default constructed children into collection and returns a span for the newly created range.
/// </summary>
/// <param name="count">Count of children that will be added.</param>
/// <returns></returns>
internal Span<IVisualNode> AddChildrenSpan(int count)
{
EnsureChildrenCreated(count);
return _children.AddSpan(count);
}
private Rect CalculateBounds() private Rect CalculateBounds()
{ {
var result = new Rect(); var result = new Rect();
@ -362,11 +375,11 @@ namespace Avalonia.Rendering.SceneGraph
return result; return result;
} }
private void EnsureChildrenCreated() private void EnsureChildrenCreated(int capacity = 0)
{ {
if (_children == null) if (_children == null)
{ {
_children = new List<IVisualNode>(); _children = new PooledList<IVisualNode>(capacity);
} }
} }
@ -377,13 +390,21 @@ namespace Avalonia.Rendering.SceneGraph
{ {
if (_drawOperations == null) if (_drawOperations == null)
{ {
_drawOperations = new List<IRef<IDrawOperation>>(); _drawOperations = new PooledList<IRef<IDrawOperation>>();
_drawOperationsRefCounter = RefCountable.Create(CreateDisposeDrawOperations(_drawOperations)); _drawOperationsRefCounter = RefCountable.Create(CreateDisposeDrawOperations(_drawOperations));
_drawOperationsCloned = false; _drawOperationsCloned = false;
} }
else if (_drawOperationsCloned) else if (_drawOperationsCloned)
{ {
_drawOperations = new List<IRef<IDrawOperation>>(_drawOperations.Select(op => op.Clone())); var oldDrawOperations = _drawOperations;
_drawOperations = new PooledList<IRef<IDrawOperation>>(oldDrawOperations.Count);
foreach (var drawOperation in oldDrawOperations)
{
_drawOperations.Add(drawOperation.Clone());
}
_drawOperationsRefCounter.Dispose(); _drawOperationsRefCounter.Dispose();
_drawOperationsRefCounter = RefCountable.Create(CreateDisposeDrawOperations(_drawOperations)); _drawOperationsRefCounter = RefCountable.Create(CreateDisposeDrawOperations(_drawOperations));
_drawOperationsCloned = false; _drawOperationsCloned = false;
@ -397,14 +418,16 @@ namespace Avalonia.Rendering.SceneGraph
/// </summary> /// </summary>
/// <param name="drawOperations">Draw operations that need to be disposed.</param> /// <param name="drawOperations">Draw operations that need to be disposed.</param>
/// <returns>Disposable for given draw operations.</returns> /// <returns>Disposable for given draw operations.</returns>
private static IDisposable CreateDisposeDrawOperations(List<IRef<IDrawOperation>> drawOperations) private static IDisposable CreateDisposeDrawOperations(PooledList<IRef<IDrawOperation>> drawOperations)
{ {
return Disposable.Create(() => return Disposable.Create(drawOperations, operations =>
{ {
foreach (var operation in drawOperations) foreach (var operation in operations)
{ {
operation.Dispose(); operation.Dispose();
} }
operations.Dispose();
}); });
} }
@ -414,6 +437,8 @@ namespace Avalonia.Rendering.SceneGraph
{ {
_drawOperationsRefCounter?.Dispose(); _drawOperationsRefCounter?.Dispose();
_children?.Dispose();
Disposed = true; Disposed = true;
} }
} }

Loading…
Cancel
Save