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 Feb 10, 2021
1 parent 73ad36c commit 8853460
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 64 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;
}
}
3 changes: 1 addition & 2 deletions src/Android/Avalonia.Android/AvaloniaActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ public abstract class AvaloniaActivity : Activity

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);
Expand Down
27 changes: 26 additions & 1 deletion src/Android/Avalonia.Android/AvaloniaView.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Platform;
using Avalonia.Rendering;

namespace Avalonia.Android
{
Expand Down Expand Up @@ -33,6 +34,30 @@ public override bool DispatchKeyEvent(KeyEvent e)
return _view.View.DispatchKeyEvent(e);
}

public override void OnVisibilityAggregated(bool isVisible)
{
base.OnVisibilityAggregated(isVisible);
OnVisibilityChanged(isVisible);
}

protected override void OnVisibilityChanged(View changedView, [GeneratedEnum] ViewStates visibility)
{
base.OnVisibilityChanged(changedView, visibility);
OnVisibilityChanged(visibility == ViewStates.Visible);
}

private void OnVisibilityChanged(bool isVisible)
{
if (isVisible)
{
_root.Renderer.Start();
}
else
{
_root.Renderer.Stop();
}
}

class ViewImpl : TopLevelImpl
{
public ViewImpl(Context context) : base(context)
Expand Down
74 changes: 74 additions & 0 deletions src/Android/Avalonia.Android/ChoreographerTimer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Threading.Tasks;

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 readonly TaskCompletionSource<Choreographer> _choreographer = new TaskCompletionSource<Choreographer>();

private Action<TimeSpan> _tick;
private int _count;

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

public event Action<TimeSpan> Tick
{
add
{
lock (_lock)
{
_tick += value;
_count++;

if (_count == 1)
{
_choreographer.Task.Result.PostFrameCallback(this);
}
}
}
remove
{
lock (_lock)
{
_tick -= value;
_count--;
}
}
}

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

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

lock (_lock)
{
if (_count > 0)
{
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 8853460

Please sign in to comment.