From 9abf7dbb10e8c9e8e3b5aae9aabede489ef36bdf Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 19 Nov 2024 21:44:59 -0800 Subject: [PATCH 1/4] Check for HasRenderContextAffinity before calling CreateNonAffinedSnapshot --- .../Rendering/Composition/Server/ServerCompositor.UserApis.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs index 7d203a7c478..84a46d42c7a 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs @@ -73,7 +73,8 @@ public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visua visual.Render(ctx, null); } - if (target is IDrawingContextLayerWithRenderContextAffinityImpl affined) + if (target is IDrawingContextLayerWithRenderContextAffinityImpl affined + && affined.HasRenderContextAffinity) return affined.CreateNonAffinedSnapshot(); // We are returning the original target, so prevent it from being disposed From e251d6c45320c14f6376c005893846dee0031b5f Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 19 Nov 2024 21:46:29 -0800 Subject: [PATCH 2/4] Add ServerVisualRenderContext.RenderChildren context parameter --- src/Avalonia.Base/Rendering/Composition/Compositor.cs | 2 +- .../Composition/Server/ServerCompositionContainerVisual.cs | 7 +++++-- .../Composition/Server/ServerCompositionTarget.cs | 2 +- .../Composition/Server/ServerCompositor.UserApis.cs | 6 +++--- .../Composition/Server/ServerVisualRenderContext.cs | 6 ++++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Base/Rendering/Composition/Compositor.cs b/src/Avalonia.Base/Rendering/Composition/Compositor.cs index 8504201bd0f..4190991b259 100644 --- a/src/Avalonia.Base/Rendering/Composition/Compositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Compositor.cs @@ -294,7 +294,7 @@ public async Task CreateCompositionVisualSnapshot(CompositionVisual visu throw new InvalidOperationException(); if (visual.Root == null) throw new InvalidOperationException(); - var impl = await InvokeServerJobAsync(() => _server.CreateCompositionVisualSnapshot(visual.Server, scaling), true); + var impl = await InvokeServerJobAsync(() => _server.CreateCompositionVisualSnapshot(visual.Server, scaling, true), true); return new Bitmap(RefCountable.Create(impl)); } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs index 69d317fff15..4f300503b2f 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs @@ -20,9 +20,12 @@ protected override void RenderCore(ServerVisualRenderContext context, LtrbRect c { base.RenderCore(context, currentTransformedClip); - foreach (var ch in Children) + if (context.RenderChildren) { - ch.Render(context, currentTransformedClip); + foreach (var ch in Children) + { + ch.Render(context, currentTransformedClip); + } } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs index 8afdb6a2cc1..e5b5e0e6c26 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs @@ -215,7 +215,7 @@ void RenderRootToContextWithClip(IDrawingContextImpl context, ServerCompositionV using (var proxy = new CompositorDrawingContextProxy(context)) { - var ctx = new ServerVisualRenderContext(proxy, DirtyRects, false); + var ctx = new ServerVisualRenderContext(proxy, DirtyRects, false, true); root.Render(ctx, null); } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs index 84a46d42c7a..cb4da6723ff 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs @@ -49,7 +49,7 @@ public IReadOnlyDictionary RT_GetRenderInterfaceFeatures() } public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visual, - double scaling) + double scaling, bool renderChildren) { using (RenderInterface.EnsureCurrent()) { @@ -69,7 +69,7 @@ public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visua PostTransform = invertRootTransform * scaleTransform, Transform = Matrix.Identity }; - var ctx = new ServerVisualRenderContext(proxy, null, true); + var ctx = new ServerVisualRenderContext(proxy, null, true, renderChildren); visual.Render(ctx, null); } @@ -88,4 +88,4 @@ public IBitmapImpl CreateCompositionVisualSnapshot(ServerCompositionVisual visua } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs index 0778a7a6213..4ee22d3bff2 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerVisualRenderContext.cs @@ -8,15 +8,17 @@ internal class ServerVisualRenderContext { public IDirtyRectTracker? DirtyRects { get; } public bool DetachedRendering { get; } + public bool RenderChildren { get; } public CompositorDrawingContextProxy Canvas { get; } private readonly Stack? _transformStack; public ServerVisualRenderContext(CompositorDrawingContextProxy canvas, IDirtyRectTracker? dirtyRects, - bool detachedRendering) + bool detachedRendering, bool renderChildren) { Canvas = canvas; DirtyRects = dirtyRects; DetachedRendering = detachedRendering; + RenderChildren = renderChildren; if (detachedRendering) { _transformStack = new(); @@ -72,4 +74,4 @@ public void Dispose() } } -} \ No newline at end of file +} From 6318bfc6c0477dfe7707da0d68f3eefb0848fccc Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 19 Nov 2024 21:50:28 -0800 Subject: [PATCH 3/4] Add Should_Render_To_A_Compositor_Snapshot_Capture test --- .../RenderingTests.cs | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs index 119b17cf2f1..8fd1c24651c 100644 --- a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs +++ b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs @@ -1,8 +1,10 @@ using System.Collections.ObjectModel; +using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Layout; using Avalonia.Media; +using Avalonia.Rendering.Composition; using Avalonia.Threading; namespace Avalonia.Headless.UnitTests; @@ -37,7 +39,7 @@ public void Should_Render_Last_Frame_To_Bitmap() Assert.NotNull(frame); } - + #if NUNIT [AvaloniaTest, Timeout(10000)] #elif XUNIT @@ -136,4 +138,34 @@ public void Should_Not_Hang_With_Non_Trivial_Layout() var frame = window.CaptureRenderedFrame(); Assert.NotNull(frame); } + +#if NUNIT + [AvaloniaTest, Timeout(10000)] +#elif XUNIT + [AvaloniaFact(Timeout = 10000)] +#endif + public async Task Should_Render_To_A_Compositor_Snapshot_Capture() + { + var window = new Window + { + Content = new ContentControl + { + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Stretch, + Width = 100, + Height = 100, + Background = Brushes.Green + }, + SizeToContent = SizeToContent.WidthAndHeight + }; + + window.Show(); + + var compositionVisual = ElementComposition.GetElementVisual(window)!; + var snapshot = await compositionVisual.Compositor.CreateCompositionVisualSnapshot(compositionVisual, 1); + + Assert.NotNull(snapshot); + Assert.AreEqual(100, snapshot.Size.Width); + Assert.AreEqual(100, snapshot.Size.Height); + } } From bca4648453a485fa40862a6d8304f1fd5bbd304a Mon Sep 17 00:00:00 2001 From: Max Katz Date: Tue, 19 Nov 2024 22:08:04 -0800 Subject: [PATCH 4/4] Fix xunit tests --- tests/Avalonia.Headless.UnitTests/RenderingTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs index 8fd1c24651c..74afb158658 100644 --- a/tests/Avalonia.Headless.UnitTests/RenderingTests.cs +++ b/tests/Avalonia.Headless.UnitTests/RenderingTests.cs @@ -165,7 +165,9 @@ public async Task Should_Render_To_A_Compositor_Snapshot_Capture() var snapshot = await compositionVisual.Compositor.CreateCompositionVisualSnapshot(compositionVisual, 1); Assert.NotNull(snapshot); - Assert.AreEqual(100, snapshot.Size.Width); - Assert.AreEqual(100, snapshot.Size.Height); + // ReSharper disable CompareOfFloatsByEqualityOperator + Assert.True(100 == snapshot.Size.Width); + Assert.True(100 == snapshot.Size.Height); + // ReSharper restore CompareOfFloatsByEqualityOperator } }