Browse Source

Don't await updates in render loop.

The render loop should not be waiting for an update to occur on the UI thread before rendering a frame. Instead of awaiting the call, simply call `IDispatcher.Post` to fire-and-forget. Placed a guard around the update to make sure multiple updates don't get queued if an update doesn't complete in a single frame.

Also don't call `IRenderLoopTask.Update` unless `IRenderLoopTask.NeedsUpdate == true`.

Fixes #1920
pull/1929/head
Steven Kirk 8 years ago
parent
commit
c311474d5b
  1. 31
      src/Avalonia.Visuals/Rendering/RenderLoop.cs

31
src/Avalonia.Visuals/Rendering/RenderLoop.cs

@ -19,7 +19,8 @@ namespace Avalonia.Rendering
private readonly IDispatcher _dispatcher;
private List<IRenderLoopTask> _items = new List<IRenderLoopTask>();
private IRenderTimer _timer;
private int inTick;
private int _inTick;
private int _inUpdate;
/// <summary>
/// Initializes a new instance of the <see cref="RenderLoop"/> class.
@ -84,21 +85,35 @@ namespace Avalonia.Rendering
}
}
private async void TimerTick(TimeSpan time)
private void TimerTick(TimeSpan time)
{
if (Interlocked.CompareExchange(ref inTick, 1, 0) == 0)
if (Interlocked.CompareExchange(ref _inTick, 1, 0) == 0)
{
try
{
if (_items.Any(item => item.NeedsUpdate))
if (_items.Any(item => item.NeedsUpdate) &&
Interlocked.CompareExchange(ref _inUpdate, 1, 0) == 0)
{
await _dispatcher.InvokeAsync(() =>
System.Diagnostics.Debug.WriteLine("Posted update");
_dispatcher.Post(() =>
{
foreach (var i in _items)
{
i.Update(time);
if (i.NeedsUpdate)
{
try
{
i.Update(time);
}
catch (Exception ex)
{
Logger.Error(LogArea.Visual, this, "Exception in render update: {Error}", ex);
}
}
}
}, DispatcherPriority.Render).ConfigureAwait(false);
Interlocked.Exchange(ref _inUpdate, 0);
}, DispatcherPriority.Render);
}
foreach (var i in _items)
@ -112,7 +127,7 @@ namespace Avalonia.Rendering
}
finally
{
Interlocked.Exchange(ref inTick, 0);
Interlocked.Exchange(ref _inTick, 0);
}
}
}

Loading…
Cancel
Save