From 067f0d0ad088d02364d4b977f21c1f87a2f47852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Fri, 22 Jan 2021 09:36:06 +0000 Subject: [PATCH 1/8] Added OpenGL support on Android. --- .../Avalonia.Android/AndroidPlatform.cs | 19 +++++++++-- .../OpenGL/GlPlatformSurface.cs | 32 +++++++++++++++++++ .../Avalonia.Android/OpenGL/GlRenderTarget.cs | 23 +++++++++++++ .../SkiaPlatform/FramebufferManager.cs | 17 ++++++++++ .../Platform/SkiaPlatform/TopLevelImpl.cs | 30 +++++++++++++---- src/Avalonia.OpenGL/Egl/EglInterface.cs | 4 ++- src/Shared/PlatformSupport/DynLoader.cs | 14 +++++++- 7 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs create mode 100644 src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs create mode 100644 src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs index 2e6f4a67c3..e0ceb0c8b7 100644 --- a/src/Android/Avalonia.Android/AndroidPlatform.cs +++ b/src/Android/Avalonia.Android/AndroidPlatform.cs @@ -1,11 +1,13 @@ using System; + +using Avalonia.Android; using Avalonia.Android.Platform; using Avalonia.Android.Platform.Input; -using Avalonia.Android.Platform.SkiaPlatform; using Avalonia.Controls; using Avalonia.Controls.Platform; using Avalonia.Input; using Avalonia.Input.Platform; +using Avalonia.OpenGL.Egl; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Shared.PlatformSupport; @@ -17,7 +19,8 @@ namespace Avalonia { public static T UseAndroid(this T builder) where T : AppBuilderBase, new() { - builder.UseWindowingSubsystem(() => Android.AndroidPlatform.Initialize(builder.ApplicationType), "Android"); + var options = AvaloniaLocator.Current.GetService() ?? new AndroidPlatformOptions(); + builder.UseWindowingSubsystem(() => AndroidPlatform.Initialize(builder.ApplicationType, options), "Android"); builder.UseSkia(); return builder; } @@ -41,7 +44,7 @@ namespace Avalonia.Android _scalingFactor = global::Android.App.Application.Context.Resources.DisplayMetrics.ScaledDensity; } - public static void Initialize(Type appType) + public static void Initialize(Type appType, AndroidPlatformOptions options) { AvaloniaLocator.CurrentMutable .Bind().ToTransient() @@ -60,6 +63,11 @@ namespace Avalonia.Android SkiaPlatform.Initialize(); ((global::Android.App.Application) global::Android.App.Application.Context.ApplicationContext) .RegisterActivityLifecycleCallbacks(new ActivityTracker()); + + if (options.UseGpu) + { + EglPlatformOpenGlInterface.TryInitialize(); + } } public IWindowImpl CreateWindow() @@ -72,4 +80,9 @@ namespace Avalonia.Android throw new NotSupportedException(); } } + + public sealed class AndroidPlatformOptions + { + public bool UseGpu { get; set; } = true; + } } diff --git a/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs b/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs new file mode 100644 index 0000000000..4f4c03fe77 --- /dev/null +++ b/src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs @@ -0,0 +1,32 @@ +using System.Linq; + +using Avalonia.OpenGL.Egl; +using Avalonia.OpenGL.Surfaces; + +namespace Avalonia.Android.OpenGL +{ + internal sealed class GlPlatformSurface : EglGlPlatformSurfaceBase + { + private readonly EglPlatformOpenGlInterface _egl; + private readonly IEglWindowGlPlatformSurfaceInfo _info; + + private GlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSurfaceInfo info) + { + _egl = egl; + _info = info; + } + + public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() => + new GlRenderTarget(_egl, _info, _egl.CreateWindowSurface(_info.Handle)); + + public static GlPlatformSurface TryCreate(IEglWindowGlPlatformSurfaceInfo info) + { + if (EglPlatformOpenGlInterface.TryCreate() is EglPlatformOpenGlInterface egl) + { + return new GlPlatformSurface(egl, info); + } + + return null; + } + } +} diff --git a/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs b/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs new file mode 100644 index 0000000000..75bbd15e3e --- /dev/null +++ b/src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs @@ -0,0 +1,23 @@ +using Avalonia.OpenGL.Egl; +using Avalonia.OpenGL.Surfaces; + +namespace Avalonia.Android.OpenGL +{ + internal sealed class GlRenderTarget : EglPlatformSurfaceRenderTargetBase + { + private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info; + private readonly EglSurface _surface; + + public GlRenderTarget( + EglPlatformOpenGlInterface egl, + EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info, + EglSurface surface) + : base(egl) + { + _info = info; + _surface = surface; + } + + public override IGlPlatformSurfaceRenderingSession BeginDraw() => BeginDraw(_surface, _info); + } +} diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs new file mode 100644 index 0000000000..18c4796fae --- /dev/null +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/FramebufferManager.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls.Platform.Surfaces; +using Avalonia.Platform; + +namespace Avalonia.Android.Platform.SkiaPlatform +{ + internal sealed class FramebufferManager : IFramebufferPlatformSurface + { + private readonly TopLevelImpl _topLevel; + + public FramebufferManager(TopLevelImpl topLevel) + { + _topLevel = topLevel; + } + + public ILockedFramebuffer Lock() => new AndroidFramebuffer(_topLevel.InternalView.Holder.Surface); + } +} diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs index 360e76b2dc..a8c7f7af9b 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs @@ -2,7 +2,10 @@ using System; using System.Collections.Generic; using Android.Content; using Android.Graphics; +using Android.Runtime; using Android.Views; + +using Avalonia.Android.OpenGL; using Avalonia.Android.Platform.Input; using Avalonia.Android.Platform.Specific; using Avalonia.Android.Platform.Specific.Helpers; @@ -10,13 +13,18 @@ using Avalonia.Controls; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Input; using Avalonia.Input.Raw; +using Avalonia.OpenGL.Egl; +using Avalonia.OpenGL.Surfaces; using Avalonia.Platform; using Avalonia.Rendering; namespace Avalonia.Android.Platform.SkiaPlatform { - class TopLevelImpl : IAndroidView, ITopLevelImpl, IFramebufferPlatformSurface + class TopLevelImpl : IAndroidView, ITopLevelImpl, EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo { + private readonly IGlPlatformSurface _gl; + private readonly IFramebufferPlatformSurface _framebuffer; + private readonly AndroidKeyboardEventsHelper _keyboardHelper; private readonly AndroidTouchEventsHelper _touchHelper; @@ -29,7 +37,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform _touchHelper = new AndroidTouchEventsHelper(this, () => InputRoot, p => GetAvaloniaPointFromEvent(p)); - Surfaces = new object[] { this }; + _gl = GlPlatformSurface.TryCreate(this); + _framebuffer = new FramebufferManager(this); MaxClientSize = new Size(_view.Resources.DisplayMetrics.WidthPixels, _view.Resources.DisplayMetrics.HeightPixels); @@ -48,7 +57,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform _keyboardHelper.HandleEvents = _handleEvents; } } - + public virtual Point GetAvaloniaPointFromEvent(MotionEvent e) => new Point(e.GetX(), e.GetY()); public IInputRoot InputRoot { get; private set; } @@ -63,7 +72,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform } set { - + } } @@ -83,9 +92,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform public View View => _view; + internal InvalidationAwareSurfaceView InternalView => _view; + public IPlatformHandle Handle => _view; - public IEnumerable Surfaces { get; } + public IEnumerable Surfaces => new object[] { _gl, _framebuffer }; public IRenderer CreateRenderer(IRenderRoot root) { @@ -96,7 +107,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform { _view.Visibility = ViewStates.Invisible; } - + public void Invalidate(Rect rect) { if (_view.Holder?.Surface?.IsValid == true) _view.Invalidate(); @@ -203,7 +214,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform public AcrylicPlatformCompensationLevels AcrylicCompensationLevels => new AcrylicPlatformCompensationLevels(1, 1, 1); - ILockedFramebuffer IFramebufferPlatformSurface.Lock() => new AndroidFramebuffer(_view.Holder.Surface); + IntPtr EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo.Handle => + AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, _view.Holder.Surface.Handle); + + public PixelSize Size => new PixelSize(_view.Holder.SurfaceFrame.Width(), _view.Holder.SurfaceFrame.Height()); + + public double Scaling => RenderScaling; public void SetTransparencyLevelHint(WindowTransparencyLevel transparencyLevel) { diff --git a/src/Avalonia.OpenGL/Egl/EglInterface.cs b/src/Avalonia.OpenGL/Egl/EglInterface.cs index 8055226042..cadd7cc1f2 100644 --- a/src/Avalonia.OpenGL/Egl/EglInterface.cs +++ b/src/Avalonia.OpenGL/Egl/EglInterface.cs @@ -30,8 +30,10 @@ namespace Avalonia.OpenGL.Egl static Func Load() { var os = AvaloniaLocator.Current.GetService().GetRuntimeInfo().OperatingSystem; - if(os == OperatingSystemType.Linux || os == OperatingSystemType.Android) + if(os == OperatingSystemType.Linux) return Load("libEGL.so.1"); + if (os == OperatingSystemType.Android) + return Load("libEGL.so"); throw new PlatformNotSupportedException(); } diff --git a/src/Shared/PlatformSupport/DynLoader.cs b/src/Shared/PlatformSupport/DynLoader.cs index 5884558baa..8fd4b1ad1e 100644 --- a/src/Shared/PlatformSupport/DynLoader.cs +++ b/src/Shared/PlatformSupport/DynLoader.cs @@ -11,13 +11,25 @@ namespace Avalonia.Shared.PlatformSupport // ReSharper disable InconsistentNaming static class LinuxImports { +#if __ANDROID__ + [DllImport("libdl.so")] +#else [DllImport("libdl.so.2")] +#endif private static extern IntPtr dlopen(string path, int flags); +#if __ANDROID__ + [DllImport("libdl.so")] +#else [DllImport("libdl.so.2")] +#endif private static extern IntPtr dlsym(IntPtr handle, string symbol); +#if __ANDROID__ + [DllImport("libdl.so")] +#else [DllImport("libdl.so.2")] +#endif private static extern IntPtr dlerror(); public static void Init() @@ -27,7 +39,7 @@ namespace Avalonia.Shared.PlatformSupport DlError = dlerror; } } - + static class OsXImports { From 259a45c4e0dbef2db792ae9ef007537ce78874ac Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 21 Jan 2021 21:31:21 +0000 Subject: [PATCH 2/8] bump versions. # Conflicts: # build/SharedVersion.props --- build/SharedVersion.props | 2 +- src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/SharedVersion.props b/build/SharedVersion.props index 9a268a21e7..75bada4bfc 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -3,7 +3,7 @@ Avalonia 0.10.999 - Copyright 2020 © The AvaloniaUI Project + Copyright 2021 © The AvaloniaUI Project https://avaloniaui.net https://github.com/AvaloniaUI/Avalonia/ true diff --git a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml index c5e1d43d80..08e8798cd5 100644 --- a/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml +++ b/src/Avalonia.Dialogs/AboutAvaloniaDialog.xaml @@ -99,7 +99,7 @@ - + From 70995c961dd3c32d8abb78fabeb714a0ca539f9e Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Fri, 22 Jan 2021 22:02:35 +0000 Subject: [PATCH 3/8] api compat baseline. --- build/ApiDiff.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ApiDiff.props b/build/ApiDiff.props index da59ad4bf2..666417addf 100644 --- a/build/ApiDiff.props +++ b/build/ApiDiff.props @@ -1,6 +1,6 @@  - 0.10.0-rc1 + 0.10.0 $(PackageId) Avalonia From 9933de07fd2f1aad2950e1ed84d13f0a0a572edf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Fri, 22 Jan 2021 19:37:02 -0500 Subject: [PATCH 4/8] Override default value instead of setting local value in LightDismissOverlayLayer --- .../Primitives/LightDismissOverlayLayer.cs | 6 ++++++ src/Avalonia.Controls/Primitives/VisualLayerManager.cs | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs index 752eedb68a..1d655bb691 100644 --- a/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs +++ b/src/Avalonia.Controls/Primitives/LightDismissOverlayLayer.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using Avalonia.Controls.Templates; using Avalonia.Input; +using Avalonia.Media; using Avalonia.Rendering; using Avalonia.Styling; using Avalonia.VisualTree; @@ -17,6 +18,11 @@ namespace Avalonia.Controls.Primitives { public IInputElement? InputPassThroughElement { get; set; } + static LightDismissOverlayLayer() + { + BackgroundProperty.OverrideDefaultValue(Brushes.Transparent); + } + /// /// Returns the light dismiss overlay for a specified visual. /// diff --git a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs index d8d3450c6f..e5e27c169a 100644 --- a/src/Avalonia.Controls/Primitives/VisualLayerManager.cs +++ b/src/Avalonia.Controls/Primitives/VisualLayerManager.cs @@ -74,7 +74,6 @@ namespace Avalonia.Controls.Primitives { rv = new LightDismissOverlayLayer { - Background = Brushes.Transparent, IsVisible = false }; From 9052b2b73a95e36f6069a29905430ef293c0d9da Mon Sep 17 00:00:00 2001 From: Sven Almgren Date: Sat, 23 Jan 2021 09:25:18 +0100 Subject: [PATCH 5/8] Mark glBlitFramebuffer optional to allow ES2.0 drm devices --- src/Avalonia.OpenGL/GlInterface.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.OpenGL/GlInterface.cs b/src/Avalonia.OpenGL/GlInterface.cs index 28b62136da..cae245732f 100644 --- a/src/Avalonia.OpenGL/GlInterface.cs +++ b/src/Avalonia.OpenGL/GlInterface.cs @@ -128,7 +128,7 @@ namespace Avalonia.OpenGL int dstY1, int mask, int filter); - [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0)] + [GlMinVersionEntryPoint("glBlitFramebuffer", 3, 0), GlOptionalEntryPoint] public GlBlitFramebuffer BlitFramebuffer { get; } public delegate void GlGenRenderbuffers(int count, int[] res); From 86a9a7184113ee15e94c4586d6aa757ac8e3a31c Mon Sep 17 00:00:00 2001 From: Tako <53405089+Takoooooo@users.noreply.github.com> Date: Mon, 25 Jan 2021 12:42:01 +0200 Subject: [PATCH 6/8] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index cfa08149cb..46cfc7f38a 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ Avalonia is a cross-platform XAML-based UI framework providing a flexible stylin ([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery)) -> **Note:** The UI theme you see in the picture above is still work-in-progress and will be available in the upcoming Avalonia 0.10.0 release. However, you can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info. +> **Note:** You can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info. To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia! From a1f9749490fcef22bb682a763ae77a2b54c36c15 Mon Sep 17 00:00:00 2001 From: Mike James Date: Mon, 25 Jan 2021 11:10:49 +0000 Subject: [PATCH 7/8] Fixing FluentTheme Expanded header foreground issue My first attempt at contributing! This commit adds a style selector to ensure that the Expanded control keeps its foreground when expanded. Fixes #5349 Tested with 0.10.0 with both Light and Dark themes. --- src/Avalonia.Themes.Fluent/Controls/Expander.xaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml index ad0fd18ea5..a6371a5be9 100644 --- a/src/Avalonia.Themes.Fluent/Controls/Expander.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/Expander.xaml @@ -26,6 +26,9 @@ +