Browse Source

Fix input starvation issues on resource-constrained devices. (#15137)

* Use 0.2 seconds for input starvation cutoff.

1 second was too long when running on resource-constrained devices.

* Allow input starvation code to run.

Using `ScheduleRender(true)` here prevented the input starvation code from running.

* Add DispatcherOptions.

And allow setting the input starvation timeout there.
pull/15451/head
Steven Kirk 2 years ago
committed by GitHub
parent
commit
8a65cb6a68
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      src/Avalonia.Base/Media/MediaContext.Compositor.cs
  2. 13
      src/Avalonia.Base/Media/MediaContext.cs
  3. 21
      src/Avalonia.Base/Threading/DispatcherOptions.cs

2
src/Avalonia.Base/Media/MediaContext.Compositor.cs

@ -146,6 +146,6 @@ partial class MediaContext
return;
// TODO: maybe skip the full render here?
ScheduleRender(true);
ScheduleRender(false);
}
}

13
src/Avalonia.Base/Media/MediaContext.cs

@ -16,7 +16,7 @@ internal partial class MediaContext : ICompositorScheduler
private TimeSpan _inputMarkerAddedAt;
private bool _isRendering;
private bool _animationsAreWaitingForComposition;
private const double MaxSecondsWithoutInput = 1;
private readonly double MaxSecondsWithoutInput;
private readonly Action _render;
private readonly Action _inputMarkerHandler;
private readonly HashSet<Compositor> _requestedCommits = new();
@ -37,12 +37,13 @@ internal partial class MediaContext : ICompositorScheduler
private readonly Dictionary<object, TopLevelInfo> _topLevels = new();
private MediaContext(Dispatcher dispatcher)
private MediaContext(Dispatcher dispatcher, TimeSpan inputStarvationTimeout)
{
_render = Render;
_inputMarkerHandler = InputMarkerHandler;
_clock = new(this);
_dispatcher = dispatcher;
MaxSecondsWithoutInput = inputStarvationTimeout.TotalSeconds;
_animationsTimer.Tick += (_, _) =>
{
_animationsTimer.Stop();
@ -57,8 +58,14 @@ internal partial class MediaContext : ICompositorScheduler
// Technically it's supposed to be a thread-static singleton, but we don't have multiple threads
// and need to do a full reset for unit tests
var context = AvaloniaLocator.Current.GetService<MediaContext>();
if (context == null)
AvaloniaLocator.CurrentMutable.Bind<MediaContext>().ToConstant(context = new(Dispatcher.UIThread));
{
var opts = AvaloniaLocator.Current.GetService<DispatcherOptions>() ?? new();
context = new MediaContext(Dispatcher.UIThread, opts.InputStarvationTimeout);
AvaloniaLocator.CurrentMutable.Bind<MediaContext>().ToConstant(context);
}
return context;
}
}

21
src/Avalonia.Base/Threading/DispatcherOptions.cs

@ -0,0 +1,21 @@
using System;
namespace Avalonia.Threading;
/// <summary>
/// AppBuilder options for configuring the <see cref="Dispatcher"/>.
/// </summary>
public class DispatcherOptions
{
/// <summary>
/// Gets or sets a timeout after which the dispatcher will start prioritizing input events over
/// rendering. The default value is 1 second.
/// </summary>
/// <remarks>
/// If no input events are processed within this time, the dispatcher will start prioritizing
/// input events over rendering to prevent the application from becoming unresponsive. This may
/// need to be lowered on resource-constrained platforms where input events are processed on
/// the same thread as rendering.
/// </remarks>
public TimeSpan InputStarvationTimeout { get; set; } = TimeSpan.FromSeconds(1);
}
Loading…
Cancel
Save