Browse Source

Propagate exceptions from compositor to unit/render tests (#14808)

* Propagate exceptions from compositor to unit/render tests

* Updated non-conforming platform
pull/14838/head
Nikita Tsukanov 2 years ago
committed by GitHub
parent
commit
8ad0290374
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      src/Avalonia.Base/Media/MediaContext.Compositor.cs
  2. 5
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  3. 19
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
  4. 2
      src/Browser/Avalonia.Browser/AvaloniaView.cs
  5. 4
      tests/Avalonia.Base.UnitTests/Media/RenderResourceTestHelper.cs
  6. 2
      tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs
  7. 2
      tests/Avalonia.RenderTests/TestBase.cs

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

@ -91,7 +91,7 @@ partial class MediaContext
/// Executes a synchronous commit when we need to wait for composition jobs to be done
/// Is used in resize and TopLevel destruction scenarios
/// </summary>
private void SyncCommit(Compositor compositor, bool waitFullRender)
private void SyncCommit(Compositor compositor, bool waitFullRender, bool catchExceptions)
{
// Unit tests are assuming that they can call any API without setting up platforms
if (AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() == null)
@ -109,7 +109,7 @@ partial class MediaContext
else
{
CommitCompositor(compositor);
compositor.Server.Render();
compositor.Server.Render(catchExceptions);
}
}
@ -118,9 +118,9 @@ partial class MediaContext
/// </summary>
// TODO: do we need to execute a render pass here too?
// We've previously tried that and it made the resize experience worse
public void ImmediateRenderRequested(CompositionTarget target)
public void ImmediateRenderRequested(CompositionTarget target, bool catchExceptions)
{
SyncCommit(target.Compositor, true);
SyncCommit(target.Compositor, true, catchExceptions);
}
@ -133,7 +133,7 @@ partial class MediaContext
compositionTarget.Dispose();
// TODO: introduce a way to skip any actual rendering for other targets and only do a dispose?
SyncCommit(compositionTarget.Compositor, false);
SyncCommit(compositionTarget.Compositor, false, true);
}
/// <summary>

5
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -211,14 +211,15 @@ internal class CompositingRenderer : IRendererWithCompositor, IHitTester
}
/// <inheritdoc />
public void Paint(Rect rect)
public void Paint(Rect rect) => Paint(rect, true);
public void Paint(Rect rect, bool catchExceptions)
{
if (_isDisposed)
return;
QueueUpdate();
CompositionTarget.RequestRedraw();
MediaContext.Instance.ImmediateRenderRequested(CompositionTarget);
MediaContext.Instance.ImmediateRenderRequested(CompositionTarget, catchExceptions);
}
/// <inheritdoc />

19
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs

@ -157,7 +157,8 @@ namespace Avalonia.Rendering.Composition.Server
_reusableToNotifyRenderedList.Clear();
}
public void Render()
public void Render() => Render(true);
public void Render(bool catchExceptions)
{
if (Dispatcher.UIThread.CheckAccess())
{
@ -167,7 +168,7 @@ namespace Avalonia.Rendering.Composition.Server
try
{
using (Dispatcher.UIThread.DisableProcessing())
RenderReentrancySafe();
RenderReentrancySafe(catchExceptions);
}
finally
{
@ -175,10 +176,10 @@ namespace Avalonia.Rendering.Composition.Server
}
}
else
RenderReentrancySafe();
RenderReentrancySafe(catchExceptions);
}
private void RenderReentrancySafe()
private void RenderReentrancySafe(bool catchExceptions)
{
lock (_lock)
{
@ -187,11 +188,7 @@ namespace Avalonia.Rendering.Composition.Server
try
{
_safeThread = Thread.CurrentThread;
RenderCore();
}
catch (Exception e) when (RT_OnContextLostExceptionFilterObserver(e) && false)
// Will never get here, only using exception filter side effect
{
RenderCore(catchExceptions);
}
finally
{
@ -205,7 +202,7 @@ namespace Avalonia.Rendering.Composition.Server
}
}
private void RenderCore()
private void RenderCore(bool catchExceptions)
{
UpdateServerTime();
ApplyPendingBatches();
@ -228,7 +225,7 @@ namespace Avalonia.Rendering.Composition.Server
foreach (var t in _activeTargets)
t.Render();
}
catch (Exception e)
catch (Exception e) when(RT_OnContextLostExceptionFilterObserver(e) && catchExceptions)
{
Logger.TryGet(LogEventLevel.Error, LogArea.Visual)?.Log(this, "Exception when rendering: {Error}", e);
}

2
src/Browser/Avalonia.Browser/AvaloniaView.cs

@ -454,7 +454,7 @@ namespace Avalonia.Browser
if (_topLevel.Renderer is CompositingRenderer dr)
{
MediaContext.Instance.ImmediateRenderRequested(dr.CompositionTarget);
MediaContext.Instance.ImmediateRenderRequested(dr.CompositionTarget, true);
}
}

4
tests/Avalonia.Base.UnitTests/Media/RenderResourceTestHelper.cs

@ -42,7 +42,7 @@ internal class RenderResourceTestHelper : IDisposable
Assert.True(Compositor.UnitTestIsRegisteredForSerialization(resource));
Compositor.Commit();
Compositor.Server.Render();
Compositor.Server.Render(false);
Assert.False(Compositor.UnitTestIsRegisteredForSerialization(resource));
cb();
@ -52,4 +52,4 @@ internal class RenderResourceTestHelper : IDisposable
}
public void Dispose() => Services.Dispose();
}
}

2
tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs

@ -31,7 +31,7 @@ namespace Avalonia.Base.UnitTests.Rendering.SceneGraph
public void ForceRender()
{
_compositor.Commit();
_compositor.Server.Render();
_compositor.Server.Render(false);
}
public Rect? GetBounds()

2
tests/Avalonia.RenderTests/TestBase.cs

@ -120,7 +120,7 @@ namespace Avalonia.Direct2D1.RenderTests
root.Initialize(renderer, target);
renderer.Start();
Dispatcher.UIThread.RunJobs();
timer.TriggerTick();
renderer.Paint(new Rect(root.Bounds.Size), false);
}
writableBitmap.Save(compositedPath);
}

Loading…
Cancel
Save