Browse Source

Merge branch 'master' into fixes/fix-missed-resources

danwalmsley 5 years ago
parent
commit
8bd24dfcf7

+ 27 - 11
src/Avalonia.Visuals/Rendering/RenderLoop.cs

@@ -18,6 +18,7 @@ namespace Avalonia.Rendering
     {
         private readonly IDispatcher _dispatcher;
         private List<IRenderLoopTask> _items = new List<IRenderLoopTask>();
+        private List<IRenderLoopTask> _itemsCopy = new List<IRenderLoopTask>();
         private IRenderTimer _timer;
         private int _inTick;
         private int _inUpdate;
@@ -63,11 +64,14 @@ namespace Avalonia.Rendering
             Contract.Requires<ArgumentNullException>(i != null);
             Dispatcher.UIThread.VerifyAccess();
 
-            _items.Add(i);
-
-            if (_items.Count == 1)
+            lock (_items)
             {
-                Timer.Tick += TimerTick;
+                _items.Add(i);
+
+                if (_items.Count == 1)
+                {
+                    Timer.Tick += TimerTick;
+                }
             }
         }
 
@@ -76,12 +80,14 @@ namespace Avalonia.Rendering
         {
             Contract.Requires<ArgumentNullException>(i != null);
             Dispatcher.UIThread.VerifyAccess();
-
-            _items.Remove(i);
-
-            if (_items.Count == 0)
+            lock (_items)
             {
-                Timer.Tick -= TimerTick;
+                _items.Remove(i);
+
+                if (_items.Count == 0)
+                {
+                    Timer.Tick -= TimerTick;
+                }
             }
         }
 
@@ -129,10 +135,20 @@ namespace Avalonia.Rendering
                         }, DispatcherPriority.Render);
                     }
 
-                    for(int i = 0; i < _items.Count; i++)
+                    lock (_items)
+                    {
+                        _itemsCopy.Clear();
+                        foreach (var i in _items)
+                            _itemsCopy.Add(i);
+                    }
+
+                    for (int i = 0; i < _itemsCopy.Count; i++)
                     {
-                        _items[i].Render();
+                        _itemsCopy[i].Render();
                     }
+                    
+                    _itemsCopy.Clear();
+
                 }
                 catch (Exception ex)
                 {

+ 72 - 0
src/Avalonia.Visuals/Rendering/SleepLoopRenderTimer.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Avalonia.Rendering
+{
+    public class SleepLoopRenderTimer : IRenderTimer
+    {
+        private Action<TimeSpan> _tick;
+        private int _count;
+        private readonly object _lock = new object();
+        private bool _running;
+        private readonly Stopwatch _st = Stopwatch.StartNew();
+        private readonly TimeSpan _timeBetweenTicks;
+
+        public SleepLoopRenderTimer(int fps)
+        {
+            _timeBetweenTicks = TimeSpan.FromSeconds(1d / fps);
+        }
+        
+        public event Action<TimeSpan> Tick
+        {
+            add
+            {
+                lock (_lock)
+                {
+                    _tick += value;
+                    _count++;
+                    if (_running)
+                        return;
+                    _running = true;
+                    new Thread(LoopProc) { IsBackground = true }.Start();
+                }
+
+            }
+            remove
+            {
+                lock (_lock)
+                {
+                    _tick -= value;
+                    _count--;
+                }
+            }
+        }
+
+        void LoopProc()
+        {
+            var now = _st.Elapsed;
+            var lastTick = now;
+
+            while (true)
+            {
+                var timeTillNextTick = lastTick + _timeBetweenTicks - now;
+                if (timeTillNextTick.TotalMilliseconds > 1) Thread.Sleep(timeTillNextTick);
+
+                lock (_lock)
+                {
+                    if (_count == 0)
+                    {
+                        _running = false;
+                        return;
+                    }
+                }
+
+                _tick?.Invoke(now);
+                now = _st.Elapsed;
+            }
+        }
+
+
+    }
+}

+ 1 - 1
src/Avalonia.X11/X11Platform.cs

@@ -47,7 +47,7 @@ namespace Avalonia.X11
             AvaloniaLocator.CurrentMutable.BindToSelf(this)
                 .Bind<IWindowingPlatform>().ToConstant(this)
                 .Bind<IPlatformThreadingInterface>().ToConstant(new X11PlatformThreading(this))
-                .Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
+                .Bind<IRenderTimer>().ToConstant(new SleepLoopRenderTimer(60))
                 .Bind<IRenderLoop>().ToConstant(new RenderLoop())
                 .Bind<PlatformHotkeyConfiguration>().ToConstant(new PlatformHotkeyConfiguration(KeyModifiers.Control))
                 .Bind<IKeyboardDevice>().ToFunc(() => KeyboardDevice)