From ad518ac6787ab8265adcd1a4eddc70c390590ca6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 3 Aug 2022 15:00:42 +0300 Subject: [PATCH 1/2] Add backpressure for sending batches to the render thread --- .../Rendering/Composition/CompositingRenderer.cs | 2 +- src/Avalonia.Base/Rendering/Composition/Compositor.cs | 11 ++++++++++- .../Rendering/Composition/Server/ServerCompositor.cs | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index db773bc43c..9aa3c25425 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -71,7 +71,7 @@ public class CompositingRenderer : IRendererWithCompositor if(_queuedUpdate) return; _queuedUpdate = true; - Dispatcher.UIThread.Post(_update, DispatcherPriority.Composition); + _compositor.InvokeWhenReadyForNextCommit(_update); } /// diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs index 45212d0f36..f812acc016 100644 --- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs @@ -33,6 +33,7 @@ namespace Avalonia.Rendering.Composition internal IEasing DefaultEasing { get; } private List? _invokeOnNextCommit; private readonly Stack> _invokeListPool = new(); + private Task? _lastBatchCompleted; /// /// Creates a new compositor on a specified render loop that would use a particular GPU @@ -86,7 +87,7 @@ namespace Avalonia.Rendering.Composition if (_invokeOnNextCommit != null) ScheduleCommitCallbacks(batch.Completed); - return batch.Completed; + return _lastBatchCompleted = batch.Completed; } async void ScheduleCommitCallbacks(Task task) @@ -139,5 +140,13 @@ namespace Avalonia.Rendering.Composition _invokeOnNextCommit ??= _invokeListPool.Count > 0 ? _invokeListPool.Pop() : new(); _invokeOnNextCommit.Add(action); } + + public void InvokeWhenReadyForNextCommit(Action action) + { + if (_lastBatchCompleted == null || _lastBatchCompleted.IsCompleted) + Dispatcher.UIThread.Post(action, DispatcherPriority.Composition); + else + _lastBatchCompleted.ContinueWith(_ => Dispatcher.UIThread.Post(action, DispatcherPriority.Composition)); + } } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs index 621bc84f4a..bfc2b2d626 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs @@ -108,6 +108,7 @@ namespace Avalonia.Rendering.Composition.Server private void RenderCore() { ApplyPendingBatches(); + CompletePendingBatches(); foreach(var animation in _activeAnimations) _animationsToUpdate.Add(animation); @@ -119,8 +120,6 @@ namespace Avalonia.Rendering.Composition.Server foreach (var t in _activeTargets) t.Render(); - - CompletePendingBatches(); } public void AddCompositionTarget(ServerCompositionTarget target) From 0d472a100b6fc191d69675512028c4e770045081 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Wed, 3 Aug 2022 15:57:13 +0300 Subject: [PATCH 2/2] Use static callback for ContinueWith --- src/Avalonia.Base/Rendering/Composition/Compositor.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs index f812acc016..10360f7874 100644 --- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs @@ -146,7 +146,9 @@ namespace Avalonia.Rendering.Composition if (_lastBatchCompleted == null || _lastBatchCompleted.IsCompleted) Dispatcher.UIThread.Post(action, DispatcherPriority.Composition); else - _lastBatchCompleted.ContinueWith(_ => Dispatcher.UIThread.Post(action, DispatcherPriority.Composition)); + _lastBatchCompleted.ContinueWith( + static (_, state) => Dispatcher.UIThread.Post((Action)state!, DispatcherPriority.Composition), + action); } } }