소스 검색

Merge pull request #3818 from MarchingCube/deferred-renderer-memory

Limit reallocations in the deferred renderer.
Steven Kirk 5 년 전
부모
커밋
21b21e40bc

+ 14 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs

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

+ 16 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/SceneLayers.cs

@@ -11,16 +11,28 @@ namespace Avalonia.Rendering.SceneGraph
     public class SceneLayers : IEnumerable<SceneLayer>
     {
         private readonly IVisual _root;
-        private readonly List<SceneLayer> _inner = new List<SceneLayer>();
-        private readonly Dictionary<IVisual, SceneLayer> _index = new Dictionary<IVisual, SceneLayer>();
+        private readonly List<SceneLayer> _inner;
+        private readonly Dictionary<IVisual, SceneLayer> _index;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="SceneLayers"/> class.
         /// </summary>
         /// <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;
+
+            _inner = new List<SceneLayer>(capacity);
+            _index = new Dictionary<IVisual, SceneLayer>(capacity);
         }
 
         /// <summary>
@@ -84,7 +96,7 @@ namespace Avalonia.Rendering.SceneGraph
         /// <returns>The cloned layers.</returns>
         public SceneLayers Clone()
         {
-            var result = new SceneLayers(_root);
+            var result = new SceneLayers(_root, Count);
 
             foreach (var src in _inner)
             {

+ 19 - 6
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Reactive.Disposables;
+using Avalonia.Collections;
 using Avalonia.Media;
 using Avalonia.Platform;
 using Avalonia.Utilities;
@@ -349,6 +349,11 @@ namespace Avalonia.Rendering.SceneGraph
             context.Transform = transformRestore;
         }
 
+        internal void TryPreallocateChildren(int count)
+        {
+            EnsureChildrenCreated(count);
+        }
+
         private Rect CalculateBounds()
         {
             var result = new Rect();
@@ -362,11 +367,11 @@ namespace Avalonia.Rendering.SceneGraph
             return result;
         }
 
-        private void EnsureChildrenCreated()
+        private void EnsureChildrenCreated(int capacity = 0)
         {
             if (_children == null)
             {
-                _children = new List<IVisualNode>();
+                _children = new List<IVisualNode>(capacity);
             }
         }
 
@@ -383,7 +388,15 @@ namespace Avalonia.Rendering.SceneGraph
             }
             else if (_drawOperationsCloned)
             {
-                _drawOperations = new List<IRef<IDrawOperation>>(_drawOperations.Select(op => op.Clone()));
+                var oldDrawOperations = _drawOperations;
+
+                _drawOperations = new List<IRef<IDrawOperation>>(oldDrawOperations.Count);
+
+                foreach (var drawOperation in oldDrawOperations)
+                {
+                    _drawOperations.Add(drawOperation.Clone());
+                }
+
                 _drawOperationsRefCounter.Dispose();
                 _drawOperationsRefCounter = RefCountable.Create(CreateDisposeDrawOperations(_drawOperations));
                 _drawOperationsCloned = false;
@@ -399,9 +412,9 @@ namespace Avalonia.Rendering.SceneGraph
         /// <returns>Disposable for given draw operations.</returns>
         private static IDisposable CreateDisposeDrawOperations(List<IRef<IDrawOperation>> drawOperations)
         {
-            return Disposable.Create(() =>
+            return Disposable.Create(drawOperations, operations =>
             {
-                foreach (var operation in drawOperations)
+                foreach (var operation in operations)
                 {
                     operation.Dispose();
                 }