From c7c1e451b0311d330bc8e9eaa13a8f6a94d96f94 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Thu, 18 May 2023 10:26:08 +0200 Subject: [PATCH 01/37] chore: Start breaking down WPF Skia host to separate app hosting and window hosting --- .../GtkHost.HarfbuzzPreload.cs | 2 +- src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs | 2 +- .../FramebufferHost.cs | 2 +- .../Hosting/IWpfApplicationHost.cs | 22 +++ .../Hosting/IWpfWindowHost.cs | 12 ++ .../Hosting/IWpfXamlRootHost.cs | 14 ++ .../Hosting/XamlRootMap.cs | 6 +- src/Uno.UI.Runtime.Skia.Wpf/IWpfHost.cs | 25 --- .../Rendering/OpenGLWpfRenderer.cs | 4 +- .../Rendering/SoftwareWpfRenderer.cs | 5 +- .../Themes/Generic.xaml | 4 +- src/Uno.UI.Runtime.Skia.Wpf/UnoWpfWindow.cs | 185 ++++++++++++++++++ src/Uno.UI.Runtime.Skia.Wpf/WpfHost.cs | 166 +--------------- .../UnoXamlHostBase.cs | 6 +- .../UnoXamlHostBase.host.cs | 6 +- src/Uno.UI/UI/Xaml/Application.skia.cs | 2 +- src/Uno.UI/UI/Xaml/ISkiaApplicationHost.cs | 5 + src/Uno.UI/UI/Xaml/ISkiaHost.cs | 5 - 18 files changed, 265 insertions(+), 208 deletions(-) create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfApplicationHost.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs delete mode 100644 src/Uno.UI.Runtime.Skia.Wpf/IWpfHost.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/UnoWpfWindow.cs create mode 100644 src/Uno.UI/UI/Xaml/ISkiaApplicationHost.cs delete mode 100644 src/Uno.UI/UI/Xaml/ISkiaHost.cs diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.HarfbuzzPreload.cs b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.HarfbuzzPreload.cs index 7ef035f7564b..9f416fd9213c 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.HarfbuzzPreload.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.HarfbuzzPreload.cs @@ -6,7 +6,7 @@ namespace Uno.UI.Runtime.Skia { - public partial class GtkHost : ISkiaHost + public partial class GtkHost : ISkiaApplicationHost { private void PreloadHarfBuzz() { diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs index 01799de3cc3f..7c5f04e1436f 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/GtkHost.cs @@ -42,7 +42,7 @@ namespace Uno.UI.Runtime.Skia { - public partial class GtkHost : ISkiaHost + public partial class GtkHost : ISkiaApplicationHost { private const int UnoThemePriority = 800; diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs index 43f747dce758..9ea70786af99 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs @@ -12,7 +12,7 @@ namespace Uno.UI.Runtime.Skia { - public class FrameBufferHost : ISkiaHost + public class FrameBufferHost : ISkiaApplicationHost { [ThreadStatic] private static bool _isDispatcherThread = false; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfApplicationHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfApplicationHost.cs new file mode 100644 index 000000000000..a05bdf1e332a --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfApplicationHost.cs @@ -0,0 +1,22 @@ +#nullable enable + +using Windows.UI.Xaml; + +namespace Uno.UI.Runtime.Skia.Wpf.Hosting; + +internal interface IWpfApplicationHost : ISkiaApplicationHost +{ + bool IsIsland { get; } + + UIElement? RootElement { get; } + + XamlRoot? XamlRoot { get; } + + public bool IgnorePixelScaling { get; } + + void ReleasePointerCapture(); + + void SetPointerCapture(); + + void InvalidateRender(); +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs new file mode 100644 index 000000000000..452d32febd61 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs @@ -0,0 +1,12 @@ +#nullable enable + +using Uno; +using Windows.UI.Xaml; +using WpfCanvas = System.Windows.Controls.Canvas; + +namespace Uno.UI.Runtime.Skia.Wpf.Hosting; + +internal interface IWpfWindowHost : IWpfXamlRootHost +{ + WpfCanvas? NativeOverlayLayer { get; } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs new file mode 100644 index 000000000000..b1d46734db47 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs @@ -0,0 +1,14 @@ +#nullable enable + +using Uno; +using Windows.UI.Xaml; +using WpfCanvas = System.Windows.Controls.Canvas; + +namespace Uno.UI.Runtime.Skia.Wpf.Hosting; + +internal interface IWpfXamlRootHost +{ + WpfCanvas? NativeOverlayLayer { get; } + + XamlRoot? XamlRoot { get; } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/XamlRootMap.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/XamlRootMap.cs index 5de6c5152965..d127e04fa431 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/XamlRootMap.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/XamlRootMap.cs @@ -9,9 +9,9 @@ namespace Uno.UI.XamlHost.Skia.Wpf.Hosting; internal static class XamlRootMap { - private static readonly Dictionary _map = new(); + private static readonly Dictionary _map = new(); - internal static void Register(XamlRoot xamlRoot, IWpfHost host) + internal static void Register(XamlRoot xamlRoot, IWpfApplicationHost host) { if (xamlRoot is null) { @@ -44,6 +44,6 @@ internal static void Unregister(XamlRoot xamlRoot) } } - internal static IWpfHost? GetHostForRoot(XamlRoot xamlRoot) => + internal static IWpfApplicationHost? GetHostForRoot(XamlRoot xamlRoot) => _map.TryGetValue(xamlRoot, out var host) ? host : null; } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/IWpfHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/IWpfHost.cs deleted file mode 100644 index 7edbb4aec413..000000000000 --- a/src/Uno.UI.Runtime.Skia.Wpf/IWpfHost.cs +++ /dev/null @@ -1,25 +0,0 @@ -#nullable enable - -using Windows.Devices.Input; -using Windows.UI.Composition; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Input; -using WpfCanvas = System.Windows.Controls.Canvas; - -namespace Uno.UI.Runtime.Skia.Wpf -{ - internal interface IWpfHost - { - bool IsIsland { get; } - - UIElement? RootElement { get; } - - XamlRoot? XamlRoot { get; } - - WpfCanvas? NativeOverlayLayer { get; } - - public bool IgnorePixelScaling { get; } - - void InvalidateRender(); - } -} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs index ca2b930104e1..d7d4097e6105 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs @@ -21,7 +21,7 @@ internal partial class OpenGLWpfRenderer : IWpfRenderer private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.TopLeft; private readonly WpfControl _hostControl; - private readonly IWpfHost _host; + private readonly IWpfApplicationHost _host; private DisplayInformation? _displayInformation; private nint _hwnd; private nint _hdc; @@ -31,7 +31,7 @@ internal partial class OpenGLWpfRenderer : IWpfRenderer private GRBackendRenderTarget? _renderTarget; private WriteableBitmap? _backBuffer; - public OpenGLWpfRenderer(IWpfHost host) + public OpenGLWpfRenderer(IWpfApplicationHost host) { _hostControl = host as WpfControl ?? throw new InvalidOperationException("Host should be a WPF control"); _host = host; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs index 4f5e8334e56c..cd5e8f565b23 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs @@ -5,6 +5,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using SkiaSharp; +using Uno.UI.Runtime.Skia.Wpf.Hosting; using Windows.Graphics.Display; using WinUI = Windows.UI.Xaml; using WpfControl = global::System.Windows.Controls.Control; @@ -16,9 +17,9 @@ internal class SoftwareWpfRenderer : IWpfRenderer private WpfControl _hostControl; private DisplayInformation? _displayInformation; private WriteableBitmap? _bitmap; - private IWpfHost _host; + private IWpfApplicationHost _host; - public SoftwareWpfRenderer(IWpfHost host) + public SoftwareWpfRenderer(IWpfApplicationHost host) { _hostControl = host as WpfControl ?? throw new InvalidOperationException("Host should be a WPF control"); _host = host; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml b/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml index f5de096c0744..68fa30e7e1fa 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml +++ b/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml @@ -1,10 +1,10 @@ - - + diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs index 86493fdb03fb..a3f42eca5ebf 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs @@ -3,6 +3,7 @@ using System; using System.IO; using System.Windows; +using System.Windows.Controls; using System.Windows.Media; using Uno.Disposables; using Uno.Foundation.Logging; @@ -15,27 +16,29 @@ using Uno.UI.Xaml.Hosting; using Uno.UI.XamlHost.Skia.Wpf; using Uno.UI.XamlHost.Skia.Wpf.Hosting; +using Windows.Networking.BackgroundTransfer; using Windows.UI.ViewManagement; using Windows.UI.Xaml.Input; using WinUI = Windows.UI.Xaml; using WpfApplication = System.Windows.Application; using WpfCanvas = System.Windows.Controls.Canvas; using WpfControl = System.Windows.Controls.Control; +using WpfContentPresenter = System.Windows.Controls.ContentPresenter; using WpfFrameworkPropertyMetadata = System.Windows.FrameworkPropertyMetadata; using WpfWindow = System.Windows.Window; namespace Uno.UI.Skia.Wpf; -[TemplatePart(Name = NativeOverlayLayerPart, Type = typeof(WpfCanvas))] +[TemplatePart(Name = NativeOverlayLayerHostPart, Type = typeof(WpfCanvas))] internal class UnoWpfWindow : WpfWindow, IWpfWindowHost { - private const string NativeOverlayLayerPart = "NativeOverlayLayer"; + private const string NativeOverlayLayerHostPart = "NativeOverlayLayerHost"; + private readonly WpfCanvas _nativeOverlayLayer = new(); private readonly WinUI.Window _window; private readonly CompositeDisposable _disposables = new(); private readonly HostPointerHandler? _hostPointerHandler; - private WpfCanvas? _nativeOverlayLayer; private IWpfRenderer? _renderer; private FocusManager? _focusManager; private bool _rendererInitialized; @@ -97,7 +100,10 @@ public override void OnApplyTemplate() { base.OnApplyTemplate(); - _nativeOverlayLayer = GetTemplateChild(NativeOverlayLayerPart) as WpfCanvas; + if (GetTemplateChild(NativeOverlayLayerHostPart) is WpfContentPresenter nativeOverlayLayerHost) + { + nativeOverlayLayerHost.Content = _nativeOverlayLayer; + } } private void WpfHost_Loaded(object sender, RoutedEventArgs e) From 36407cc91a698c865547c309e152f3f4b0c71b5c Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Sun, 4 Jun 2023 12:39:47 +0200 Subject: [PATCH 15/37] chore: XamlRoot adjustments, internals --- .../Extensions/GtkCoreWindowExtension.cs | 1 - .../Hosting/IGtkWindowHost.cs | 7 + .../Hosting/XamlRootMap.cs | 3 +- .../UI/Controls/GtkTextBoxView.cs | 1 - .../UI/Controls/UnoGtkWindow.cs | 254 +++++++++--------- .../Uno.UI.Runtime.Skia.Gtk.csproj | 2 +- .../FramebufferHost.cs | 5 +- .../UI/Controls/UnoWpfWindow.cs | 4 +- .../UnoXamlHostBase.host.cs | 15 +- src/Uno.UI/AssemblyInfo.skia.cs | 1 + .../UI/Xaml/Hosting/IXamlRootHost.skia.cs | 4 - 11 files changed, 154 insertions(+), 143 deletions(-) create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Extensions/GtkCoreWindowExtension.cs b/src/Uno.UI.Runtime.Skia.Gtk/Extensions/GtkCoreWindowExtension.cs index 6d9cd813e707..7470c88a6f62 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Extensions/GtkCoreWindowExtension.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Extensions/GtkCoreWindowExtension.cs @@ -21,7 +21,6 @@ using Windows.UI.Xaml; using Uno.UI.Xaml.Core; using Windows.Foundation; -using Uno.UI.XamlHost.Skia.Gtk.Hosting; using Atk; namespace Uno.UI.Runtime.Skia diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs new file mode 100644 index 000000000000..0d9885e034b2 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs @@ -0,0 +1,7 @@ +using Uno.UI.Xaml.Hosting; + +namespace Uno.UI.Runtime.Skia.GTK.Hosting; + +internal interface IGtkWindowHost : IXamlRootHost +{ +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/XamlRootMap.cs b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/XamlRootMap.cs index dc34b1d19efd..19ca6f3473ea 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/XamlRootMap.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/XamlRootMap.cs @@ -3,10 +3,9 @@ using System; using System.Collections.Generic; using Uno.UI.Runtime.Skia.GTK.Hosting; -using Uno.UI.Xaml.Hosting; using Windows.UI.Xaml; -namespace Uno.UI.XamlHost.Skia.Gtk.Hosting; +namespace Uno.UI.XamlHost.Skia.GTK.Hosting; internal static class XamlRootMap { diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/GtkTextBoxView.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/GtkTextBoxView.cs index 2caad7bb0424..67bc4edd4a15 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/GtkTextBoxView.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/GtkTextBoxView.cs @@ -7,7 +7,6 @@ using Uno.Foundation.Logging; using Uno.UI.Runtime.Skia.GTK.UI.Text; using Uno.UI.Xaml.Controls.Extensions; -using Uno.UI.XamlHost.Skia.Gtk.Hosting; using Windows.UI.Text; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs index df829adcbb51..ac6c4130ce50 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs @@ -7,7 +7,6 @@ using Uno.Foundation.Logging; using Uno.UI.Runtime.Skia.GTK.UI.Core; using Uno.UI.Xaml.Core; -using Uno.UI.XamlHost.Skia.Gtk.Hosting; using Windows.Foundation; using Windows.UI.Core.Preview; using Windows.UI.ViewManagement; @@ -16,11 +15,14 @@ using WinUIWindow = Windows.UI.Xaml.Window; using UnoApplication = Windows.UI.Xaml.Application; using WinUI = Windows.UI.Xaml; +using Uno.UI.Runtime.Skia.GTK.Hosting; +using Uno.UI.Xaml.Hosting; + namespace Uno.UI.Runtime.Skia.UI.Xaml.Controls; #pragma warning disable CS0649 #pragma warning disable CS0169 -internal class UnoGtkWindow : Gtk.Window +internal class UnoGtkWindow : Gtk.Window, IGtkWindowHost { private readonly WinUIWindow _window; @@ -61,14 +63,55 @@ public UnoGtkWindow(WinUIWindow window) : base(WindowType.Toplevel) WindowStateEvent += OnWindowStateChanged; - SetupRenderSurface(); + //SetupRenderSurface(); + + var overlay = new Overlay(); + + _eventBox = new UnoEventBox(); + + _renderSurface = BuildRenderSurfaceType(); + _area = (Widget)_renderSurface; + _fix = new Fixed(); + overlay.Add(_area); + overlay.AddOverlay(_fix); + _eventBox.Add(overlay); + Add(_eventBox); + + //// Show the whole tree again, since we may have + //// swapped the content with the GLValidationSurface. + //_window.ShowAll(); + + //if (this.Log().IsEnabled(LogLevel.Information)) + //{ + // this.Log().Info($"Using {RenderSurfaceType} rendering"); + //} + + //_area.Realized += (s, e) => + //{ + // WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(_area.AllocatedWidth, _area.AllocatedHeight)); + //}; + + //_area.SizeAllocated += (s, e) => + //{ + // WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(e.Allocation.Width, e.Allocation.Height)); + //}; + + ///* avoids double invokes at window level */ + //_area.AddEvents((int)GtkCoreWindowExtension.RequestedEvents); + + + CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet += OnCoreWindowContentRootSet; + + RegisterForBackgroundColor(); + UpdateWindowPropertiesFromPackage(); + + //ReplayPendingWindowStateChanges(); } private void OnShown(object? sender, EventArgs e) => ShowAll(); internal IRenderSurface? RenderSurface => _renderSurface; - internal Fixed? NativeOverlayLayer => GtkCoreWindowExtension.FindNativeOverlayLayer(this); internal static UnoEventBox? EventBox => _eventBox; @@ -187,131 +230,84 @@ private void UpdateWindowPropertiesFromPackage() } - //private IRenderSurface BuildRenderSurfaceType() - // => RenderSurfaceType switch - // { - // Skia.RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(), - // Skia.RenderSurfaceType.OpenGL => new OpenGLRenderSurface(), - // Skia.RenderSurfaceType.Software => new SoftwareRenderSurface(), - // _ => throw new InvalidOperationException($"Unsupported RenderSurfaceType {RenderSurfaceType}") - // }; - - - private void SetupRenderSurface() - { - //TryReadRenderSurfaceTypeEnvironment(); - - //if (!OpenGLRenderSurface.IsSupported && !OpenGLESRenderSurface.IsSupported) - //{ - // // Pre-validation is required to avoid initializing OpenGL on macOS - // // where the whole app may get visually corrupted even if OpenGL is not - // // used in the app. - - // if (this.Log().IsEnabled(LogLevel.Debug)) - // { - // this.Log().Debug($"Neither OpenGL or OpenGL ES are supporting, using software rendering"); - // } - - // RenderSurfaceType = Skia.RenderSurfaceType.Software; - //} - - //if (RenderSurfaceType == null) - //{ - // // Create a temporary surface to automatically detect - // // the OpenGL environment that can be used on the system. - // GLValidationSurface validationSurface = new(); - - // _window.Add(validationSurface); - // _window.ShowAll(); - - // DispatchNativeSingle(ValidatedSurface); - - // async void ValidatedSurface() - // { - // try - // { - // if (this.Log().IsEnabled(LogLevel.Debug)) - // { - // this.Log().Debug($"Auto-detecting surface type"); - // } - - // // Wait for a realization of the GLValidationSurface - // RenderSurfaceType = await validationSurface.GetSurfaceTypeAsync(); - - // // Continue on the GTK main thread - // DispatchNativeSingle(() => - // { - // if (this.Log().IsEnabled(LogLevel.Debug)) - // { - // this.Log().Debug($"Auto-detected {RenderSurfaceType} rendering"); - // } - - // _window.Remove(validationSurface); - - // FinalizeStartup(); - // }); - // } - // catch (Exception e) - // { - // if (this.Log().IsEnabled(LogLevel.Error)) - // { - // this.Log().Error($"Auto-detected failed", e); - // } - // } - // } - //} - //else - //{ - // FinalizeStartup(); - //} - } - - private void FinalizeStartup() - { - //var overlay = new Overlay(); - - //_eventBox = new UnoEventBox(); - - //_renderSurface = BuildRenderSurfaceType(); - //_area = (Widget)_renderSurface; - //_fix = new Fixed(); - //overlay.Add(_area); - //overlay.AddOverlay(_fix); - //_eventBox.Add(overlay); - //_window.Add(_eventBox); - - //// Show the whole tree again, since we may have - //// swapped the content with the GLValidationSurface. - //_window.ShowAll(); - - //if (this.Log().IsEnabled(LogLevel.Information)) - //{ - // this.Log().Info($"Using {RenderSurfaceType} rendering"); - //} - - //_area.Realized += (s, e) => - //{ - // WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(_area.AllocatedWidth, _area.AllocatedHeight)); - //}; - - //_area.SizeAllocated += (s, e) => - //{ - // WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(e.Allocation.Width, e.Allocation.Height)); - //}; - - ///* avoids double invokes at window level */ - //_area.AddEvents((int)GtkCoreWindowExtension.RequestedEvents); + private IRenderSurface BuildRenderSurfaceType() + => GtkHost.Current!.RenderSurfaceType switch + { + Skia.RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(this), + Skia.RenderSurfaceType.OpenGL => new OpenGLRenderSurface(this), + Skia.RenderSurfaceType.Software => new SoftwareRenderSurface(this), + _ => throw new InvalidOperationException($"Unsupported RenderSurfaceType {GtkHost.Current!.RenderSurfaceType}") + }; - //ReplayPendingWindowStateChanges(); - //CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet += OnCoreWindowContentRootSet; + //private void SetupRenderSurface() + //{ + // TryReadRenderSurfaceTypeEnvironment(); - //UpdateWindowPropertiesFromPackage(); + // if (!OpenGLRenderSurface.IsSupported && !OpenGLESRenderSurface.IsSupported) + // { + // // Pre-validation is required to avoid initializing OpenGL on macOS + // // where the whole app may get visually corrupted even if OpenGL is not + // // used in the app. - //RegisterForBackgroundColor(); - } + // if (this.Log().IsEnabled(LogLevel.Debug)) + // { + // this.Log().Debug($"Neither OpenGL or OpenGL ES are supporting, using software rendering"); + // } + // GtkHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.Software; + // } + // if (GtkHost.Current!.RenderSurfaceType == null) + // { + // // Create a temporary surface to automatically detect + // // the OpenGL environment that can be used on the system. + // GLValidationSurface validationSurface = new(); + + // Add(validationSurface); + // ShowAll(); + + // DispatchNativeSingle(ValidatedSurface); + + // async void ValidatedSurface() + // { + // try + // { + // if (this.Log().IsEnabled(LogLevel.Debug)) + // { + // this.Log().Debug($"Auto-detecting surface type"); + // } + + // // Wait for a realization of the GLValidationSurface + // RenderSurfaceType = await validationSurface.GetSurfaceTypeAsync(); + + // // Continue on the GTK main thread + // DispatchNativeSingle(() => + // { + // if (this.Log().IsEnabled(LogLevel.Debug)) + // { + // this.Log().Debug($"Auto-detected {RenderSurfaceType} rendering"); + // } + + // _window.Remove(validationSurface); + + // FinalizeStartup(); + // }); + // } + // catch (Exception e) + // { + // if (this.Log().IsEnabled(LogLevel.Error)) + // { + // this.Log().Error($"Auto-detected failed", e); + // } + // } + // } + // } + // else + // { + // FinalizeStartup(); + // } + //} private void TryReadRenderSurfaceTypeEnvironment() { @@ -370,6 +366,18 @@ private void OnCoreWindowContentRootSet(object sender, object e) //CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet -= OnCoreWindowContentRootSet; } + void IXamlRootHost.InvalidateRender() + { + //InvalidateOverlays(); + _renderSurface?.InvalidateRender(); + } + + bool IXamlRootHost.IsIsland => false; + + WinUI.UIElement? IXamlRootHost.RootElement => _window.RootElement; + + WinUI.XamlRoot? IXamlRootHost.XamlRoot => _window.RootElement?.XamlRoot; + private void WindowClosing(object sender, DeleteEventArgs args) { //var manager = SystemNavigationManagerPreview.GetForCurrentView(); diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj b/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj index eb87fd487698..646cb2f171b7 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj +++ b/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj @@ -16,7 +16,7 @@ Uno.WinUI.Runtime.Skia.Gtk - Uno.UI.Runtime.Skia + Uno.UI.Runtime.Skia.GTK true diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs index 9ea70786af99..595b8e2f47db 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/FramebufferHost.cs @@ -5,6 +5,7 @@ using Uno.Foundation.Extensibility; using Uno.Foundation.Logging; using Uno.UI.Xaml.Core; +using Uno.UI.Xaml.Hosting; using Uno.WinUI.Runtime.Skia.LinuxFB; using Windows.Graphics.Display; using Windows.UI.Xaml; @@ -12,7 +13,7 @@ namespace Uno.UI.Runtime.Skia { - public class FrameBufferHost : ISkiaApplicationHost + public class FrameBufferHost : ISkiaApplicationHost, IXamlRootHost { [ThreadStatic] private static bool _isDispatcherThread = false; @@ -119,7 +120,7 @@ void CreateApp(ApplicationInitializationCallbackParams _) Windows.UI.Core.CoreDispatcher.DispatchOverride = Dispatch; Windows.UI.Core.CoreDispatcher.HasThreadAccessOverride = () => _isDispatcherThread; - _renderer = new Renderer(); + _renderer = new Renderer(this); _displayInformationExtension!.Renderer = _renderer; CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet += OnCoreWindowContentRootSet; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs index a3f42eca5ebf..4328a7af254c 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs @@ -92,9 +92,9 @@ void IXamlRootHost.InvalidateRender() InvalidateVisual(); } - void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] + //void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] - void IXamlRootHost.SetPointerCapture() => CaptureMouse(); + //void IXamlRootHost.SetPointerCapture() => CaptureMouse(); public override void OnApplyTemplate() { diff --git a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs index 401fd7c16e98..a4295739723a 100644 --- a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs +++ b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs @@ -11,6 +11,7 @@ using WinUI = Windows.UI.Xaml; using WpfControl = global::System.Windows.Controls.Control; using WpfCanvas = global::System.Windows.Controls.Canvas; +using Uno.UI.Xaml.Hosting; using Uno.UI.Controls; using Uno.UI.Skia.Platform; using Uno.UI.Runtime.Skia.Wpf.Rendering; @@ -100,24 +101,24 @@ protected override void OnRender(DrawingContext drawingContext) _renderer?.Render(drawingContext); } - void IWpfXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] + void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] - void IWpfXamlRootHost.SetPointerCapture() => CaptureMouse(); + void IXamlRootHost.SetPointerCapture() => CaptureMouse(); - void IWpfXamlRootHost.InvalidateRender() + void IXamlRootHost.InvalidateRender() { //InvalidateOverlays(); InvalidateVisual(); } - bool IWpfXamlRootHost.IsIsland => true; + bool IXamlRootHost.IsIsland => true; - WinUI.UIElement? IWpfXamlRootHost.RootElement => _rootElement ??= _xamlSource?.GetVisualTreeRoot(); + WinUI.UIElement? IXamlRootHost.RootElement => _rootElement ??= _xamlSource?.GetVisualTreeRoot(); WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; - WinUI.XamlRoot? IWpfXamlRootHost.XamlRoot => ChildInternal?.XamlRoot; + WinUI.XamlRoot? IXamlRootHost.XamlRoot => ChildInternal?.XamlRoot; - bool IWpfXamlRootHost.IgnorePixelScaling => throw new NotImplementedException(); + bool IWpfXamlRootHost.IgnorePixelScaling => IgnorePixelScaling; } } diff --git a/src/Uno.UI/AssemblyInfo.skia.cs b/src/Uno.UI/AssemblyInfo.skia.cs index 2e25a48f8279..e469d3be1a5a 100644 --- a/src/Uno.UI/AssemblyInfo.skia.cs +++ b/src/Uno.UI/AssemblyInfo.skia.cs @@ -4,3 +4,4 @@ [assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Wpf")] [assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Tizen")] [assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Linux.FrameBuffer")] +[assembly: InternalsVisibleTo("Uno.UI.XamlHost.Skia.Wpf")] diff --git a/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs b/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs index 230b5ccce70f..6dff9ea88aa4 100644 --- a/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs +++ b/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs @@ -13,8 +13,4 @@ internal interface IXamlRootHost XamlRoot? XamlRoot { get; } void InvalidateRender(); - - void ReleasePointerCapture(); - - void SetPointerCapture(); } From 7632e77d16cdc27671e4b6c6ea4b3c596e7cebb0 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Sun, 4 Jun 2023 15:44:50 +0200 Subject: [PATCH 16/37] chore: Separate WPF window host and window itself --- .../Extensions/WpfCoreWindowExtension.cs | 15 +- .../Extensions/WpfExtensionsRegistrar.cs | 6 +- .../Input/WpfCorePointerInputSource.cs | 3 +- .../UI/Controls/UnoWpfWindow.cs | 260 +---------------- .../UI/Controls/UnoWpfWindowHost.cs | 265 ++++++++++++++++++ src/Uno.UI/UI/Xaml/Internal/InputManager.cs | 7 +- 6 files changed, 280 insertions(+), 276 deletions(-) create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfCoreWindowExtension.cs b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfCoreWindowExtension.cs index 0459f8537b05..a31318ea8bfd 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfCoreWindowExtension.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfCoreWindowExtension.cs @@ -28,8 +28,8 @@ namespace Uno.UI.Skia.Platform { internal partial class WpfCoreWindowExtension : ICoreWindowExtension { - private readonly ICoreWindowEvents _ownerEvents; - //private readonly WpfHost? _host; + private readonly WpfHost? _host; + private readonly CoreWindow _owner; public CoreCursor PointerCursor { @@ -39,7 +39,8 @@ public CoreCursor PointerCursor public WpfCoreWindowExtension(object owner) { - _ownerEvents = (ICoreWindowEvents)owner; + _owner = (CoreWindow)owner; + _host = WpfHost.Current; // TODO:MZ: Multi-window, attach to main window //_host = WpfHost.Current; @@ -62,14 +63,6 @@ public WpfCoreWindowExtension(object owner) //} } - // TODO:MZ: Fix - public void SetPointerCapture(PointerIdentifier pointer) { } - //=> WpfHost.Current?.CaptureMouse(); - - // TODO:MZ: Fix - public void ReleasePointerCapture(PointerIdentifier pointer) { } - //=> WpfHost.Current?.ReleaseMouseCapture(); - internal static WpfCanvas? GetOverlayLayer(XamlRoot xamlRoot) => XamlRootMap.GetHostForRoot(xamlRoot)?.NativeOverlayLayer; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs index 57c470e4cf1d..148158ffcaa5 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs @@ -10,11 +10,13 @@ using Uno.Helpers.Theming; using Uno.UI.Core.Preview; using Uno.UI.Runtime.Skia.Wpf.Extensions.UI.Xaml.Controls; -using Uno.UI.Runtime.Skia.Wpf.Extensions.UI.Xaml.Input; using Uno.UI.Runtime.Skia.Wpf.WPF.Extensions.Helpers.Theming; +using Uno.UI.Skia; using Uno.UI.Skia.Platform; using Uno.UI.Xaml.Controls.Extensions; +using Uno.UI.Xaml.Hosting; using Uno.UI.Xaml.Input; +using Uno.UI.XamlHost.Skia.Wpf; using Windows.Graphics.Display; using Windows.Networking.Connectivity; using Windows.Storage.Pickers; @@ -35,6 +37,7 @@ internal static void Register() } ApiExtensibility.Register(typeof(Uno.ApplicationModel.Core.ICoreApplicationExtension), o => new CoreApplicationExtension(o)); + ApiExtensibility.Register(typeof(Windows.UI.Core.IUnoCorePointerInputSource), o => new WpfCorePointerInputSource(o)); ApiExtensibility.Register(typeof(Windows.UI.Core.ICoreWindowExtension), o => new WpfCoreWindowExtension(o)); ApiExtensibility.Register(typeof(Windows.UI.ViewManagement.IApplicationViewExtension), o => new WpfApplicationViewExtension(o)); ApiExtensibility.Register(typeof(ISystemThemeHelperExtension), o => new WpfSystemThemeHelperExtension(o)); @@ -49,7 +52,6 @@ internal static void Register() ApiExtensibility.Register(typeof(IClipboardExtension), o => new ClipboardExtensions(o)); ApiExtensibility.Register(typeof(IAnalyticsInfoExtension), o => new AnalyticsInfoExtension()); ApiExtensibility.Register(typeof(ISystemNavigationManagerPreviewExtension), o => new SystemNavigationManagerPreviewExtension()); - ApiExtensibility.Register(typeof(IPointerExtension), o => new PointerExtension()); _registered = true; } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs b/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs index 2332dd834228..cd19162cce8d 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs @@ -8,6 +8,7 @@ using Uno.UI.Runtime.Skia.Wpf; using Uno.UI.Runtime.Skia.Wpf.Constants; using Uno.UI.Runtime.Skia.Wpf.Input; +using Uno.UI.Xaml.Hosting; using Windows.Devices.Input; using Windows.Foundation; using Windows.System; @@ -35,7 +36,7 @@ internal sealed class WpfCorePointerInputSource : IUnoCorePointerInputSource private HwndSource? _hwndSource; private PointerEventArgs? _previous; - public WpfCorePointerInputSource(IWpfHost host) + public WpfCorePointerInputSource(IXamlRootHost host) { if (host is null) return; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs index 4328a7af254c..ab2ed965da18 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindow.cs @@ -1,272 +1,18 @@ #nullable enable using System; -using System.IO; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using Uno.Disposables; -using Uno.Foundation.Logging; -using Uno.UI.Controls; -using Uno.UI.Runtime.Skia.Wpf.Extensions; -using Uno.UI.Runtime.Skia.Wpf.Hosting; -using Uno.UI.Runtime.Skia.Wpf.Rendering; -using Uno.UI.Skia.Platform; -using Uno.UI.Xaml.Core; -using Uno.UI.Xaml.Hosting; -using Uno.UI.XamlHost.Skia.Wpf; -using Uno.UI.XamlHost.Skia.Wpf.Hosting; -using Windows.Networking.BackgroundTransfer; -using Windows.UI.ViewManagement; -using Windows.UI.Xaml.Input; using WinUI = Windows.UI.Xaml; -using WpfApplication = System.Windows.Application; -using WpfCanvas = System.Windows.Controls.Canvas; -using WpfControl = System.Windows.Controls.Control; -using WpfContentPresenter = System.Windows.Controls.ContentPresenter; -using WpfFrameworkPropertyMetadata = System.Windows.FrameworkPropertyMetadata; using WpfWindow = System.Windows.Window; namespace Uno.UI.Skia.Wpf; -[TemplatePart(Name = NativeOverlayLayerHostPart, Type = typeof(WpfCanvas))] -internal class UnoWpfWindow : WpfWindow, IWpfWindowHost +internal class UnoWpfWindow : WpfWindow { - private const string NativeOverlayLayerHostPart = "NativeOverlayLayerHost"; - - private readonly WpfCanvas _nativeOverlayLayer = new(); - private readonly WinUI.Window _window; - private readonly CompositeDisposable _disposables = new(); - private readonly HostPointerHandler? _hostPointerHandler; - - private IWpfRenderer? _renderer; - private FocusManager? _focusManager; - private bool _rendererInitialized; - - static UnoWpfWindow() - { - DefaultStyleKeyProperty.OverrideMetadata( - typeof(UnoWpfWindow), - new WpfFrameworkPropertyMetadata(typeof(UnoWpfWindow))); - } - public UnoWpfWindow(WinUI.Window window) { - _window = window; - _window.Shown += OnShown; - _hostPointerHandler = new HostPointerHandler(this); - - FocusVisualStyle = null; - - SizeChanged += WpfHost_SizeChanged; - Loaded += WpfHost_Loaded; - - Windows.Foundation.Size preferredWindowSize = ApplicationView.PreferredLaunchViewSize; - if (preferredWindowSize != Windows.Foundation.Size.Empty) - { - Width = (int)preferredWindowSize.Width; - Height = (int)preferredWindowSize.Height; - } - - CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet += OnCoreWindowContentRootSet; - - RegisterForBackgroundColor(); - UpdateWindowPropertiesFromPackage(); + window.Shown += OnShown; + Content = new UnoWpfWindowHost(this, window); } private void OnShown(object? sender, EventArgs e) => Show(); - - WinUI.UIElement? IXamlRootHost.RootElement => _window.RootElement; - - WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; - - WinUI.XamlRoot? IXamlRootHost.XamlRoot => _window.RootElement?.XamlRoot; - - public bool IgnorePixelScaling => WpfHost.Current!.IgnorePixelScaling; - - public bool IsIsland => false; - - void IXamlRootHost.InvalidateRender() - { - InvalidateOverlays(); - InvalidateVisual(); - } - - //void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] - - //void IXamlRootHost.SetPointerCapture() => CaptureMouse(); - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (GetTemplateChild(NativeOverlayLayerHostPart) is WpfContentPresenter nativeOverlayLayerHost) - { - nativeOverlayLayerHost.Content = _nativeOverlayLayer; - } - } - - private void WpfHost_Loaded(object sender, RoutedEventArgs e) - { - WinUI.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(ActualWidth, ActualHeight)); - - // Avoid dotted border on focus. - if (Parent is WpfControl control) - { - control.FocusVisualStyle = null; - } - } - - private void InitializeRenderer() - { - // TODO:MZ: Do this only once, not for every window - if (WpfHost.Current!.RenderSurfaceType is null) - { - WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.OpenGL; - } - - if (this.Log().IsEnabled(LogLevel.Debug)) - { - this.Log().Debug($"Using {WpfHost.Current!.RenderSurfaceType} rendering"); - } - - _renderer = WpfHost.Current!.RenderSurfaceType switch - { - Skia.RenderSurfaceType.Software => new SoftwareWpfRenderer(this), - Skia.RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(this), - _ => throw new InvalidOperationException($"Render Surface type {WpfHost.Current!.RenderSurfaceType} is not supported") - }; - - UpdateRendererBackground(); - - if (!_renderer.Initialize()) - { - // OpenGL initialization failed, fallback to software rendering - // This may happen on headless systems or containers. - - if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"OpenGL failed to initialize, using software rendering"); - } - - WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.Software; - InitializeRenderer(); - } - else - { - _rendererInitialized = true; - } - } - - private void OnCoreWindowContentRootSet(object? sender, object e) - { - var xamlRoot = CoreServices.Instance - .ContentRootCoordinator - .CoreWindowContentRoot? - .GetOrCreateXamlRoot(); - - if (xamlRoot is null) - { - throw new InvalidOperationException("XamlRoot was not properly initialized"); - } - - XamlRootMap.Register(xamlRoot, this); - - CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet -= OnCoreWindowContentRootSet; - } - - private void UpdateWindowPropertiesFromPackage() - { - if (Windows.ApplicationModel.Package.Current.Logo is Uri uri) - { - var basePath = uri.OriginalString.Replace('\\', Path.DirectorySeparatorChar); - var iconPath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledPath, basePath); - - if (File.Exists(iconPath)) - { - if (this.Log().IsEnabled(LogLevel.Information)) - { - this.Log().Info($"Loading icon file [{iconPath}] from Package.appxmanifest file"); - } - - Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(iconPath)); - } - else if (Windows.UI.Xaml.Media.Imaging.BitmapImage.GetScaledPath(basePath) is { } scaledPath && File.Exists(scaledPath)) - { - if (this.Log().IsEnabled(LogLevel.Information)) - { - this.Log().Info($"Loading icon file [{scaledPath}] scaled logo from Package.appxmanifest file"); - } - - Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(scaledPath)); - } - else - { - if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"Unable to find icon file [{iconPath}] specified in the Package.appxmanifest file."); - } - } - } - - Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Title = Windows.ApplicationModel.Package.Current.DisplayName; - } - - private void WpfHost_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e) - { - // TODO:MZ: Use Content.Size! - WinUI.Window.Current.OnNativeSizeChanged( - new Windows.Foundation.Size( - e.NewSize.Width, - e.NewSize.Height - ) - ); - } - - private void RegisterForBackgroundColor() - { - UpdateRendererBackground(); - - _disposables.Add(_window.RegisterBackgroundChangedEvent((s, e) => UpdateRendererBackground())); - } - - private void UpdateRendererBackground() - { - if (_window.Background is WinUI.Media.SolidColorBrush brush) - { - if (_renderer is not null) - { - _renderer.BackgroundColor = brush.Color; - Background = new SolidColorBrush(brush.Color.ToWpfColor()); - } - } - else - { - if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"This platform only supports SolidColorBrush for the Window background"); - } - } - } - - protected override void OnRender(DrawingContext drawingContext) - { - base.OnRender(drawingContext); - - if (!_rendererInitialized) - { - InitializeRenderer(); - } - _renderer?.Render(drawingContext); - } - - private void InvalidateOverlays() - { - _focusManager ??= VisualTree.GetFocusManagerForElement(_window.RootElement); - _focusManager?.FocusRectManager?.RedrawFocusVisual(); - if (_focusManager?.FocusedElement is Windows.UI.Xaml.Controls.TextBox textBox) - { - textBox.TextBoxView?.Extension?.InvalidateLayout(); - } - } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs new file mode 100644 index 000000000000..159dc220d511 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs @@ -0,0 +1,265 @@ +#nullable enable + +using Uno.UI.Runtime.Skia.Wpf.Hosting; +using System; +using System.IO; +using System.Windows; +using System.Windows.Media; +using Uno.Disposables; +using Uno.Foundation.Logging; +using Uno.UI.Runtime.Skia.Wpf.Extensions; +using Uno.UI.Runtime.Skia.Wpf.Rendering; +using Uno.UI.Xaml.Core; +using Uno.UI.Xaml.Hosting; +using Uno.UI.XamlHost.Skia.Wpf.Hosting; +using Windows.UI.ViewManagement; +using Windows.UI.Xaml.Input; +using WinUI = Windows.UI.Xaml; +using WpfCanvas = System.Windows.Controls.Canvas; +using WpfControl = System.Windows.Controls.Control; +using WpfContentPresenter = System.Windows.Controls.ContentPresenter; +using WpfFrameworkPropertyMetadata = System.Windows.FrameworkPropertyMetadata; +using WpfWindow = System.Windows.Window; + +namespace Uno.UI.Skia.Wpf; + +[TemplatePart(Name = NativeOverlayLayerHostPart, Type = typeof(WpfCanvas))] +internal class UnoWpfWindowHost : WpfControl, IWpfWindowHost +{ + private const string NativeOverlayLayerHostPart = "NativeOverlayLayerHost"; + + private readonly WpfCanvas _nativeOverlayLayer = new(); + private readonly WpfWindow _wpfWindow; + private readonly WinUI.Window _window; + private readonly CompositeDisposable _disposables = new(); + + private IWpfRenderer? _renderer; + private FocusManager? _focusManager; + private bool _rendererInitialized; + + static UnoWpfWindowHost() + { + DefaultStyleKeyProperty.OverrideMetadata( + typeof(UnoWpfWindowHost), + new WpfFrameworkPropertyMetadata(typeof(UnoWpfWindowHost))); + } + + public UnoWpfWindowHost(WpfWindow wpfWindow, WinUI.Window window) + { + _wpfWindow = wpfWindow; + _window = window; + + FocusVisualStyle = null; + + SizeChanged += WpfHost_SizeChanged; + Loaded += WpfHost_Loaded; + + Windows.Foundation.Size preferredWindowSize = ApplicationView.PreferredLaunchViewSize; + if (preferredWindowSize != Windows.Foundation.Size.Empty) + { + Width = (int)preferredWindowSize.Width; + Height = (int)preferredWindowSize.Height; + } + + CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet += OnCoreWindowContentRootSet; + + RegisterForBackgroundColor(); + UpdateWindowPropertiesFromPackage(); + } + + WinUI.UIElement? IXamlRootHost.RootElement => _window.RootElement; + + WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; + + WinUI.XamlRoot? IXamlRootHost.XamlRoot => _window.RootElement?.XamlRoot; + + public bool IgnorePixelScaling => WpfHost.Current!.IgnorePixelScaling; + + public bool IsIsland => false; + + void IXamlRootHost.InvalidateRender() + { + InvalidateOverlays(); + InvalidateVisual(); + } + + //void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] + + //void IXamlRootHost.SetPointerCapture() => CaptureMouse(); + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + if (GetTemplateChild(NativeOverlayLayerHostPart) is WpfContentPresenter nativeOverlayLayerHost) + { + nativeOverlayLayerHost.Content = _nativeOverlayLayer; + } + } + + private void WpfHost_Loaded(object sender, RoutedEventArgs e) + { + WinUI.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(ActualWidth, ActualHeight)); + + // Avoid dotted border on focus. + if (Parent is WpfControl control) + { + control.FocusVisualStyle = null; + } + } + + private void InitializeRenderer() + { + // TODO:MZ: Do this only once, not for every window + if (WpfHost.Current!.RenderSurfaceType is null) + { + WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.OpenGL; + } + + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"Using {WpfHost.Current!.RenderSurfaceType} rendering"); + } + + _renderer = WpfHost.Current!.RenderSurfaceType switch + { + Skia.RenderSurfaceType.Software => new SoftwareWpfRenderer(this), + Skia.RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(this), + _ => throw new InvalidOperationException($"Render Surface type {WpfHost.Current!.RenderSurfaceType} is not supported") + }; + + UpdateRendererBackground(); + + if (!_renderer.Initialize()) + { + // OpenGL initialization failed, fallback to software rendering + // This may happen on headless systems or containers. + + if (this.Log().IsEnabled(LogLevel.Warning)) + { + this.Log().Warn($"OpenGL failed to initialize, using software rendering"); + } + + WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.Software; + InitializeRenderer(); + } + else + { + _rendererInitialized = true; + } + } + + private void OnCoreWindowContentRootSet(object? sender, object e) + { + var contentRoot = CoreServices.Instance + .ContentRootCoordinator + .CoreWindowContentRoot; + + var xamlRoot = contentRoot?.GetOrCreateXamlRoot(); + + if (xamlRoot is null) + { + throw new InvalidOperationException("XamlRoot was not properly initialized"); + } + + contentRoot!.SetHost(this); + XamlRootMap.Register(xamlRoot, this); + + CoreServices.Instance.ContentRootCoordinator.CoreWindowContentRootSet -= OnCoreWindowContentRootSet; + } + + private void UpdateWindowPropertiesFromPackage() + { + if (Windows.ApplicationModel.Package.Current.Logo is Uri uri) + { + var basePath = uri.OriginalString.Replace('\\', Path.DirectorySeparatorChar); + var iconPath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledPath, basePath); + + if (File.Exists(iconPath)) + { + if (this.Log().IsEnabled(LogLevel.Information)) + { + this.Log().Info($"Loading icon file [{iconPath}] from Package.appxmanifest file"); + } + + _wpfWindow.Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(iconPath)); + } + else if (Windows.UI.Xaml.Media.Imaging.BitmapImage.GetScaledPath(basePath) is { } scaledPath && File.Exists(scaledPath)) + { + if (this.Log().IsEnabled(LogLevel.Information)) + { + this.Log().Info($"Loading icon file [{scaledPath}] scaled logo from Package.appxmanifest file"); + } + + _wpfWindow.Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(scaledPath)); + } + else + { + if (this.Log().IsEnabled(LogLevel.Warning)) + { + this.Log().Warn($"Unable to find icon file [{iconPath}] specified in the Package.appxmanifest file."); + } + } + } + + Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Title = Windows.ApplicationModel.Package.Current.DisplayName; + } + + private void WpfHost_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e) + { + // TODO:MZ: Use Content.Size! + WinUI.Window.Current.OnNativeSizeChanged( + new Windows.Foundation.Size( + e.NewSize.Width, + e.NewSize.Height + ) + ); + } + + private void RegisterForBackgroundColor() + { + UpdateRendererBackground(); + + _disposables.Add(_window.RegisterBackgroundChangedEvent((s, e) => UpdateRendererBackground())); + } + + private void UpdateRendererBackground() + { + if (_window.Background is WinUI.Media.SolidColorBrush brush) + { + if (_renderer is not null) + { + _renderer.BackgroundColor = brush.Color; + Background = new SolidColorBrush(brush.Color.ToWpfColor()); + } + } + else + { + if (this.Log().IsEnabled(LogLevel.Warning)) + { + this.Log().Warn($"This platform only supports SolidColorBrush for the Window background"); + } + } + } + + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); + + if (!_rendererInitialized) + { + InitializeRenderer(); + } + _renderer?.Render(drawingContext); + } + + private void InvalidateOverlays() + { + _focusManager ??= VisualTree.GetFocusManagerForElement(_window.RootElement); + _focusManager?.FocusRectManager?.RedrawFocusVisual(); + if (_focusManager?.FocusedElement is Windows.UI.Xaml.Controls.TextBox textBox) + { + textBox.TextBoxView?.Extension?.InvalidateLayout(); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Internal/InputManager.cs b/src/Uno.UI/UI/Xaml/Internal/InputManager.cs index e7b3f23c5f02..d132650569a6 100644 --- a/src/Uno.UI/UI/Xaml/Internal/InputManager.cs +++ b/src/Uno.UI/UI/Xaml/Internal/InputManager.cs @@ -28,12 +28,9 @@ public InputManager(ContentRoot contentRoot) /// /// Initialize the InputManager. /// - internal void Initialize(object host) - { - InitializeManagedPointers(host); - } - partial void InitializeManagedPointers(object host); + internal void Initialize(object host) => InitializeManagedPointers(host); + partial void InitializeManagedPointers(object host); //TODO Uno: Set along with user input - this needs to be adjusted soon internal InputDeviceType LastInputDeviceType { get; set; } = InputDeviceType.None; From 1dca1aa453c216eae5df7bda3536297bc571c576 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Mon, 5 Jun 2023 10:18:31 +0200 Subject: [PATCH 17/37] chore: Fix rendering issue on WPF OpenGL --- src/Uno.UI.Composition/Composition/Compositor.skia.cs | 2 +- src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs | 2 +- .../Rendering/SoftwareRenderSurface.cs | 2 +- src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs | 2 +- src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs | 2 +- src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs | 2 +- src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs | 4 ---- src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs | 4 ---- 8 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/Uno.UI.Composition/Composition/Compositor.skia.cs b/src/Uno.UI.Composition/Composition/Compositor.skia.cs index de668e68ec4a..d40f3bb0b270 100644 --- a/src/Uno.UI.Composition/Composition/Compositor.skia.cs +++ b/src/Uno.UI.Composition/Composition/Compositor.skia.cs @@ -64,7 +64,7 @@ internal SKColorFilter? CurrentOpacityColorFilter } } - internal void Render(SKSurface surface, ContainerVisual rootVisual) + internal void RenderRootVisual(SKSurface surface, ContainerVisual rootVisual) { if (rootVisual is null) { diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs index 57ef304f9a30..f926c6c1fc08 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs @@ -151,7 +151,7 @@ private void UnoGLDrawingArea_Render(object o, RenderArgs args) if (_host.RootElement?.Visual is { } rootVisual) { - WUX.Window.Current.Compositor.Render(_surface, rootVisual); + WUX.Window.Current.Compositor.RenderRootVisual(_surface, rootVisual); } } diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs index 9ea7665c245d..9ca28a4ef401 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs @@ -119,7 +119,7 @@ protected override bool OnDrawn(Context cr) if (_host.RootElement?.Visual is { } rootVisual) { - WUX.Window.Current.Compositor.Render(_surface, rootVisual); + WUX.Window.Current.Compositor.RenderRootVisual(_surface, rootVisual); } } diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs index 0055f6065a75..ac6e510aa8b7 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs @@ -70,7 +70,7 @@ void Invalidate() if (_host.RootElement?.Visual is { } rootVisual) { - WUX.Window.Current.Compositor.Render(surface, rootVisual); + WUX.Window.Current.Compositor.RenderRootVisual(surface, rootVisual); } _fbDev.VSync(); diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs index c3a6948cb193..a7cc75b74a30 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs @@ -207,7 +207,7 @@ public void Render(DrawingContext drawingContext) if (_host.RootElement?.Visual is { } rootVisual) { - WinUI.Window.Current.Compositor.RenderVisual(_surface, rootVisual); + WinUI.Window.Current.Compositor.RenderRootVisual(_surface, rootVisual); } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs index 14d5b55df532..362cd488c803 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs @@ -81,7 +81,7 @@ public void Render(DrawingContext drawingContext) surface.Canvas.SetMatrix(SKMatrix.CreateScale((float)dpiScaleX, (float)dpiScaleY)); if (_host.RootElement?.Visual is { } rootVisual) { - WinUI.Window.Current.Compositor.Render(surface, rootVisual); + WinUI.Window.Current.Compositor.RenderRootVisual(surface, rootVisual); } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs index 159dc220d511..eede85bf23cb 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs @@ -83,10 +83,6 @@ void IXamlRootHost.InvalidateRender() InvalidateVisual(); } - //void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] - - //void IXamlRootHost.SetPointerCapture() => CaptureMouse(); - public override void OnApplyTemplate() { base.OnApplyTemplate(); diff --git a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs index a4295739723a..dca82857199b 100644 --- a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs +++ b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs @@ -101,10 +101,6 @@ protected override void OnRender(DrawingContext drawingContext) _renderer?.Render(drawingContext); } - void IXamlRootHost.ReleasePointerCapture() => ReleaseMouseCapture(); //TODO: This should capture the correct type of pointer (stylus/mouse/touch) https://github.com/unoplatform/uno/issues/8978[capture] - - void IXamlRootHost.SetPointerCapture() => CaptureMouse(); - void IXamlRootHost.InvalidateRender() { //InvalidateOverlays(); From b0c601b607e7b5404919e69ab84ffb0ba2334f75 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Mon, 5 Jun 2023 11:07:01 +0200 Subject: [PATCH 18/37] chore: Refactor WPF renderer infrastructure --- .../Rendering/GLRenderSurfaceBase.cs | 2 +- .../Rendering/GLValidationSurface.cs | 145 +++++++++--------- .../Rendering/IGtkRenderer.cs | 7 + .../Rendering/IRenderSurface.cs | 18 --- .../Rendering/SoftwareRenderSurface.cs | 2 +- .../UI/Controls/UnoGtkWindow.cs | 6 +- .../Extensions/WpfExtensionsRegistrar.cs | 4 +- .../Hosting/IWpfWindowHost.cs | 4 - .../Hosting/IWpfXamlRootHost.cs | 2 +- .../Input/WpfCorePointerInputSource.cs | 3 +- .../Rendering/IWpfRenderer.cs | 13 +- .../Rendering/OpenGLWpfRenderer.cs | 36 ++--- .../Rendering/SoftwareWpfRenderer.cs | 135 ++++++++-------- .../Rendering/WpfRendererProvider.cs | 48 ++++++ .../UI/Controls/UnoWpfWindowHost.cs | 79 +++------- .../UnoXamlHostBase.host.cs | 6 + .../Xaml => }/Hosting/IXamlRootHost.skia.cs | 2 +- src/Uno.UI/Rendering/IRenderer.skia.cs | 10 ++ 18 files changed, 256 insertions(+), 266 deletions(-) create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs delete mode 100644 src/Uno.UI.Runtime.Skia.Gtk/Rendering/IRenderSurface.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs rename src/Uno.UI/{UI/Xaml => }/Hosting/IXamlRootHost.skia.cs (86%) create mode 100644 src/Uno.UI/Rendering/IRenderer.skia.cs diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs index f926c6c1fc08..d4c54d544d9d 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs @@ -23,7 +23,7 @@ namespace Uno.UI.Runtime.Skia { - internal abstract partial class GLRenderSurfaceBase : GLArea, IRenderSurface + internal abstract partial class GLRenderSurfaceBase : GLArea, IGtkRenderer { private const SKColorType colorType = SKColorType.Rgba8888; private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft; diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLValidationSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLValidationSurface.cs index 63739b6ed601..3733accb2867 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLValidationSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLValidationSurface.cs @@ -6,109 +6,108 @@ using Gtk; using Uno.Foundation.Logging; -namespace Uno.UI.Runtime.Skia +namespace Uno.UI.Runtime.Skia; + +/// +/// Validation surface for OpenGL rendering, as CreateGRGLContext +/// needs to be invoked with an active OpenGL context, and that Skia +/// does additional validation that cannot be extracted at an earlier stage. +/// +internal class GLValidationSurface : GLArea { - /// - /// Validation surface for OpenGL rendering, as CreateGRGLContext - /// needs to be invoked with an active OpenGL context, and that Skia - /// does additional validation that cannot be extracted at an earlier stage. - /// - internal class GLValidationSurface : GLArea + private TaskCompletionSource _result = new(); + + public GLValidationSurface() { - private TaskCompletionSource _result = new(); + HasDepthBuffer = false; + HasStencilBuffer = false; + AutoRender = true; + SetRequiredVersion(3, 3); + + Render += GLValidationSurface_Render; + Realized += GLValidationSurface_Realized; + } - public GLValidationSurface() + private void GLValidationSurface_Realized(object? sender, EventArgs e) + { + if (Context == null) { - HasDepthBuffer = false; - HasStencilBuffer = false; - AutoRender = true; - SetRequiredVersion(3, 3); + // In this case, the UI is displaying "Unable to create a GL context" + // meaning that GTK was not able to be detected. This can happen on Raspberry Pi + // running using Wayland. + // This can be adjusted by setting `GDK_BACKEND=x11` to force a fallback on X11 rendering + // and enable the use of OpenGL (non-ES) rendering. + + if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) + { + typeof(GLValidationSurface).Log().Debug($"GL Context realization failed"); + } + + _result.TrySetResult(RenderSurfaceType.Software); + } + } - Render += GLValidationSurface_Render; - Realized += GLValidationSurface_Realized; + private void GLValidationSurface_Render(object o, RenderArgs args) + { + if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) + { + typeof(GLValidationSurface).Log().Debug($"GLValidationSurface: UseEs={UseEs}"); } - private void GLValidationSurface_Realized(object? sender, EventArgs e) + args.Context.MakeCurrent(); + + ValidateOpenGLSupport(); + } + + private void ValidateOpenGLSupport() + { + try { - if (Context == null) + if (OpenGLESRenderSurface.IsSupported) { - // In this case, the UI is displaying "Unable to create a GL context" - // meaning that GTK was not able to be detected. This can happen on Raspberry Pi - // running using Wayland. - // This can be adjusted by setting `GDK_BACKEND=x11` to force a fallback on X11 rendering - // and enable the use of OpenGL (non-ES) rendering. + using var ctx = OpenGLESRenderSurface.CreateGRGLContext(); - if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) + if (ctx != null) { - typeof(GLValidationSurface).Log().Debug($"GL Context realization failed"); + _result.TrySetResult(RenderSurfaceType.OpenGLES); + return; } - - _result.TrySetResult(RenderSurfaceType.Software); } } - - private void GLValidationSurface_Render(object o, RenderArgs args) + catch (Exception e) { if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) { - typeof(GLValidationSurface).Log().Debug($"GLValidationSurface: UseEs={UseEs}"); + typeof(GLValidationSurface).Log().Debug($"OpenGL ES cannot be used ({e.Message})"); } - - args.Context.MakeCurrent(); - - ValidateOpenGLSupport(); } - private void ValidateOpenGLSupport() + try { - try + if (OpenGLRenderSurface.IsSupported) { - if (OpenGLESRenderSurface.IsSupported) - { - using var ctx = OpenGLESRenderSurface.CreateGRGLContext(); + OpenGLRenderSurface.TryValidateExtensions(); - if (ctx != null) - { - _result.TrySetResult(RenderSurfaceType.OpenGLES); - return; - } - } - } - catch (Exception e) - { - if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) - { - typeof(GLValidationSurface).Log().Debug($"OpenGL ES cannot be used ({e.Message})"); - } - } + using var ctx = OpenGLRenderSurface.CreateGRGLContext(); - try - { - if (OpenGLRenderSurface.IsSupported) + if (ctx != null) { - OpenGLRenderSurface.TryValidateExtensions(); - - using var ctx = OpenGLRenderSurface.CreateGRGLContext(); - - if (ctx != null) - { - _result.TrySetResult(RenderSurfaceType.OpenGL); - return; - } + _result.TrySetResult(RenderSurfaceType.OpenGL); + return; } } - catch (Exception e) + } + catch (Exception e) + { + if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) { - if (typeof(GLValidationSurface).Log().IsEnabled(LogLevel.Debug)) - { - typeof(GLValidationSurface).Log().Debug($"OpenGL cannot be used ({e.Message})"); - } + typeof(GLValidationSurface).Log().Debug($"OpenGL cannot be used ({e.Message})"); } - - _result.TrySetResult(RenderSurfaceType.Software); } - internal Task GetSurfaceTypeAsync() - => _result.Task; + _result.TrySetResult(RenderSurfaceType.Software); } + + internal Task GetSurfaceTypeAsync() + => _result.Task; } diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs new file mode 100644 index 000000000000..481f95f191b1 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs @@ -0,0 +1,7 @@ +using Uno.UI.Rendering; + +namespace Uno.UI.Runtime.Skia; + +internal interface IGtkRenderer : IRenderer +{ +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IRenderSurface.cs deleted file mode 100644 index 6b695b8d3d18..000000000000 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IRenderSurface.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Gtk; -using SkiaSharp; - -namespace Uno.UI.Runtime.Skia; - -internal interface IRenderSurface -{ - Widget Widget { get; } - - void TakeScreenshot(string filePath); - - /// - /// Background color for the render surface - /// - SKColor BackgroundColor { get; set; } - - void InvalidateRender(); -} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs index 9ca28a4ef401..3ccb7ddd5012 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs @@ -21,7 +21,7 @@ namespace Uno.UI.Runtime.Skia; -internal class SoftwareRenderSurface : Gtk.DrawingArea, IRenderSurface +internal class SoftwareRenderSurface : Gtk.DrawingArea, IGtkRenderer { private readonly DisplayInformation _displayInformation; private FocusManager? _focusManager; diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs index ac6c4130ce50..8cb3e49e5afd 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs @@ -30,7 +30,7 @@ internal class UnoGtkWindow : Gtk.Window, IGtkWindowHost private Widget? _area; private Fixed? _fix; - private IRenderSurface? _renderSurface; + private IGtkRenderer? _renderSurface; private GtkDisplayInformationExtension? _displayInformationExtension; private CompositeDisposable _registrations = new(); @@ -110,7 +110,7 @@ public UnoGtkWindow(WinUIWindow window) : base(WindowType.Toplevel) private void OnShown(object? sender, EventArgs e) => ShowAll(); - internal IRenderSurface? RenderSurface => _renderSurface; + internal IGtkRenderer? RenderSurface => _renderSurface; internal Fixed? NativeOverlayLayer => GtkCoreWindowExtension.FindNativeOverlayLayer(this); @@ -230,7 +230,7 @@ private void UpdateWindowPropertiesFromPackage() } - private IRenderSurface BuildRenderSurfaceType() + private IGtkRenderer BuildRenderSurfaceType() => GtkHost.Current!.RenderSurfaceType switch { Skia.RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(this), diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs index 148158ffcaa5..f4838cefc101 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Extensions/WpfExtensionsRegistrar.cs @@ -9,13 +9,11 @@ using Uno.Foundation.Extensibility; using Uno.Helpers.Theming; using Uno.UI.Core.Preview; +using Uno.UI.Hosting; using Uno.UI.Runtime.Skia.Wpf.Extensions.UI.Xaml.Controls; using Uno.UI.Runtime.Skia.Wpf.WPF.Extensions.Helpers.Theming; -using Uno.UI.Skia; using Uno.UI.Skia.Platform; using Uno.UI.Xaml.Controls.Extensions; -using Uno.UI.Xaml.Hosting; -using Uno.UI.Xaml.Input; using Uno.UI.XamlHost.Skia.Wpf; using Windows.Graphics.Display; using Windows.Networking.Connectivity; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs index 48d9ff5929d2..c5261d54bc87 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfWindowHost.cs @@ -1,9 +1,5 @@ #nullable enable -using Uno; -using Windows.UI.Xaml; -using WpfCanvas = System.Windows.Controls.Canvas; - namespace Uno.UI.Runtime.Skia.Wpf.Hosting; internal interface IWpfWindowHost : IWpfXamlRootHost diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs index 96995234f7e7..ee08ef27989b 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs @@ -1,6 +1,6 @@ #nullable enable -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; using WpfCanvas = System.Windows.Controls.Canvas; namespace Uno.UI.Runtime.Skia.Wpf.Hosting; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs b/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs index cd19162cce8d..5c758defeb86 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Input/WpfCorePointerInputSource.cs @@ -5,10 +5,9 @@ using System.Windows.Input; using System.Windows.Interop; using Uno.Foundation.Logging; -using Uno.UI.Runtime.Skia.Wpf; +using Uno.UI.Hosting; using Uno.UI.Runtime.Skia.Wpf.Constants; using Uno.UI.Runtime.Skia.Wpf.Input; -using Uno.UI.Xaml.Hosting; using Windows.Devices.Input; using Windows.Foundation; using Windows.System; diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs index 938792a365bc..d08223337035 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs @@ -1,16 +1,11 @@ -using System; -using System.Windows.Media; -using SkiaSharp; +using System.Windows.Media; +using Uno.UI.Rendering; namespace Uno.UI.Runtime.Skia.Wpf.Rendering; -internal interface IWpfRenderer : IDisposable +internal interface IWpfRenderer : IRenderer { - SKColor BackgroundColor { get; set; } + bool TryInitialize(); void Render(DrawingContext drawingContext); - - bool Initialize(); - - SKSize CanvasSize { get; } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs index a7cc75b74a30..9e71b75ad1ee 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/OpenGLWpfRenderer.cs @@ -38,7 +38,9 @@ public OpenGLWpfRenderer(IWpfXamlRootHost host) _host = host; } - public bool Initialize() + public SKColor BackgroundColor { get; set; } + + public bool TryInitialize() { // Get the window from the wpf control var hwnd = new WindowInteropHelper(Window.GetWindow(_hostControl)).Handle; @@ -131,15 +133,15 @@ public bool Initialize() public void Render(DrawingContext drawingContext) { if (_hostControl.ActualWidth == 0 - || _hostControl.ActualHeight == 0 - || double.IsNaN(_hostControl.ActualWidth) - || double.IsNaN(_hostControl.ActualHeight) - || double.IsInfinity(_hostControl.ActualWidth) - || double.IsInfinity(_hostControl.ActualHeight) - || _hostControl.Visibility != Visibility.Visible - || _hdc == 0 - || _glContext == 0 - || _grContext is null) + || _hostControl.ActualHeight == 0 + || double.IsNaN(_hostControl.ActualWidth) + || double.IsNaN(_hostControl.ActualHeight) + || double.IsInfinity(_hostControl.ActualWidth) + || double.IsInfinity(_hostControl.ActualHeight) + || _hostControl.Visibility != Visibility.Visible + || _hdc == 0 + || _glContext == 0 + || _grContext is null) { return; } @@ -226,6 +228,8 @@ public void Render(DrawingContext drawingContext) } } + public void Dispose() => Release(); + private (int framebuffer, int stencil, int samples) GetGLBuffers() { NativeMethods.glGetIntegerv(NativeMethods.GL_FRAMEBUFFER_BINDING, out var framebuffer); @@ -235,7 +239,7 @@ public void Render(DrawingContext drawingContext) return (framebuffer, stencil, samples); } - internal bool TryCreateGRGLContext(out GRContext? context) + private bool TryCreateGRGLContext(out GRContext? context) { context = null; @@ -266,11 +270,6 @@ internal bool TryCreateGRGLContext(out GRContext? context) return true; } - public void Dispose() - { - Release(); - } - private void Release() { // Cleanup resources @@ -292,9 +291,4 @@ private void Release() _backBuffer = null; } - - public SKSize CanvasSize - => _backBuffer == null ? SKSize.Empty : new SKSize(_backBuffer.PixelWidth, _backBuffer.PixelHeight); - - public SKColor BackgroundColor { get; set; } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs index 362cd488c803..16568075b038 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/SoftwareWpfRenderer.cs @@ -10,91 +10,88 @@ using WinUI = Windows.UI.Xaml; using WpfControl = global::System.Windows.Controls.Control; -namespace Uno.UI.Runtime.Skia.Wpf.Rendering +namespace Uno.UI.Runtime.Skia.Wpf.Rendering; + +internal class SoftwareWpfRenderer : IWpfRenderer { - internal class SoftwareWpfRenderer : IWpfRenderer + private WpfControl _hostControl; + private DisplayInformation? _displayInformation; + private WriteableBitmap? _bitmap; + private IWpfXamlRootHost _host; + + public SoftwareWpfRenderer(IWpfXamlRootHost host) { - private WpfControl _hostControl; - private DisplayInformation? _displayInformation; - private WriteableBitmap? _bitmap; - private IWpfXamlRootHost _host; + _hostControl = host as WpfControl ?? throw new InvalidOperationException("Host should be a WPF control"); + _host = host; + } - public SoftwareWpfRenderer(IWpfXamlRootHost host) - { - _hostControl = host as WpfControl ?? throw new InvalidOperationException("Host should be a WPF control"); - _host = host; - } + public SKColor BackgroundColor { get; set; } = SKColors.White; + + public bool TryInitialize() => true; - public SKColor BackgroundColor { get; set; } = SKColors.White; + public void Dispose() { } - public void Render(DrawingContext drawingContext) + public void Render(DrawingContext drawingContext) + { + if (_hostControl.ActualWidth == 0 + || _hostControl.ActualHeight == 0 + || double.IsNaN(_hostControl.ActualWidth) + || double.IsNaN(_hostControl.ActualHeight) + || double.IsInfinity(_hostControl.ActualWidth) + || double.IsInfinity(_hostControl.ActualHeight) + || _hostControl.Visibility != Visibility.Visible) { - if (_hostControl.ActualWidth == 0 - || _hostControl.ActualHeight == 0 - || double.IsNaN(_hostControl.ActualWidth) - || double.IsNaN(_hostControl.ActualHeight) - || double.IsInfinity(_hostControl.ActualWidth) - || double.IsInfinity(_hostControl.ActualHeight) - || _hostControl.Visibility != Visibility.Visible) - { - return; - } + return; + } - int width, height; + int width, height; - if (_displayInformation == null) - { - _displayInformation = DisplayInformation.GetForCurrentView(); - } + if (_displayInformation == null) + { + _displayInformation = DisplayInformation.GetForCurrentView(); + } - var dpi = _displayInformation.RawPixelsPerViewPixel; - double dpiScaleX = dpi; - double dpiScaleY = dpi; - if (_host.IgnorePixelScaling) - { - width = (int)_hostControl.ActualWidth; - height = (int)_hostControl.ActualHeight; - } - else - { - var matrix = PresentationSource.FromVisual(_hostControl).CompositionTarget.TransformToDevice; - dpiScaleX = matrix.M11; - dpiScaleY = matrix.M22; - width = (int)(_hostControl.ActualWidth * dpiScaleX); - height = (int)(_hostControl.ActualHeight * dpiScaleY); - } + var dpi = _displayInformation.RawPixelsPerViewPixel; + double dpiScaleX = dpi; + double dpiScaleY = dpi; + if (_host.IgnorePixelScaling) + { + width = (int)_hostControl.ActualWidth; + height = (int)_hostControl.ActualHeight; + } + else + { + var matrix = PresentationSource.FromVisual(_hostControl).CompositionTarget.TransformToDevice; + dpiScaleX = matrix.M11; + dpiScaleY = matrix.M22; + width = (int)(_hostControl.ActualWidth * dpiScaleX); + height = (int)(_hostControl.ActualHeight * dpiScaleY); + } - var info = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul); + var info = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul); - // reset the bitmap if the size has changed - if (_bitmap == null || info.Width != _bitmap.PixelWidth || info.Height != _bitmap.PixelHeight) - { - _bitmap = new WriteableBitmap(width, height, 96 * dpiScaleX, 96 * dpiScaleY, PixelFormats.Pbgra32, null); - } + // reset the bitmap if the size has changed + if (_bitmap == null || info.Width != _bitmap.PixelWidth || info.Height != _bitmap.PixelHeight) + { + _bitmap = new WriteableBitmap(width, height, 96 * dpiScaleX, 96 * dpiScaleY, PixelFormats.Pbgra32, null); + } - // draw on the bitmap - _bitmap.Lock(); - using (var surface = SKSurface.Create(info, _bitmap.BackBuffer, _bitmap.BackBufferStride)) + // draw on the bitmap + _bitmap.Lock(); + using (var surface = SKSurface.Create(info, _bitmap.BackBuffer, _bitmap.BackBufferStride)) + { + surface.Canvas.Clear(BackgroundColor); + surface.Canvas.SetMatrix(SKMatrix.CreateScale((float)dpiScaleX, (float)dpiScaleY)); + if (_host.RootElement?.Visual is { } rootVisual) { - surface.Canvas.Clear(BackgroundColor); - surface.Canvas.SetMatrix(SKMatrix.CreateScale((float)dpiScaleX, (float)dpiScaleY)); - if (_host.RootElement?.Visual is { } rootVisual) - { - WinUI.Window.Current.Compositor.RenderRootVisual(surface, rootVisual); - } + WinUI.Window.Current.Compositor.RenderRootVisual(surface, rootVisual); } - - // draw the bitmap to the screen - _bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); - _bitmap.Unlock(); - drawingContext.DrawImage(_bitmap, new Rect(0, 0, _hostControl.ActualWidth, _hostControl.ActualHeight)); } - public bool Initialize() => true; - - public void Dispose() { } - - public SKSize CanvasSize => _bitmap == null ? SKSize.Empty : new SKSize(_bitmap.PixelWidth, _bitmap.PixelHeight); + // draw the bitmap to the screen + _bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); + _bitmap.Unlock(); + drawingContext.DrawImage(_bitmap, new Rect(0, 0, _hostControl.ActualWidth, _hostControl.ActualHeight)); } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs new file mode 100644 index 000000000000..dcd40d16ef2c --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs @@ -0,0 +1,48 @@ +using System; +using Uno.Foundation.Logging; +using Uno.UI.Runtime.Skia.Wpf.Hosting; +using Uno.UI.Skia; + +namespace Uno.UI.Runtime.Skia.Wpf.Rendering; + +internal static class WpfRendererProvider +{ + public static IWpfRenderer CreateForHost(IWpfXamlRootHost host) + { + // TODO:MZ: Do this only once, not for every window + if (WpfHost.Current!.RenderSurfaceType is null) + { + WpfHost.Current!.RenderSurfaceType = RenderSurfaceType.OpenGL; + } + + if (typeof(WpfRendererProvider).Log().IsEnabled(LogLevel.Debug)) + { + typeof(WpfRendererProvider).Log().Debug($"Using {WpfHost.Current!.RenderSurfaceType} rendering"); + } + + IWpfRenderer renderer = WpfHost.Current!.RenderSurfaceType switch + { + RenderSurfaceType.Software => new SoftwareWpfRenderer(host), + RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(host), + _ => throw new InvalidOperationException($"Render Surface type {WpfHost.Current!.RenderSurfaceType} is not supported") + }; + + if (!renderer.TryInitialize()) + { + // OpenGL initialization failed, fallback to software rendering + // This may happen on headless systems or containers. + + if (typeof(WpfRendererProvider).Log().IsEnabled(LogLevel.Warning)) + { + typeof(WpfRendererProvider).Log().Warn($"OpenGL failed to initialize, using software rendering"); + } + + WpfHost.Current!.RenderSurfaceType = RenderSurfaceType.Software; + return CreateForHost(host); + } + else + { + return renderer; + } + } +} diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs index eede85bf23cb..74730a2e3be9 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs @@ -10,7 +10,6 @@ using Uno.UI.Runtime.Skia.Wpf.Extensions; using Uno.UI.Runtime.Skia.Wpf.Rendering; using Uno.UI.Xaml.Core; -using Uno.UI.Xaml.Hosting; using Uno.UI.XamlHost.Skia.Wpf.Hosting; using Windows.UI.ViewManagement; using Windows.UI.Xaml.Input; @@ -20,6 +19,8 @@ using WpfContentPresenter = System.Windows.Controls.ContentPresenter; using WpfFrameworkPropertyMetadata = System.Windows.FrameworkPropertyMetadata; using WpfWindow = System.Windows.Window; +using RoutedEventArgs = System.Windows.RoutedEventArgs; +using Uno.UI.Hosting; namespace Uno.UI.Skia.Wpf; @@ -33,9 +34,10 @@ internal class UnoWpfWindowHost : WpfControl, IWpfWindowHost private readonly WinUI.Window _window; private readonly CompositeDisposable _disposables = new(); + private Size _previousArrangeBounds; + private IWpfRenderer? _renderer; private FocusManager? _focusManager; - private bool _rendererInitialized; static UnoWpfWindowHost() { @@ -51,7 +53,6 @@ public UnoWpfWindowHost(WpfWindow wpfWindow, WinUI.Window window) FocusVisualStyle = null; - SizeChanged += WpfHost_SizeChanged; Loaded += WpfHost_Loaded; Windows.Foundation.Size preferredWindowSize = ApplicationView.PreferredLaunchViewSize; @@ -67,13 +68,23 @@ public UnoWpfWindowHost(WpfWindow wpfWindow, WinUI.Window window) UpdateWindowPropertiesFromPackage(); } + protected override Size ArrangeOverride(Size arrangeBounds) + { + if (arrangeBounds != _previousArrangeBounds) + { + _window.OnNativeSizeChanged(new Windows.Foundation.Size(arrangeBounds.Width, arrangeBounds.Height)); + _previousArrangeBounds = arrangeBounds; + } + return base.ArrangeOverride(arrangeBounds); + } + WinUI.UIElement? IXamlRootHost.RootElement => _window.RootElement; WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; WinUI.XamlRoot? IXamlRootHost.XamlRoot => _window.RootElement?.XamlRoot; - public bool IgnorePixelScaling => WpfHost.Current!.IgnorePixelScaling; + bool IWpfXamlRootHost.IgnorePixelScaling => WpfHost.Current!.IgnorePixelScaling; public bool IsIsland => false; @@ -95,8 +106,6 @@ public override void OnApplyTemplate() private void WpfHost_Loaded(object sender, RoutedEventArgs e) { - WinUI.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(ActualWidth, ActualHeight)); - // Avoid dotted border on focus. if (Parent is WpfControl control) { @@ -104,47 +113,6 @@ private void WpfHost_Loaded(object sender, RoutedEventArgs e) } } - private void InitializeRenderer() - { - // TODO:MZ: Do this only once, not for every window - if (WpfHost.Current!.RenderSurfaceType is null) - { - WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.OpenGL; - } - - if (this.Log().IsEnabled(LogLevel.Debug)) - { - this.Log().Debug($"Using {WpfHost.Current!.RenderSurfaceType} rendering"); - } - - _renderer = WpfHost.Current!.RenderSurfaceType switch - { - Skia.RenderSurfaceType.Software => new SoftwareWpfRenderer(this), - Skia.RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(this), - _ => throw new InvalidOperationException($"Render Surface type {WpfHost.Current!.RenderSurfaceType} is not supported") - }; - - UpdateRendererBackground(); - - if (!_renderer.Initialize()) - { - // OpenGL initialization failed, fallback to software rendering - // This may happen on headless systems or containers. - - if (this.Log().IsEnabled(LogLevel.Warning)) - { - this.Log().Warn($"OpenGL failed to initialize, using software rendering"); - } - - WpfHost.Current!.RenderSurfaceType = Skia.RenderSurfaceType.Software; - InitializeRenderer(); - } - else - { - _rendererInitialized = true; - } - } - private void OnCoreWindowContentRootSet(object? sender, object e) { var contentRoot = CoreServices.Instance @@ -201,17 +169,6 @@ private void UpdateWindowPropertiesFromPackage() Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().Title = Windows.ApplicationModel.Package.Current.DisplayName; } - private void WpfHost_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e) - { - // TODO:MZ: Use Content.Size! - WinUI.Window.Current.OnNativeSizeChanged( - new Windows.Foundation.Size( - e.NewSize.Width, - e.NewSize.Height - ) - ); - } - private void RegisterForBackgroundColor() { UpdateRendererBackground(); @@ -242,10 +199,12 @@ protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); - if (!_rendererInitialized) + if (_renderer is null) { - InitializeRenderer(); + _renderer = WpfRendererProvider.CreateForHost(this); + UpdateRendererBackground(); } + _renderer?.Render(drawingContext); } diff --git a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs index dca82857199b..aabbb8f1f255 100644 --- a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs +++ b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs @@ -21,6 +21,7 @@ using Windows.Foundation.Metadata; using Uno.UI.Runtime.Skia.Wpf.Hosting; using Uno.UI.Runtime.Skia.Wpf.Extensions; +using Uno.UI.Hosting; namespace Uno.UI.XamlHost.Skia.Wpf { @@ -98,6 +99,11 @@ protected override void OnRender(DrawingContext drawingContext) return; } + if (_renderer is null) + { + _renderer = WpfRendererProvider.CreateForHost(this); + } + _renderer?.Render(drawingContext); } diff --git a/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs b/src/Uno.UI/Hosting/IXamlRootHost.skia.cs similarity index 86% rename from src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs rename to src/Uno.UI/Hosting/IXamlRootHost.skia.cs index 6dff9ea88aa4..f74767a56323 100644 --- a/src/Uno.UI/UI/Xaml/Hosting/IXamlRootHost.skia.cs +++ b/src/Uno.UI/Hosting/IXamlRootHost.skia.cs @@ -2,7 +2,7 @@ using Windows.UI.Xaml; -namespace Uno.UI.Xaml.Hosting; +namespace Uno.UI.Hosting; internal interface IXamlRootHost { diff --git a/src/Uno.UI/Rendering/IRenderer.skia.cs b/src/Uno.UI/Rendering/IRenderer.skia.cs new file mode 100644 index 000000000000..3b084c0de378 --- /dev/null +++ b/src/Uno.UI/Rendering/IRenderer.skia.cs @@ -0,0 +1,10 @@ +#nullable enable + +using SkiaSharp; + +namespace Uno.UI.Rendering; + +internal interface IRenderer +{ + SKColor BackgroundColor { get; set; } +} From 7fb07b08d4fd33439dfcaf028f7a504cfd7f80d4 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Mon, 5 Jun 2023 11:38:27 +0200 Subject: [PATCH 19/37] chore: Move render invalidation to application level, finalize WPF refactor --- .../Composition/Compositor.skia.cs | 3 +- .../Hosting/IWpfXamlRootHost.cs | 3 + .../Rendering/IWpfRenderer.cs | 5 +- .../Rendering/WpfRendererProvider.cs | 50 +++---- .../UI/Controls/UnoWpfWindowHost.cs | 2 + .../UnoXamlHostBase.host.cs | 137 +++++++----------- src/Uno.UI/UI/Xaml/Application.skia.cs | 11 ++ src/Uno.UI/UI/Xaml/Window.skia.cs | 2 - src/Uno.UI/Uno.UI.Skia.csproj | 4 - .../Core/CoreApplication.skia.cs | 9 ++ src/Uno.UWP/UI/Core/CoreWindow.cs | 8 - 11 files changed, 104 insertions(+), 130 deletions(-) diff --git a/src/Uno.UI.Composition/Composition/Compositor.skia.cs b/src/Uno.UI.Composition/Composition/Compositor.skia.cs index d40f3bb0b270..9e98708c4da4 100644 --- a/src/Uno.UI.Composition/Composition/Compositor.skia.cs +++ b/src/Uno.UI.Composition/Composition/Compositor.skia.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Numerics; using SkiaSharp; +using Windows.ApplicationModel.Core; using Windows.UI.Core; namespace Windows.UI.Composition @@ -168,7 +169,7 @@ partial void InvalidateRenderPartial() if (!_isDirty) { _isDirty = true; - CoreWindow.QueueInvalidateRender(); + CoreApplication.QueueInvalidateRender(); } } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs index ee08ef27989b..12c8e208d58e 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Hosting/IWpfXamlRootHost.cs @@ -1,6 +1,7 @@ #nullable enable using Uno.UI.Hosting; +using Uno.UI.Skia; using WpfCanvas = System.Windows.Controls.Canvas; namespace Uno.UI.Runtime.Skia.Wpf.Hosting; @@ -10,4 +11,6 @@ internal interface IWpfXamlRootHost : IXamlRootHost WpfCanvas? NativeOverlayLayer { get; } bool IgnorePixelScaling { get; } + + RenderSurfaceType? RenderSurfaceType { get; } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs index d08223337035..440b46e58181 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/IWpfRenderer.cs @@ -1,9 +1,10 @@ -using System.Windows.Media; +using System; +using System.Windows.Media; using Uno.UI.Rendering; namespace Uno.UI.Runtime.Skia.Wpf.Rendering; -internal interface IWpfRenderer : IRenderer +internal interface IWpfRenderer : IRenderer, IDisposable { bool TryInitialize(); diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs index dcd40d16ef2c..3605475d0666 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/Rendering/WpfRendererProvider.cs @@ -9,40 +9,40 @@ internal static class WpfRendererProvider { public static IWpfRenderer CreateForHost(IWpfXamlRootHost host) { - // TODO:MZ: Do this only once, not for every window - if (WpfHost.Current!.RenderSurfaceType is null) - { - WpfHost.Current!.RenderSurfaceType = RenderSurfaceType.OpenGL; - } + var requestedRenderer = host.RenderSurfaceType ?? RenderSurfaceType.OpenGL; if (typeof(WpfRendererProvider).Log().IsEnabled(LogLevel.Debug)) { - typeof(WpfRendererProvider).Log().Debug($"Using {WpfHost.Current!.RenderSurfaceType} rendering"); + typeof(WpfRendererProvider).Log().Debug($"Validating {host.RenderSurfaceType} rendering"); } - IWpfRenderer renderer = WpfHost.Current!.RenderSurfaceType switch - { - RenderSurfaceType.Software => new SoftwareWpfRenderer(host), - RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(host), - _ => throw new InvalidOperationException($"Render Surface type {WpfHost.Current!.RenderSurfaceType} is not supported") - }; - - if (!renderer.TryInitialize()) + IWpfRenderer renderer = null; + while (renderer is null) { - // OpenGL initialization failed, fallback to software rendering - // This may happen on headless systems or containers. + renderer = requestedRenderer switch + { + RenderSurfaceType.Software => new SoftwareWpfRenderer(host), + RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(host), + _ => throw new InvalidOperationException($"Render Surface type {host.RenderSurfaceType} is not supported") + }; - if (typeof(WpfRendererProvider).Log().IsEnabled(LogLevel.Warning)) + if (!renderer.TryInitialize()) { - typeof(WpfRendererProvider).Log().Warn($"OpenGL failed to initialize, using software rendering"); - } + renderer.Dispose(); + renderer = null; - WpfHost.Current!.RenderSurfaceType = RenderSurfaceType.Software; - return CreateForHost(host); - } - else - { - return renderer; + // OpenGL initialization failed, fallback to software rendering + // This may happen on headless systems or containers. + + if (typeof(WpfRendererProvider).Log().IsEnabled(LogLevel.Warning)) + { + typeof(WpfRendererProvider).Log().Warn($"OpenGL failed to initialize, using software rendering"); + } + + requestedRenderer = RenderSurfaceType.Software; + } } + + return renderer; } } diff --git a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs index 74730a2e3be9..16ecd54f0650 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs +++ b/src/Uno.UI.Runtime.Skia.Wpf/UI/Controls/UnoWpfWindowHost.cs @@ -86,6 +86,8 @@ protected override Size ArrangeOverride(Size arrangeBounds) bool IWpfXamlRootHost.IgnorePixelScaling => WpfHost.Current!.IgnorePixelScaling; + RenderSurfaceType? IWpfXamlRootHost.RenderSurfaceType => WpfHost.Current!.RenderSurfaceType; + public bool IsIsland => false; void IXamlRootHost.InvalidateRender() diff --git a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs index aabbb8f1f255..5c6fdc46412b 100644 --- a/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs +++ b/src/Uno.UI.XamlHost.Skia.Wpf/UnoXamlHostBase.host.cs @@ -3,124 +3,85 @@ using System.ComponentModel; using System.Windows; using System.Windows.Media; -using System.Windows.Media.Imaging; -using SkiaSharp; -using Uno.UI.XamlHost.Skia.Wpf; -using Windows.Devices.Input; -using Windows.Graphics.Display; using WinUI = Windows.UI.Xaml; -using WpfControl = global::System.Windows.Controls.Control; using WpfCanvas = global::System.Windows.Controls.Canvas; -using Uno.UI.Xaml.Hosting; -using Uno.UI.Controls; -using Uno.UI.Skia.Platform; using Uno.UI.Runtime.Skia.Wpf.Rendering; using Uno.UI.XamlHost.Extensions; using System; -using Uno.Foundation.Logging; -using Windows.Foundation.Metadata; using Uno.UI.Runtime.Skia.Wpf.Hosting; using Uno.UI.Runtime.Skia.Wpf.Extensions; using Uno.UI.Hosting; +using Uno.UI.Skia; -namespace Uno.UI.XamlHost.Skia.Wpf +namespace Uno.UI.XamlHost.Skia.Wpf; + +/// +/// UnoXamlHost control hosts UWP XAML content inside the Windows Presentation Foundation +/// +partial class UnoXamlHostBase : IWpfXamlRootHost { + private bool _designMode; + private bool _ignorePixelScaling; + private WpfCanvas _nativeOverlayLayer; + private IWpfRenderer _renderer; + private Windows.UI.Xaml.UIElement? _rootElement; + /// - /// UnoXamlHost control hosts UWP XAML content inside the Windows Presentation Foundation + /// Gets or sets the current Skia Render surface type. /// - partial class UnoXamlHostBase : IWpfXamlRootHost + /// If null, the host will try to determine the most compatible mode. + public Uno.UI.Skia.RenderSurfaceType? RenderSurfaceType { get; set; } + + public bool IgnorePixelScaling { - private bool _designMode; - private bool _ignorePixelScaling; - private WpfCanvas _nativeOverlayLayer; - private IWpfRenderer _renderer; - private Windows.UI.Xaml.UIElement? _rootElement; - - /// - /// Gets or sets the current Skia Render surface type. - /// - /// If null, the host will try to determine the most compatible mode. - public Uno.UI.Skia.RenderSurfaceType? RenderSurfaceType { get; set; } - - public bool IgnorePixelScaling + get => _ignorePixelScaling; + set { - get => _ignorePixelScaling; - set - { - _ignorePixelScaling = value; - InvalidateVisual(); - } + _ignorePixelScaling = value; + InvalidateVisual(); } + } - private void InitializeHost() - { - WpfExtensionsRegistrar.Register(); - - _designMode = DesignerProperties.GetIsInDesignMode(this); - - SetupRenderer(); + private void InitializeHost() + { + WpfExtensionsRegistrar.Register(); - Loaded += UnoXamlHostBase_Loaded; - Unloaded += UnoXamlHostBase_Unloaded; - } + _designMode = DesignerProperties.GetIsInDesignMode(this); + } - private void UnoXamlHostBase_Unloaded(object sender, RoutedEventArgs e) - { - } + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); - private void UnoXamlHostBase_Loaded(object sender, RoutedEventArgs e) + if (!IsXamlContentLoaded()) { - if (!(_renderer?.Initialize() ?? false)) - { - RenderSurfaceType = Uno.UI.Skia.RenderSurfaceType.Software; - SetupRenderer(); - _renderer?.Initialize(); - } + return; } - private void SetupRenderer() + if (_renderer is null) { - RenderSurfaceType ??= Uno.UI.Skia.RenderSurfaceType.OpenGL; - - _renderer = RenderSurfaceType switch - { - Uno.UI.Skia.RenderSurfaceType.Software => new SoftwareWpfRenderer(this), - Uno.UI.Skia.RenderSurfaceType.OpenGL => new OpenGLWpfRenderer(this), - _ => throw new InvalidOperationException($"Render Surface type {RenderSurfaceType} is not supported") - }; + _renderer = WpfRendererProvider.CreateForHost(this); } - protected override void OnRender(DrawingContext drawingContext) - { - base.OnRender(drawingContext); - - if (!IsXamlContentLoaded()) - { - return; - } - - if (_renderer is null) - { - _renderer = WpfRendererProvider.CreateForHost(this); - } + _renderer?.Render(drawingContext); + } - _renderer?.Render(drawingContext); - } + void IXamlRootHost.InvalidateRender() + { + // TODO: MZ: + //InvalidateOverlays(); + InvalidateVisual(); + } - void IXamlRootHost.InvalidateRender() - { - //InvalidateOverlays(); - InvalidateVisual(); - } + bool IXamlRootHost.IsIsland => true; - bool IXamlRootHost.IsIsland => true; + WinUI.UIElement? IXamlRootHost.RootElement => _rootElement ??= _xamlSource?.GetVisualTreeRoot(); - WinUI.UIElement? IXamlRootHost.RootElement => _rootElement ??= _xamlSource?.GetVisualTreeRoot(); + WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; - WpfCanvas? IWpfXamlRootHost.NativeOverlayLayer => _nativeOverlayLayer; + WinUI.XamlRoot? IXamlRootHost.XamlRoot => ChildInternal?.XamlRoot; - WinUI.XamlRoot? IXamlRootHost.XamlRoot => ChildInternal?.XamlRoot; + bool IWpfXamlRootHost.IgnorePixelScaling => IgnorePixelScaling; - bool IWpfXamlRootHost.IgnorePixelScaling => IgnorePixelScaling; - } + RenderSurfaceType? IWpfXamlRootHost.RenderSurfaceType => RenderSurfaceType; } diff --git a/src/Uno.UI/UI/Xaml/Application.skia.cs b/src/Uno.UI/UI/Xaml/Application.skia.cs index 0eb0747c60b0..d33f41555236 100644 --- a/src/Uno.UI/UI/Xaml/Application.skia.cs +++ b/src/Uno.UI/UI/Xaml/Application.skia.cs @@ -11,6 +11,8 @@ using Uno.Foundation.Logging; using System.Threading; using System.Globalization; +using Windows.ApplicationModel.Core; +using Uno.UI.Xaml.Core; namespace Windows.UI.Xaml { @@ -33,6 +35,15 @@ public Application() } _ = CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, Initialize); + + CoreApplication.SetInvalidateRender(() => + { + var roots = CoreServices.Instance.ContentRootCoordinator.ContentRoots; + for (int i = 0; i < roots.Count; i++) + { + roots[i].XamlRoot?.QueueInvalidateRender(); + } + }); } internal ISkiaApplicationHost? Host { get; set; } diff --git a/src/Uno.UI/UI/Xaml/Window.skia.cs b/src/Uno.UI/UI/Xaml/Window.skia.cs index 6141f98777c2..0a1f34e7b51a 100644 --- a/src/Uno.UI/UI/Xaml/Window.skia.cs +++ b/src/Uno.UI/UI/Xaml/Window.skia.cs @@ -64,8 +64,6 @@ private void InternalSetContent(UIElement content) throw new InvalidOperationException("The root visual could not be created."); } - CoreWindow.SetInvalidateRender(_rootVisual.XamlRoot.QueueInvalidateRender); - UIElement.LoadingRootElement(_rootVisual); _rootVisual?.XamlRoot.InvalidateMeasure(); diff --git a/src/Uno.UI/Uno.UI.Skia.csproj b/src/Uno.UI/Uno.UI.Skia.csproj index dbe4aec6d5ab..6e32c9855b3f 100644 --- a/src/Uno.UI/Uno.UI.Skia.csproj +++ b/src/Uno.UI/Uno.UI.Skia.csproj @@ -48,10 +48,6 @@ - - - - diff --git a/src/Uno.UWP/ApplicationModel/Core/CoreApplication.skia.cs b/src/Uno.UWP/ApplicationModel/Core/CoreApplication.skia.cs index f83222a446f0..22d0bff033cf 100644 --- a/src/Uno.UWP/ApplicationModel/Core/CoreApplication.skia.cs +++ b/src/Uno.UWP/ApplicationModel/Core/CoreApplication.skia.cs @@ -1,5 +1,6 @@ #nullable enable +using System; using Uno.Foundation.Logging; using Uno.ApplicationModel.Core; using Uno.Foundation.Extensibility; @@ -8,6 +9,7 @@ namespace Windows.ApplicationModel.Core; partial class CoreApplication { + private static Action? _invalidateRender; private static ICoreApplicationExtension? _coreApplicationExtension; static partial void InitializePlatform() @@ -29,4 +31,11 @@ private static void ExitPlatform() } } } + + internal static void SetInvalidateRender(Action invalidateRender) + // Currently we don't support multi-windowing, so we invalidate all XamlRoots + => _invalidateRender ??= invalidateRender; + + internal static void QueueInvalidateRender() + => _invalidateRender?.Invoke(); } diff --git a/src/Uno.UWP/UI/Core/CoreWindow.cs b/src/Uno.UWP/UI/Core/CoreWindow.cs index 1b1ccffa6a4a..7f3d22c83d04 100644 --- a/src/Uno.UWP/UI/Core/CoreWindow.cs +++ b/src/Uno.UWP/UI/Core/CoreWindow.cs @@ -20,7 +20,6 @@ public partial class CoreWindow { [ThreadStatic] private static CoreWindow? _current; - private static Action? _invalidateRender; private Point? _pointerPosition; private CoreWindowActivationState _lastActivationState; @@ -107,13 +106,6 @@ public CoreVirtualKeyStates GetAsyncKeyState(System.VirtualKey virtualKey) public CoreVirtualKeyStates GetKeyState(System.VirtualKey virtualKey) => KeyboardStateTracker.GetKeyState(virtualKey); - internal static void SetInvalidateRender(Action invalidateRender) - // Currently we don't support multi-windowing, so only the first window can set the InvalidateRender - => _invalidateRender ??= invalidateRender; - - internal static void QueueInvalidateRender() - => _invalidateRender?.Invoke(); - internal void OnActivated(WindowActivatedEventArgs args) { _lastActivationState = args.WindowActivationState; From ee46dc314e902db9d9a8ab80312c0d5e82bb89b9 Mon Sep 17 00:00:00 2001 From: Martin Zikmund Date: Mon, 5 Jun 2023 12:49:18 +0200 Subject: [PATCH 20/37] chore: Shared overlay invalidation, restore WPF input --- .../Hosting/IGtkWindowHost.cs | 2 +- .../Hosting/IGtkXamlRootHost.cs | 4 +- .../Rendering/GLRenderSurfaceBase.cs | 28 +--------- .../Rendering/GtkRendererProvider.cs | 56 +++++++++++++++++++ .../Rendering/IGtkRenderer.cs | 1 + .../Rendering/OpenGLESRenderSurface.cs | 3 +- .../Rendering/OpenGLRenderSurface.cs | 16 +----- .../Rendering/SoftwareRenderSurface.cs | 33 +---------- .../UI/Controls/UnoGtkWindow.cs | 24 +++----- .../Renderer.cs | 2 +- .../Themes/Generic.xaml | 4 +- .../UI/Controls/UnoWpfWindowHost.cs | 15 +---- .../UnoXamlHostBase.host.cs | 4 +- src/Uno.UI/UI/Xaml/XamlRoot.input.skia.cs | 12 ---- src/Uno.UI/UI/Xaml/XamlRoot.skia.cs | 22 ++++++++ 15 files changed, 104 insertions(+), 122 deletions(-) create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/Rendering/GtkRendererProvider.cs delete mode 100644 src/Uno.UI/UI/Xaml/XamlRoot.input.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/XamlRoot.skia.cs diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs index 0d9885e034b2..e69cdf3d531c 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkWindowHost.cs @@ -1,4 +1,4 @@ -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia.GTK.Hosting; diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkXamlRootHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkXamlRootHost.cs index de050b0f2290..5968b0fbbdf1 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkXamlRootHost.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Hosting/IGtkXamlRootHost.cs @@ -1,11 +1,13 @@ #nullable enable using Gtk; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia.GTK.Hosting; internal interface IGtkXamlRootHost : IXamlRootHost { Fixed? NativeOverlayLayer { get; } + + RenderSurfaceType? RenderSurfaceType { get; } } diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs index d4c54d544d9d..0b62d8fa9045 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GLRenderSurfaceBase.cs @@ -3,23 +3,14 @@ using System; using System.IO; using SkiaSharp; -using Uno.Extensions; using Uno.UI.Xaml.Core; using Windows.UI.Xaml.Input; using WUX = Windows.UI.Xaml; using Uno.Foundation.Logging; using Windows.UI.Xaml.Controls; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Uno.UI.Runtime.Skia.Helpers.Windows; -using Uno.UI.Runtime.Skia.Helpers.Dpi; using Windows.Graphics.Display; -using Gdk; -using System.Reflection; using Gtk; -using System.Runtime.InteropServices.JavaScript; -using Uno.UI.Runtime.Skia.GTK.Hosting; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia { @@ -80,12 +71,7 @@ public GLRenderSurfaceBase(IXamlRootHost host) public Widget Widget => this; - public void InvalidateRender() - { - // TODO Uno: Make this invalidation less often if possible. - InvalidateOverlays(); - QueueRender(); - } + public void InvalidateRender() => QueueRender(); private void GLRenderSurface_Realized(object? sender, EventArgs e) { @@ -192,16 +178,6 @@ private void GLFlush() private void OnDpiChanged(DisplayInformation sender, object args) => UpdateDpi(); - private void InvalidateOverlays() - { - _focusManager ??= VisualTree.GetFocusManagerForElement(Windows.UI.Xaml.Window.Current?.RootElement); - _focusManager?.FocusRectManager?.RedrawFocusVisual(); - if (_focusManager?.FocusedElement is TextBox textBox) - { - textBox.TextBoxView?.Extension?.InvalidateLayout(); - } - } - public void TakeScreenshot(string filePath) { if (_surface != null) diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GtkRendererProvider.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GtkRendererProvider.cs new file mode 100644 index 000000000000..6e6626d1bdaf --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/GtkRendererProvider.cs @@ -0,0 +1,56 @@ +using System; +using Uno.Foundation.Logging; +using Uno.UI.Runtime.Skia.GTK.Hosting; + +namespace Uno.UI.Runtime.Skia.GTK.Rendering; + +internal static class GTKRendererProvider +{ + public static IGtkRenderer CreateForHost(IGtkXamlRootHost host) + { + var requestedRenderer = host.RenderSurfaceType ?? RenderSurfaceType.OpenGL; + + if (typeof(GTKRendererProvider).Log().IsEnabled(LogLevel.Debug)) + { + typeof(GTKRendererProvider).Log().Debug($"Validating {host.RenderSurfaceType} rendering"); + } + + IGtkRenderer renderer = null; + while (renderer is null) + { + renderer = requestedRenderer switch + { + RenderSurfaceType.Software => new SoftwareGTKRenderer(host), + RenderSurfaceType.OpenGL => new OpenGLGTKRenderer(host), + _ => throw new InvalidOperationException($"Render Surface type {host.RenderSurfaceType} is not supported") + }; + + if (!renderer.TryInitialize()) + { + renderer.Dispose(); + renderer = null; + + // OpenGL initialization failed, fallback to software rendering + // This may happen on headless systems or containers. + + if (typeof(GTKRendererProvider).Log().IsEnabled(LogLevel.Warning)) + { + typeof(GTKRendererProvider).Log().Warn($"OpenGL failed to initialize, using software rendering"); + } + + requestedRenderer = RenderSurfaceType.Software; + } + } + + return renderer; + } + + private static IGtkRenderer BuildRenderSurfaceType(RenderSurfaceType renderSurfaceType, IGtkXamlRootHost host) + => renderSurfaceType switch + { + Skia.RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(host), + Skia.RenderSurfaceType.OpenGL => new OpenGLRenderSurface(host), + Skia.RenderSurfaceType.Software => new SoftwareRenderSurface(host), + _ => throw new InvalidOperationException($"Unsupported RenderSurfaceType {GtkHost.Current!.RenderSurfaceType}") + }; +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs index 481f95f191b1..b5756bb27d9c 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/IGtkRenderer.cs @@ -4,4 +4,5 @@ namespace Uno.UI.Runtime.Skia; internal interface IGtkRenderer : IRenderer { + void InvalidateRender(); } diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLESRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLESRenderSurface.cs index f525ad6e6320..514a3f9218dd 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLESRenderSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLESRenderSurface.cs @@ -20,11 +20,10 @@ using Silk.NET.OpenGLES; using Silk.NET.Core.Loader; using Silk.NET.Core.Contexts; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia { - internal class OpenGLESRenderSurface : GLRenderSurfaceBase { private static DefaultNativeContext? _nativeContext; diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLRenderSurface.cs index 1b053c996f6c..194ac6ddae02 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLRenderSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/OpenGLRenderSurface.cs @@ -1,27 +1,13 @@ #nullable enable using System; -using System.IO; using SkiaSharp; -using Uno.Extensions; -using Uno.UI.Xaml.Core; -using Windows.UI.Xaml.Input; -using WUX = Windows.UI.Xaml; using Uno.Foundation.Logging; -using Windows.UI.Xaml.Controls; -using System.Diagnostics; using System.Runtime.InteropServices; -using Uno.UI.Runtime.Skia.Helpers.Windows; -using Uno.UI.Runtime.Skia.Helpers.Dpi; -using Windows.Graphics.Display; -using Gdk; -using System.Reflection; -using Gtk; using Silk.NET.OpenGL; using Silk.NET.Core.Loader; using Silk.NET.Core.Contexts; -using static Uno.UI.Runtime.Skia.OpenGLESRenderSurface; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia { diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs index 3ccb7ddd5012..f2fe1b379f8e 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/Rendering/SoftwareRenderSurface.cs @@ -1,30 +1,22 @@ #nullable enable -using System; using System.IO; using System.Runtime.InteropServices; using Cairo; using SkiaSharp; -using Uno.Extensions; -using Uno.UI.Xaml.Core; using Windows.UI.Xaml.Input; using WUX = Windows.UI.Xaml; using Uno.Foundation.Logging; -using Windows.UI.Xaml.Controls; using System.Diagnostics; -using Uno.UI.Runtime.Skia.Helpers.Windows; -using Uno.UI.Runtime.Skia.Helpers.Dpi; using Windows.Graphics.Display; using Gtk; -using System.Runtime.InteropServices.JavaScript; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia; internal class SoftwareRenderSurface : Gtk.DrawingArea, IGtkRenderer { private readonly DisplayInformation _displayInformation; - private FocusManager? _focusManager; private SKSurface? _surface; private SKBitmap? _bitmap; private int _bheight, _bwidth; @@ -58,28 +50,9 @@ public SoftwareRenderSurface(IXamlRootHost host) public Widget Widget => this; - public void InvalidateRender() - { - // TODO Uno: Make this invalidation less often if possible. - InvalidateOverlays(); - Invalidate(); - } - - private void OnDpiChanged(DisplayInformation sender, object args) => - UpdateDpi(); - - private void InvalidateOverlays() - { - _focusManager ??= VisualTree.GetFocusManagerForElement(Windows.UI.Xaml.Window.Current?.RootElement); - _focusManager?.FocusRectManager?.RedrawFocusVisual(); - if (_focusManager?.FocusedElement is TextBox textBox) - { - textBox.TextBoxView?.Extension?.InvalidateLayout(); - } - } + public void InvalidateRender() => QueueDrawArea(0, 0, 10000, 10000); - private void Invalidate() - => QueueDrawArea(0, 0, 10000, 10000); + private void OnDpiChanged(DisplayInformation sender, object args) => UpdateDpi(); protected override bool OnDrawn(Context cr) { diff --git a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs index 8cb3e49e5afd..3a5a68e008d9 100644 --- a/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs +++ b/src/Uno.UI.Runtime.Skia.Gtk/UI/Controls/UnoGtkWindow.cs @@ -4,19 +4,17 @@ using System.Collections.Generic; using Gtk; using Uno.Disposables; -using Uno.Foundation.Logging; using Uno.UI.Runtime.Skia.GTK.UI.Core; using Uno.UI.Xaml.Core; using Windows.Foundation; -using Windows.UI.Core.Preview; using Windows.UI.ViewManagement; -using Windows.UI.WebUI; -using Windows.UI.Xaml; using WinUIWindow = Windows.UI.Xaml.Window; -using UnoApplication = Windows.UI.Xaml.Application; using WinUI = Windows.UI.Xaml; using Uno.UI.Runtime.Skia.GTK.Hosting; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Controls; +using Uno.UI.Rendering; namespace Uno.UI.Runtime.Skia.UI.Xaml.Controls; #pragma warning disable CS0649 @@ -25,6 +23,7 @@ namespace Uno.UI.Runtime.Skia.UI.Xaml.Controls; internal class UnoGtkWindow : Gtk.Window, IGtkWindowHost { private readonly WinUIWindow _window; + private FocusManager? _focusManager; private static UnoEventBox? _eventBox; private Widget? _area; @@ -230,16 +229,6 @@ private void UpdateWindowPropertiesFromPackage() } - private IGtkRenderer BuildRenderSurfaceType() - => GtkHost.Current!.RenderSurfaceType switch - { - Skia.RenderSurfaceType.OpenGLES => new OpenGLESRenderSurface(this), - Skia.RenderSurfaceType.OpenGL => new OpenGLRenderSurface(this), - Skia.RenderSurfaceType.Software => new SoftwareRenderSurface(this), - _ => throw new InvalidOperationException($"Unsupported RenderSurfaceType {GtkHost.Current!.RenderSurfaceType}") - }; - - //private void SetupRenderSurface() //{ // TryReadRenderSurfaceTypeEnvironment(); @@ -368,7 +357,8 @@ private void OnCoreWindowContentRootSet(object sender, object e) void IXamlRootHost.InvalidateRender() { - //InvalidateOverlays(); + _window.RootElement?.XamlRoot?.InvalidateOverlays(); + _renderSurface?.InvalidateRender(); } diff --git a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs index ac6e510aa8b7..9741bec6ffcb 100644 --- a/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs +++ b/src/Uno.UI.Runtime.Skia.Linux.FrameBuffer/Renderer.cs @@ -9,7 +9,7 @@ using Uno.Foundation.Logging; using Windows.Graphics.Display; using System.Runtime.InteropServices.JavaScript; -using Uno.UI.Xaml.Hosting; +using Uno.UI.Hosting; namespace Uno.UI.Runtime.Skia { diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml b/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml index e8f6c9be9f3d..8f1af50f1e32 100644 --- a/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml +++ b/src/Uno.UI.Runtime.Skia.Wpf/Themes/Generic.xaml @@ -4,10 +4,10 @@ xmlns:controls="clr-namespace:Uno.UI.Runtime.Skia.Wpf.Controls" xmlns:platform="clr-namespace:Uno.UI.Skia.Wpf"> -