Skip to content

Commit

Permalink
Added OpenGL support on Android.
Browse files Browse the repository at this point in the history
  • Loading branch information
jp2masa committed Jan 22, 2021
1 parent 091dc64 commit 3b9422c
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 12 deletions.
20 changes: 17 additions & 3 deletions src/Android/Avalonia.Android/AndroidPlatform.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -17,7 +19,8 @@ public static class AndroidApplicationExtensions
{
public static T UseAndroid<T>(this T builder) where T : AppBuilderBase<T>, new()
{
builder.UseWindowingSubsystem(() => Android.AndroidPlatform.Initialize(builder.ApplicationType), "Android");
var options = AvaloniaLocator.Current.GetService<AndroidPlatformOptions>() ?? new AndroidPlatformOptions();
builder.UseWindowingSubsystem(() => AndroidPlatform.Initialize(builder.ApplicationType, options), "Android");
builder.UseSkia();
return builder;
}
Expand All @@ -29,6 +32,7 @@ namespace Avalonia.Android
class AndroidPlatform : IPlatformSettings, IWindowingPlatform
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public static bool UseGpu { get; set; } = true;
public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200);
public double RenderScalingFactor => _scalingFactor;
Expand All @@ -41,7 +45,7 @@ public AndroidPlatform()
_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<IClipboard>().ToTransient<ClipboardImpl>()
Expand All @@ -60,6 +64,11 @@ public static void Initialize(Type appType)
SkiaPlatform.Initialize();
((global::Android.App.Application) global::Android.App.Application.Context.ApplicationContext)
.RegisterActivityLifecycleCallbacks(new ActivityTracker());

if (options.UseGpu)
{
EglPlatformOpenGlInterface.TryInitialize();
}
}

public IWindowImpl CreateWindow()
Expand All @@ -72,4 +81,9 @@ public IWindowImpl CreateEmbeddableWindow()
throw new NotSupportedException();
}
}

public sealed class AndroidPlatformOptions
{
public bool UseGpu { get; set; } = true;
}
}
32 changes: 32 additions & 0 deletions src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
23 changes: 23 additions & 0 deletions src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
30 changes: 23 additions & 7 deletions src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@
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;
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<TopLevelImpl> _keyboardHelper;
private readonly AndroidTouchEventsHelper<TopLevelImpl> _touchHelper;

Expand All @@ -29,7 +37,8 @@ public TopLevelImpl(Context context, bool placeOnTop = false)
_touchHelper = new AndroidTouchEventsHelper<TopLevelImpl>(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);
Expand All @@ -48,7 +57,7 @@ public bool HandleEvents
_keyboardHelper.HandleEvents = _handleEvents;
}
}

public virtual Point GetAvaloniaPointFromEvent(MotionEvent e) => new Point(e.GetX(), e.GetY());

public IInputRoot InputRoot { get; private set; }
Expand All @@ -63,7 +72,7 @@ public virtual Size ClientSize
}
set
{

}
}

Expand All @@ -83,9 +92,11 @@ public virtual Size ClientSize

public View View => _view;

internal InvalidationAwareSurfaceView InternalView => _view;

public IPlatformHandle Handle => _view;

public IEnumerable<object> Surfaces { get; }
public IEnumerable<object> Surfaces => new object[] { _gl, _framebuffer };

public IRenderer CreateRenderer(IRenderRoot root)
{
Expand All @@ -96,7 +107,7 @@ public virtual void Hide()
{
_view.Visibility = ViewStates.Invisible;
}

public void Invalidate(Rect rect)
{
if (_view.Holder?.Surface?.IsValid == true) _view.Invalidate();
Expand Down Expand Up @@ -203,7 +214,12 @@ void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format,

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)
{
Expand Down
4 changes: 3 additions & 1 deletion src/Avalonia.OpenGL/Egl/EglInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ public EglInterface(string library) : base(Load(library))
static Func<string, IntPtr> Load()
{
var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().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();
}
Expand Down
14 changes: 13 additions & 1 deletion src/Shared/PlatformSupport/DynLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,25 @@ class UnixLoader : IDynamicLibraryLoader
// 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()
Expand All @@ -27,7 +39,7 @@ public static void Init()
DlError = dlerror;
}
}

static class OsXImports
{

Expand Down

0 comments on commit 3b9422c

Please sign in to comment.