Skip to content

Commit

Permalink
Use deferred renderer on Android.
Browse files Browse the repository at this point in the history
  • Loading branch information
jp2masa committed Jan 27, 2021
1 parent 3e279e0 commit 523cd74
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 70 deletions.
47 changes: 0 additions & 47 deletions src/Android/Avalonia.Android/ActivityTracker.cs

This file was deleted.

8 changes: 5 additions & 3 deletions src/Android/Avalonia.Android/AndroidPlatform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace Avalonia.Android
class AndroidPlatform : IPlatformSettings, IWindowingPlatform
{
public static readonly AndroidPlatform Instance = new AndroidPlatform();
public static AndroidPlatformOptions Options { get; private set; }
public Size DoubleClickSize => new Size(4, 4);
public TimeSpan DoubleClickTime => TimeSpan.FromMilliseconds(200);
public double RenderScalingFactor => _scalingFactor;
Expand All @@ -46,6 +47,8 @@ public AndroidPlatform()

public static void Initialize(Type appType, AndroidPlatformOptions options)
{
Options = options;

AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToTransient<ClipboardImpl>()
.Bind<IStandardCursorFactory>().ToTransient<CursorFactory>()
Expand All @@ -55,14 +58,12 @@ public static void Initialize(Type appType, AndroidPlatformOptions options)
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<IRenderTimer>().ToConstant(new ChoreographerTimer())
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IAssetLoader>().ToConstant(new AssetLoader(appType.Assembly));

SkiaPlatform.Initialize();
((global::Android.App.Application) global::Android.App.Application.Context.ApplicationContext)
.RegisterActivityLifecycleCallbacks(new ActivityTracker());

if (options.UseGpu)
{
Expand All @@ -83,6 +84,7 @@ public IWindowImpl CreateEmbeddableWindow()

public sealed class AndroidPlatformOptions
{
public bool UseDeferredRendering { get; set; } = true;
public bool UseGpu { get; set; } = true;
}
}
31 changes: 27 additions & 4 deletions src/Android/Avalonia.Android/AvaloniaActivity.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,50 @@

using Android.App;
using Android.OS;
using Android.Views;

using Avalonia.Rendering;

namespace Avalonia.Android
{
public abstract class AvaloniaActivity : Activity
{

internal AvaloniaView View;
object _content;

protected override void OnCreate(Bundle savedInstanceState)
{
RequestWindowFeature(WindowFeatures.NoTitle);
View = new AvaloniaView(this);
if(_content != null)
if (_content != null)
View.Content = _content;
SetContentView(View);
TakeKeyEvents(true);
base.OnCreate(savedInstanceState);
}

protected override void OnResume()
{
base.OnResume();

if (AvaloniaLocator.Current.GetService<IRenderTimer>() is ChoreographerTimer timer)
{
timer.OnResume();
}

View.Root.Renderer.Start();
}

protected override void OnPause()
{
base.OnPause();

View.Root.Renderer.Stop();

if (AvaloniaLocator.Current.GetService<IRenderTimer>() is ChoreographerTimer timer)
{
timer.OnPause();
}
}

public object Content
{
get
Expand Down
12 changes: 7 additions & 5 deletions src/Android/Avalonia.Android/AvaloniaView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ namespace Avalonia.Android
{
public class AvaloniaView : FrameLayout
{
private readonly EmbeddableControlRoot _root;
private readonly ViewImpl _view;

public AvaloniaView(Context context) : base(context)
{
_view = new ViewImpl(context);
AddView(_view.View);
_root = new EmbeddableControlRoot(_view);
_root.Prepare();
Root = new EmbeddableControlRoot(_view);
Root.Prepare();
Root.Renderer.Start();
}

public object Content
{
get { return _root.Content; }
set { _root.Content = value; }
get { return Root.Content; }
set { Root.Content = value; }
}

internal EmbeddableControlRoot Root { get; }

public override bool DispatchKeyEvent(KeyEvent e)
{
return _view.View.DispatchKeyEvent(e);
Expand Down
66 changes: 66 additions & 0 deletions src/Android/Avalonia.Android/ChoreographerTimer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;

using Android.OS;
using Android.Views;

using Avalonia.Rendering;

using Java.Lang;

namespace Avalonia.Android
{
internal sealed class ChoreographerTimer : Java.Lang.Object, IRenderTimer, Choreographer.IFrameCallback
{
private readonly object _lock = new object();

private readonly Thread _thread;

private Choreographer _choreographer;
private bool _running;

public ChoreographerTimer()
{
_thread = new Thread(Loop);
_thread.Start();
}

public event Action<TimeSpan> Tick;

internal void OnResume()
{
lock (_lock)
{
_running = true;
_choreographer.PostFrameCallback(this);
}
}

internal void OnPause()
{
lock (_lock)
{
_running = false;
}
}

private void Loop()
{
Looper.Prepare();
_choreographer = Choreographer.Instance;
Looper.Loop();
}

public void DoFrame(long frameTimeNanos)
{
Tick?.Invoke(TimeSpan.FromTicks(frameTimeNanos / 100));

lock (_lock)
{
if (_running)
{
Choreographer.Instance.PostFrameCallback(this);
}
}
}
}
}
6 changes: 2 additions & 4 deletions src/Android/Avalonia.Android/OpenGL/GlPlatformSurface.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Linq;

using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;

namespace Avalonia.Android.OpenGL
Expand All @@ -17,7 +15,7 @@ private GlPlatformSurface(EglPlatformOpenGlInterface egl, IEglWindowGlPlatformSu
}

public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() =>
new GlRenderTarget(_egl, _info, _egl.CreateWindowSurface(_info.Handle));
new GlRenderTarget(_egl, _info, _egl.CreateWindowSurface(_info.Handle), _info.Handle);

public static GlPlatformSurface TryCreate(IEglWindowGlPlatformSurfaceInfo info)
{
Expand Down
13 changes: 10 additions & 3 deletions src/Android/Avalonia.Android/OpenGL/GlRenderTarget.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
using Avalonia.OpenGL.Egl;
using System;

using Avalonia.OpenGL.Egl;
using Avalonia.OpenGL.Surfaces;

namespace Avalonia.Android.OpenGL
{
internal sealed class GlRenderTarget : EglPlatformSurfaceRenderTargetBase
internal sealed class GlRenderTarget : EglPlatformSurfaceRenderTargetBase, IGlPlatformSurfaceRenderTargetWithCorruptionInfo
{
private readonly EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo _info;
private readonly EglSurface _surface;
private readonly IntPtr _handle;

public GlRenderTarget(
EglPlatformOpenGlInterface egl,
EglGlPlatformSurfaceBase.IEglWindowGlPlatformSurfaceInfo info,
EglSurface surface)
EglSurface surface,
IntPtr handle)
: base(egl)
{
_info = info;
_surface = surface;
_handle = handle;
}

public bool IsCorrupted => _handle != _info.Handle;

public override IGlPlatformSurfaceRenderingSession BeginDraw() => BeginDraw(_surface, _info);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ public virtual Size ClientSize

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

public IRenderer CreateRenderer(IRenderRoot root)
{
return new ImmediateRenderer(root);
}
public IRenderer CreateRenderer(IRenderRoot root) =>
AndroidPlatform.Options.UseDeferredRendering
? new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>()) { RenderOnlyOnRenderThread = true }
: new ImmediateRenderer(root);

public virtual void Hide()
{
Expand Down

0 comments on commit 523cd74

Please sign in to comment.