From 77dc35bf469fbc583d9c09add0fa255e9badd1bc Mon Sep 17 00:00:00 2001 From: stepan_govorko Date: Thu, 17 Aug 2023 09:26:25 +0200 Subject: [PATCH] Introduced counting of rendered visuals in ServerCompositionVisual and added relevant unit tests in CompositorInvalidationClippingTests. The new tests ensure that visuals that are not in dirty rect are rendered correctly with different ClipToBounds and Clip geometry parameters. --- .../ICompositionTargetDebugEvents.cs | 2 + .../Server/ServerCompositionVisual.cs | 1 + .../CompositorInvalidationClippingTests.cs | 60 +++++++++++++++++++ .../CompositorTestServices.cs | 17 +++++- 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.Base.UnitTests/Rendering/CompositorInvalidationClippingTests.cs diff --git a/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs b/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs index c830ca2c49..cfbce221d6 100644 --- a/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs +++ b/src/Avalonia.Base/Rendering/Composition/ICompositionTargetDebugEvents.cs @@ -2,5 +2,7 @@ namespace Avalonia.Rendering.Composition; internal interface ICompositionTargetDebugEvents { + public int RenderedVisuals { get; } + void IncrementRenderedVisuals(); void RectInvalidated(Rect rc); } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs index fd1e2165b7..aeb228282e 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs @@ -38,6 +38,7 @@ namespace Avalonia.Rendering.Composition.Server return; Root!.RenderedVisuals++; + Root!.DebugEvents?.IncrementRenderedVisuals(); var boundsRect = new Rect(new Size(Size.X, Size.Y)); diff --git a/tests/Avalonia.Base.UnitTests/Rendering/CompositorInvalidationClippingTests.cs b/tests/Avalonia.Base.UnitTests/Rendering/CompositorInvalidationClippingTests.cs new file mode 100644 index 0000000000..1de2cfa717 --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/Rendering/CompositorInvalidationClippingTests.cs @@ -0,0 +1,60 @@ +using Avalonia.Controls; +using Avalonia.Media; +using Xunit; + +namespace Avalonia.Base.UnitTests.Rendering; + +public class CompositorInvalidationClippingTests : CompositorTestsBase +{ + [Fact] + public void Siblings_Should_Be_Rendered_On_Invalidate_Without_ClipToBounds() + { + AssertRenderedVisuals(clipToBounds: false, clipGeometry: false, expectedRenderedVisualsCount: 4); + } + + [Fact] + public void Siblings_Should_Not_Be_Rendered_On_Invalidate_With_ClipToBounds() + { + AssertRenderedVisuals(clipToBounds: true, clipGeometry: false, expectedRenderedVisualsCount: 3); + } + + [Fact] + public void Siblings_Should_Not_Be_Rendered_On_Invalidate_With_Clip() + { + AssertRenderedVisuals(clipToBounds: false, clipGeometry: true, expectedRenderedVisualsCount: 3); + } + + private void AssertRenderedVisuals(bool clipToBounds, bool clipGeometry, int expectedRenderedVisualsCount) + { + using (var s = new CompositorCanvas()) + { + //#1 visual to render is root + //#2 visual to render is s.Canvas + + //#3 visual to render + s.Canvas.Children.Add(new Border() + { + [Canvas.LeftProperty] = 0, [Canvas.TopProperty] = 0, + Width = 20, Height = 10, + Background = Brushes.Red, + ClipToBounds = clipToBounds, + Clip = clipGeometry ? new RectangleGeometry(new Rect(new Size(20, 10))) : null + }); + + //#4 visual to render + s.Canvas.Children.Add(new Border() + { + [Canvas.LeftProperty] = 30, [Canvas.TopProperty] = 50, + Width = 20, Height = 10, + Background = Brushes.Red, + ClipToBounds = clipToBounds, + Clip = clipGeometry ? new RectangleGeometry(new Rect(new Size(20, 10))) : null + }); + s.RunJobs(); + s.Events.Reset(); + s.Canvas.Children[0].IsVisible = false; + s.RunJobs(); + s.AssertRenderedVisuals(expectedRenderedVisualsCount); + } + } +} diff --git a/tests/Avalonia.UnitTests/CompositorTestServices.cs b/tests/Avalonia.UnitTests/CompositorTestServices.cs index 53fd610a17..00645259a5 100644 --- a/tests/Avalonia.UnitTests/CompositorTestServices.cs +++ b/tests/Avalonia.UnitTests/CompositorTestServices.cs @@ -89,6 +89,13 @@ public class CompositorTestServices : IDisposable Events.Rects.Clear(); } + public void AssertRenderedVisuals(int renderVisuals) + { + RunJobs(); + Assert.Equal(Events.RenderedVisuals, renderVisuals); + Events.Rects.Clear(); + } + public void AssertHitTest(double x, double y, Func filter, params object[] expected) => AssertHitTest(new Point(x, y), filter, expected); @@ -110,6 +117,13 @@ public class CompositorTestServices : IDisposable { public List Rects = new(); + public int RenderedVisuals { get; private set; } + + public void IncrementRenderedVisuals() + { + RenderedVisuals++; + } + public void RectInvalidated(Rect rc) { Rects.Add(rc); @@ -118,6 +132,7 @@ public class CompositorTestServices : IDisposable public void Reset() { Rects.Clear(); + RenderedVisuals = 0; } } @@ -218,4 +233,4 @@ public class DispatcherCompositorScheduler : ICompositorScheduler { Dispatcher.UIThread.Post(() => compositor.Commit(), DispatcherPriority.UiThreadRender); } -} \ No newline at end of file +}