Browse Source

[Android] Do not underutilize CPU/GPU when can't keep up with refresh rate (#18973)

pull/18993/head
Nikita Tsukanov 1 year ago
committed by GitHub
parent
commit
37121ba3be
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 38
      src/Android/Avalonia.Android/ChoreographerTimer.cs

38
src/Android/Avalonia.Android/ChoreographerTimer.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Android.OS; using Android.OS;
@ -7,16 +8,16 @@ using Android.Views;
using Avalonia.Reactive; using Avalonia.Reactive;
using Avalonia.Rendering; using Avalonia.Rendering;
using ThreadPriority = System.Threading.ThreadPriority;
using Java.Lang;
namespace Avalonia.Android namespace Avalonia.Android
{ {
internal sealed class ChoreographerTimer : Java.Lang.Object, IRenderTimer, Choreographer.IFrameCallback internal sealed class ChoreographerTimer : Java.Lang.Object, IRenderTimer, Choreographer.IFrameCallback
{ {
private readonly object _lock = new(); private readonly object _lock = new();
private readonly Thread _thread; private AutoResetEvent _event = new(false);
private long _lastTime;
private readonly TaskCompletionSource<Choreographer> _choreographer = new(); private readonly TaskCompletionSource<Choreographer> _choreographer = new();
private readonly ISet<AvaloniaView> _views = new HashSet<AvaloniaView>(); private readonly ISet<AvaloniaView> _views = new HashSet<AvaloniaView>();
@ -26,8 +27,14 @@ namespace Avalonia.Android
public ChoreographerTimer() public ChoreographerTimer()
{ {
_thread = new Thread(Loop); new Thread(Loop)
_thread.Start(); {
Priority = ThreadPriority.AboveNormal
}.Start();
new Thread(RenderLoop)
{
Priority = ThreadPriority.AboveNormal
}.Start();
} }
public bool RunsInBackground => true; public bool RunsInBackground => true;
@ -86,17 +93,32 @@ namespace Avalonia.Android
_choreographer.SetResult(Choreographer.Instance!); _choreographer.SetResult(Choreographer.Instance!);
Looper.Loop(); Looper.Loop();
} }
private void RenderLoop()
{
while (true)
{
_event.WaitOne();
long time;
lock (_lock)
{
time = _lastTime;
}
_tick?.Invoke(TimeSpan.FromTicks(time / 100));
}
}
public void DoFrame(long frameTimeNanos) public void DoFrame(long frameTimeNanos)
{ {
_tick?.Invoke(TimeSpan.FromTicks(frameTimeNanos / 100));
lock (_lock) lock (_lock)
{ {
if (_count > 0 && _views.Count > 0) if (_count > 0 && _views.Count > 0)
{ {
Choreographer.Instance!.PostFrameCallback(this); Choreographer.Instance!.PostFrameCallback(this);
} }
_lastTime = frameTimeNanos;
_event.Set();
} }
} }
} }

Loading…
Cancel
Save