From b2274ea127d376756cbb3ef08b86a102b5b53024 Mon Sep 17 00:00:00 2001 From: Yoshi Askharoun Date: Wed, 6 Oct 2021 17:04:15 -0500 Subject: [PATCH] Prevent UIX from blocking UI thread with MainLoop --- .../Iris/Render/WpfRenderWindow.WPF.cs | 111 ++++++++++++------ UIX.Skia/Microsoft/Iris/Application.cs | 4 + UIX.Skia/Microsoft/Iris/Debug/Trace.cs | 10 +- .../Microsoft/Iris/Debug/TraceSettings.cs | 22 +--- UIX.Skia/Microsoft/Iris/Queues/Dispatcher.cs | 6 +- Xune.Wpf/MainWindow.xaml.cs | 15 ++- 6 files changed, 113 insertions(+), 55 deletions(-) diff --git a/UIX.RenderApi.Skia/Microsoft/Iris/Render/WpfRenderWindow.WPF.cs b/UIX.RenderApi.Skia/Microsoft/Iris/Render/WpfRenderWindow.WPF.cs index 9d7a745..c8e1a9c 100644 --- a/UIX.RenderApi.Skia/Microsoft/Iris/Render/WpfRenderWindow.WPF.cs +++ b/UIX.RenderApi.Skia/Microsoft/Iris/Render/WpfRenderWindow.WPF.cs @@ -199,20 +199,31 @@ namespace Microsoft.Iris.Render } set { - if (WpfWindow.Content is Control ctl) + WpfWindow.Dispatcher.Invoke(() => { - ctl.Background = new SolidColorBrush(Color.FromArgb( - (byte)(value.A * 255), - (byte)(value.R * 255), - (byte)(value.G * 255), - (byte)(value.B * 255) - )); - } + if (WpfWindow.Content is Control ctl) + { + ctl.Background = new SolidColorBrush(Color.FromArgb( + (byte)(value.A * 255), + (byte)(value.R * 255), + (byte)(value.G * 255), + (byte)(value.B * 255) + )); + } + }); } } public override bool EnableExternalDragDrop { - get => WpfWindow.AllowDrop; + get + { + bool drop = false; + WpfWindow.Dispatcher.Invoke(() => + { + drop = WpfWindow.AllowDrop; + }); + return drop; + } set => WpfWindow.AllowDrop = true; } public override bool IsDragInProgress { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } @@ -222,17 +233,21 @@ namespace Microsoft.Iris.Render get => isFullscreen; set { - isFullscreen = value; - if (isFullscreen) + + WpfWindow.Dispatcher.Invoke(() => { - WpfWindow.WindowStyle = WindowStyle.None; - WpfWindow.WindowState = System.Windows.WindowState.Maximized; - } - else - { - WpfWindow.WindowStyle = WindowStyle.SingleBorderWindow; - WpfWindow.WindowState = System.Windows.WindowState.Normal; - } + isFullscreen = value; + if (isFullscreen) + { + WpfWindow.WindowStyle = WindowStyle.None; + WpfWindow.WindowState = System.Windows.WindowState.Maximized; + } + else + { + WpfWindow.WindowStyle = WindowStyle.SingleBorderWindow; + WpfWindow.WindowState = System.Windows.WindowState.Normal; + } + }); } } @@ -327,11 +342,22 @@ namespace Microsoft.Iris.Render public override void ClientToScreen(ref Point point) { - var p = WpfWindow.PointToScreen(new System.Windows.Point(point.X, point.Y)); - point = new Point((int)p.X, (int)p.Y); + var locPoint = point; + WpfWindow.Dispatcher.Invoke(() => + { + var p = WpfWindow.PointToScreen(new System.Windows.Point(locPoint.X, locPoint.Y)); + locPoint = new Point((int)p.X, (int)p.Y); + }); + point = locPoint; } - public override void Close(FormCloseReason fcrCloseReason) => WpfWindow.Close(); + public override void Close(FormCloseReason fcrCloseReason) + { + WpfWindow.Dispatcher.Invoke(() => + { + WpfWindow.Close(); + }); + } public override IHwndHostWindow CreateHwndHostWindow() { @@ -360,21 +386,32 @@ namespace Microsoft.Iris.Render public override void Restore() { - WpfWindow.WindowState = System.Windows.WindowState.Normal; + WpfWindow.Dispatcher.Invoke(() => + { + WpfWindow.WindowState = System.Windows.WindowState.Normal; + }); } public override void ScreenToClient(ref Point point) { - var p = WpfWindow.PointFromScreen(new System.Windows.Point(point.X, point.Y)); - point = new Point((int)p.X, (int)p.Y); + var locPoint = point; + WpfWindow.Dispatcher.Invoke(() => + { + var p = WpfWindow.PointFromScreen(new System.Windows.Point(locPoint.X, locPoint.Y)); + locPoint = new Point((int)p.X, (int)p.Y); + }); + point = locPoint; } public override void SetCapture(IRawInputSite captureSite, bool state) { - if (state) - WpfWindow.CaptureMouse(); - else - WpfWindow.ReleaseMouseCapture(); + WpfWindow.Dispatcher.Invoke(() => + { + if (state) + WpfWindow.CaptureMouse(); + else + WpfWindow.ReleaseMouseCapture(); + }); } public override void SetDragDropResult(uint nDragOverResult, uint nDragDropResult) @@ -389,7 +426,10 @@ namespace Microsoft.Iris.Render public override void SetIcon(string sModuleName, uint nResourceID, IconFlags nOptions) { - WpfWindow.Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(sModuleName)); + WpfWindow.Dispatcher.Invoke(() => + { + WpfWindow.Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(sModuleName)); + }); } public override void SetMouseIdleOptions(Size sizeMouseIdleTolerance, uint nMouseIdleDelay) @@ -399,10 +439,13 @@ namespace Microsoft.Iris.Render public override void SetWindowOptions(WindowOptions options, bool enable) { - if (options.HasFlag(WindowOptions.FreeformResize)) - WpfWindow.ResizeMode = enable ? ResizeMode.CanResize : ResizeMode.NoResize; - if (options.HasFlag(WindowOptions.EnableCursor)) - WpfWindow.Cursor = enable ? System.Windows.Input.Cursors.Arrow : System.Windows.Input.Cursors.None; + WpfWindow.Dispatcher.Invoke(() => + { + if (options.HasFlag(WindowOptions.FreeformResize)) + WpfWindow.ResizeMode = enable ? ResizeMode.CanResize : ResizeMode.NoResize; + if (options.HasFlag(WindowOptions.EnableCursor)) + WpfWindow.Cursor = enable ? WpfCursors.Arrow : WpfCursors.None; + }); } public override void TakeFocus() => WpfWindow.Focus(); diff --git a/UIX.Skia/Microsoft/Iris/Application.cs b/UIX.Skia/Microsoft/Iris/Application.cs index 6ae9134..7785bd4 100644 --- a/UIX.Skia/Microsoft/Iris/Application.cs +++ b/UIX.Skia/Microsoft/Iris/Application.cs @@ -145,6 +145,10 @@ namespace Microsoft.Iris Debug.Assert.IsNotNull(skSurface, nameof(skSurface)); VerifyTrustedEnvironment(); +#if DEBUG + Debug.Trace.EnableAllCategories(true); +#endif + s_session = new UISession(skSurface, renderWindow); s_session.IsRtl = s_IsRTL; s_session.InputManager.KeyCoalescePolicy = new KeyCoalesceFilter(QueryKeyCoalesce); diff --git a/UIX.Skia/Microsoft/Iris/Debug/Trace.cs b/UIX.Skia/Microsoft/Iris/Debug/Trace.cs index a2b8fd0..4c9d0c4 100644 --- a/UIX.Skia/Microsoft/Iris/Debug/Trace.cs +++ b/UIX.Skia/Microsoft/Iris/Debug/Trace.cs @@ -128,9 +128,13 @@ namespace Microsoft.Iris.Debug public static void EnableCategory(TraceCategory cat, bool enabled) { - byte level = 0; - if (enabled) level = 1; - TraceSettings.SetCategoryLevel(cat, level); + TraceSettings.SetCategoryLevel(cat, (byte)(enabled ? 1 : 0)); + } + + public static void EnableAllCategories(bool enabled) + { + foreach (Enum e in Enum.GetValues(typeof(TraceCategory))) + EnableCategory((TraceCategory)e, enabled); } [Conditional("DEBUG")] diff --git a/UIX.Skia/Microsoft/Iris/Debug/TraceSettings.cs b/UIX.Skia/Microsoft/Iris/Debug/TraceSettings.cs index 8ee7684..e349738 100644 --- a/UIX.Skia/Microsoft/Iris/Debug/TraceSettings.cs +++ b/UIX.Skia/Microsoft/Iris/Debug/TraceSettings.cs @@ -6,7 +6,7 @@ using Microsoft.Iris.OS; using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.Security; namespace Microsoft.Iris.Debug @@ -14,7 +14,7 @@ namespace Microsoft.Iris.Debug [SuppressUnmanagedCodeSecurity] internal static class TraceSettings { - private static Dictionary CategoryLevels = new(); + private static ConcurrentDictionary CategoryLevels = new(); private static string s_debugTraceFile; @@ -38,32 +38,22 @@ namespace Microsoft.Iris.Debug public static byte GetCategoryLevel(TraceCategory cat) { if (CategoryLevels.TryGetValue(cat, out byte level)) - { return level; - } else - { - CategoryLevels.Add(cat, 0); - return GetCategoryLevel(cat); - } + return 0; } public static void SetCategoryLevel(TraceCategory cat, byte level) { - if (CategoryLevels.ContainsKey(cat)) - { - CategoryLevels[cat] = level; - } - else - { - CategoryLevels.Add(cat, level); - } + CategoryLevels.AddOrUpdate(cat, level, UpdateValueFactory); } public static bool IsFlagsCategory(TraceCategory cat) => false; private static bool IsExternalCategory(TraceCategory cat) => (uint)cat < 25U; + private static byte UpdateValueFactory(TraceCategory cat, byte level) => level; + public static bool SendOutputToDebugger { get; set; } = true; public static bool TimedWriteLines { get; set; } = false; diff --git a/UIX.Skia/Microsoft/Iris/Queues/Dispatcher.cs b/UIX.Skia/Microsoft/Iris/Queues/Dispatcher.cs index 330691d..8441b18 100644 --- a/UIX.Skia/Microsoft/Iris/Queues/Dispatcher.cs +++ b/UIX.Skia/Microsoft/Iris/Queues/Dispatcher.cs @@ -72,7 +72,11 @@ namespace Microsoft.Iris.Queues QueueItem nextItem = queue.GetNextItem(); if (nextItem != null) { - SendDebugMessage(nextItem.ToDebugPacketString()); +#if DEBUG + string debugString = nextItem.ToDebugPacketString(); + SendDebugMessage(debugString); + Debug.Trace.WriteLine(Debug.TraceCategory.Dispatcher, debugString); +#endif nextItem.Dispatch(); } else diff --git a/Xune.Wpf/MainWindow.xaml.cs b/Xune.Wpf/MainWindow.xaml.cs index 52c699e..5cbfe25 100644 --- a/Xune.Wpf/MainWindow.xaml.cs +++ b/Xune.Wpf/MainWindow.xaml.cs @@ -1,4 +1,5 @@ using Microsoft.Iris.Render; +using SkiaSharp; using SkiaSharp.Views.Desktop; using System; using System.Collections.Generic; @@ -22,10 +23,14 @@ namespace Xune.Wpf /// public partial class MainWindow : Window { + public static MainWindow Current { get; private set; } + private static SKSurface Surface { get; set; } + public MainWindow() { InitializeComponent(); + Current = this; Canvas.PaintSurface += Canvas_PaintSurface; } @@ -38,8 +43,16 @@ namespace Xune.Wpf return; } - Microsoft.Iris.Application.Initialize(e.Surface, new WpfRenderWindow(this)); + Surface = e.Surface; + var initTask = new Task(Init); + initTask.Start(); + } + + private void Init() + { + Microsoft.Iris.Application.Initialize(Surface, new WpfRenderWindow(this)); Microsoft.Iris.Application.LoadMarkup(@"file://D:\Repos\yoshiask\ZuneUIXTools\test\testA.uix"); + Microsoft.Iris.Application.Run(); } } }