From 8ad0290374f244ef9a39ba02c60eb9d3bf4abb42 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 5 Mar 2024 12:55:17 +0600 Subject: [PATCH] Propagate exceptions from compositor to unit/render tests (#14808) * Propagate exceptions from compositor to unit/render tests * Updated non-conforming platform --- .../Media/MediaContext.Compositor.cs | 10 +++++----- .../Composition/CompositingRenderer.cs | 5 +++-- .../Composition/Server/ServerCompositor.cs | 19 ++++++++----------- src/Browser/Avalonia.Browser/AvaloniaView.cs | 2 +- .../Media/RenderResourceTestHelper.cs | 4 ++-- .../SceneGraph/DrawOperationTests.cs | 2 +- tests/Avalonia.RenderTests/TestBase.cs | 2 +- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/Avalonia.Base/Media/MediaContext.Compositor.cs b/src/Avalonia.Base/Media/MediaContext.Compositor.cs index 41585ddc51..0d6aec9ae2 100644 --- a/src/Avalonia.Base/Media/MediaContext.Compositor.cs +++ b/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 /// - 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() == 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 /// // 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); } /// diff --git a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs index 52892b379b..eef5188564 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs @@ -211,14 +211,15 @@ internal class CompositingRenderer : IRendererWithCompositor, IHitTester } /// - 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); } /// diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs index c1f286e827..cd4ef0317e 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs +++ b/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); } diff --git a/src/Browser/Avalonia.Browser/AvaloniaView.cs b/src/Browser/Avalonia.Browser/AvaloniaView.cs index 6b32abe74f..5129f3095c 100644 --- a/src/Browser/Avalonia.Browser/AvaloniaView.cs +++ b/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); } } diff --git a/tests/Avalonia.Base.UnitTests/Media/RenderResourceTestHelper.cs b/tests/Avalonia.Base.UnitTests/Media/RenderResourceTestHelper.cs index ffb07da2f5..c283982e5e 100644 --- a/tests/Avalonia.Base.UnitTests/Media/RenderResourceTestHelper.cs +++ b/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(); -} \ No newline at end of file +} diff --git a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs index d0eb34b509..1d55534fca 100644 --- a/tests/Avalonia.Base.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/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() diff --git a/tests/Avalonia.RenderTests/TestBase.cs b/tests/Avalonia.RenderTests/TestBase.cs index ad84b897fb..06653ff33c 100644 --- a/tests/Avalonia.RenderTests/TestBase.cs +++ b/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); }