From 6e3bf60f2899ae1254c2cca509d067e69ecc387c Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 7 Dec 2020 22:40:56 +0300 Subject: [PATCH] Now using non-pumping mode for UpdateScene in deferred renderer, also improved the non-pumping sync context --- .../Utilities/NonPumpingLockHelper.cs | 14 ++++++++++ .../Rendering/DeferredRenderer.cs | 1 + .../Avalonia.Win32/NonPumpingSyncContext.cs | 26 ++++++++++++++++--- src/Windows/Avalonia.Win32/Win32Platform.cs | 2 ++ 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs diff --git a/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs b/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs new file mode 100644 index 0000000000..fd4e5d2ace --- /dev/null +++ b/src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs @@ -0,0 +1,14 @@ +using System; + +namespace Avalonia.Utilities +{ + public class NonPumpingLockHelper + { + public interface IHelperImpl + { + IDisposable Use(); + } + + public static IDisposable Use() => AvaloniaLocator.Current.GetService()?.Use(); + } +} diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 1c8a47c4b7..3bd8e05ee2 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -607,6 +607,7 @@ namespace Avalonia.Rendering private bool? UpdateScene() { Dispatcher.UIThread.VerifyAccess(); + using var noPump = NonPumpingLockHelper.Use(); lock (_sceneLock) { if (_disposed) diff --git a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs index ab35b04b7a..5577664cc4 100644 --- a/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs +++ b/src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs @@ -2,6 +2,7 @@ using System; using System.Runtime.ConstrainedExecution; using System.Threading; using Avalonia.Threading; +using Avalonia.Utilities; using Avalonia.Win32.Interop; namespace Avalonia.Win32 @@ -10,9 +11,9 @@ namespace Avalonia.Win32 { private readonly SynchronizationContext _inner; - private NonPumpingSyncContext() + private NonPumpingSyncContext(SynchronizationContext inner) { - _inner = Current; + _inner = inner; SetWaitNotificationRequired(); SetSynchronizationContext(this); } @@ -27,8 +28,25 @@ namespace Avalonia.Win32 millisecondsTimeout, false); } - public void Dispose() => SynchronizationContext.SetSynchronizationContext(_inner); + public void Dispose() => SetSynchronizationContext(_inner); - public static IDisposable Use() => new NonPumpingSyncContext(); + public static IDisposable Use() + { + var current = Current; + if (current == null) + { + if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) + return null; + } + if (current is NonPumpingSyncContext) + return null; + + return new NonPumpingSyncContext(current); + } + + internal class HelperImpl : NonPumpingLockHelper.IHelperImpl + { + IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use(); + } } } diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs index c205faefdd..9da593c995 100644 --- a/src/Windows/Avalonia.Win32/Win32Platform.cs +++ b/src/Windows/Avalonia.Win32/Win32Platform.cs @@ -16,6 +16,7 @@ using Avalonia.OpenGL.Egl; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Threading; +using Avalonia.Utilities; using Avalonia.Win32.Input; using Avalonia.Win32.Interop; using static Avalonia.Win32.Interop.UnmanagedMethods; @@ -110,6 +111,7 @@ namespace Avalonia.Win32 .Bind().ToConstant(s_instance) .Bind().ToSingleton() .Bind().ToConstant(s_instance) + .Bind().ToConstant(new NonPumpingSyncContext.HelperImpl()) .Bind().ToConstant(new WindowsMountedVolumeInfoProvider()); Win32GlManager.Initialize();