Explorar o código

Run deferred render tests on a background thread.

Run deferred render tests on a background thread to expose any threading
errors in the deferred rendering path. And threading errors found. Also
had to decrease the timeout for D2D render tests as
`renderTarget.EndDraw` is hanging when an exception is thrown between
`renderTarget.BeginDraw` and `EndDraw`.
Steven Kirk %!s(int64=8) %!d(string=hai) anos
pai
achega
b3f9a8464e

+ 4 - 0
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@@ -124,6 +124,10 @@ namespace Avalonia.Rendering
             }
             }
         }
         }
 
 
+        internal void UnitTestUpdateScene() => UpdateScene();
+
+        internal void UnitTestRender() => Render(_scene);
+
         private void Render(Scene scene)
         private void Render(Scene scene)
         {
         {
             _rendering = true;
             _rendering = true;

+ 5 - 0
src/Shared/SharedAssemblyInfo.cs

@@ -3,6 +3,7 @@
 
 
 using System.Reflection;
 using System.Reflection;
 using System.Resources;
 using System.Resources;
+using System.Runtime.CompilerServices;
 
 
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyCompany("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyConfiguration("")]
@@ -16,3 +17,7 @@ using System.Resources;
 [assembly: AssemblyVersion("0.4.1")]
 [assembly: AssemblyVersion("0.4.1")]
 [assembly: AssemblyFileVersion("0.4.1")]
 [assembly: AssemblyFileVersion("0.4.1")]
 [assembly: AssemblyInformationalVersion("0.4.1")]
 [assembly: AssemblyInformationalVersion("0.4.1")]
+
+[assembly: InternalsVisibleTo("Avalonia.Cairo.RenderTests")]
+[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests")]
+[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests")]

+ 83 - 0
tests/Avalonia.RenderTests/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject

@@ -0,0 +1,83 @@
+<ProjectConfiguration>
+  <Settings>
+    <DefaultTestTimeout>1000</DefaultTestTimeout>
+    <IgnoredTests>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipX_TopLeftDest</TestName>
+      </NamedTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Media.LinearGradientBrushTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Media.VisualBrushTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Controls.BorderTests</FixtureName>
+      </FixtureTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipXY_TopLeftDest</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_FlipY_TopLeftDest</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_BottomRight</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_Center</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_Alignment_TopLeft</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterDest</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_Uniform_NoTile</TestName>
+      </NamedTestSelector>
+      <NamedTestSelector>
+        <TestName>Avalonia.Direct2D1.RenderTests.Media.ImageBrushTests.ImageBrush_UniformToFill_NoTile</TestName>
+      </NamedTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Controls.ImageTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.GeometryClippingTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Media.FormattedTextImplTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.OpacityMaskTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.EllipseTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.LineTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.PathTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.PolygonTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.PolylineTests</FixtureName>
+      </FixtureTestSelector>
+      <FixtureTestSelector>
+        <FixtureName>Avalonia.Direct2D1.RenderTests.Shapes.RectangleTests</FixtureName>
+      </FixtureTestSelector>
+    </IgnoredTests>
+    <PreviouslyBuiltSuccessfully>True</PreviouslyBuiltSuccessfully>
+  </Settings>
+</ProjectConfiguration>

+ 31 - 30
tests/Avalonia.RenderTests/Controls/BorderTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Layout;
 using Avalonia.Layout;
 using Avalonia.Media;
 using Avalonia.Media;
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_1px_Border()
+        public async Task Border_1px_Border()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -36,12 +37,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_2px_Border()
+        public async Task Border_2px_Border()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -55,12 +56,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_Fill()
+        public async Task Border_Fill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -73,12 +74,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_Brush_Offsets_Content()
+        public async Task Border_Brush_Offsets_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -96,12 +97,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_Padding_Offsets_Content()
+        public async Task Border_Padding_Offsets_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -120,12 +121,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_Margin_Offsets_Content()
+        public async Task Border_Margin_Offsets_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -144,7 +145,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -153,7 +154,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Centers_Content_Horizontally()
+        public async Task Border_Centers_Content_Horizontally()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -175,7 +176,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -186,7 +187,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Centers_Content_Vertically()
+        public async Task Border_Centers_Content_Vertically()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -208,7 +209,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -217,7 +218,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Stretches_Content_Horizontally()
+        public async Task Border_Stretches_Content_Horizontally()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -239,7 +240,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -248,7 +249,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Stretches_Content_Vertically()
+        public async Task Border_Stretches_Content_Vertically()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -270,7 +271,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -279,7 +280,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Left_Aligns_Content()
+        public async Task Border_Left_Aligns_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -301,7 +302,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -310,7 +311,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Right_Aligns_Content()
+        public async Task Border_Right_Aligns_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -332,7 +333,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -343,7 +344,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Top_Aligns_Content()
+        public async Task Border_Top_Aligns_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -365,7 +366,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -376,7 +377,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Border_Bottom_Aligns_Content()
+        public async Task Border_Bottom_Aligns_Content()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -398,12 +399,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Border_Nested_Rotate()
+        public async Task Border_Nested_Rotate()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -426,7 +427,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 9 - 8
tests/Avalonia.RenderTests/Controls/ImageTests.cs

@@ -2,6 +2,7 @@
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
 using System.IO;
 using System.IO;
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Media.Imaging;
 using Avalonia.Media.Imaging;
@@ -26,7 +27,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Image_Stretch_None()
+        public async Task Image_Stretch_None()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -44,12 +45,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Image_Stretch_Fill()
+        public async Task Image_Stretch_Fill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -67,12 +68,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Image_Stretch_Uniform()
+        public async Task Image_Stretch_Uniform()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -90,12 +91,12 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Image_Stretch_UniformToFill()
+        public async Task Image_Stretch_UniformToFill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -113,7 +114,7 @@ namespace Avalonia.Direct2D1.RenderTests.Controls
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 3 - 2
tests/Avalonia.RenderTests/GeometryClippingTests.cs

@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 using Xunit;
 using Xunit;
+using System.Threading.Tasks;
 
 
 #if AVALONIA_CAIRO
 #if AVALONIA_CAIRO
 namespace Avalonia.Cairo.RenderTests
 namespace Avalonia.Cairo.RenderTests
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.RenderTests
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Geometry_Clip_Clips_Path()
+        public async Task Geometry_Clip_Clips_Path()
         {
         {
             var target = new Canvas
             var target = new Canvas
             {
             {
@@ -44,7 +45,7 @@ namespace Avalonia.Direct2D1.RenderTests
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 27 - 26
tests/Avalonia.RenderTests/Media/ImageBrushTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Layout;
 using Avalonia.Layout;
@@ -29,7 +30,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_NoTile_Alignment_TopLeft()
+        public async Task ImageBrush_NoStretch_NoTile_Alignment_TopLeft()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -49,12 +50,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_NoTile_Alignment_Center()
+        public async Task ImageBrush_NoStretch_NoTile_Alignment_Center()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -74,12 +75,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_NoTile_Alignment_BottomRight()
+        public async Task ImageBrush_NoStretch_NoTile_Alignment_BottomRight()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -99,7 +100,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 #if AVALONIA_SKIA_SKIP_FAIL
 #if AVALONIA_SKIA_SKIP_FAIL
@@ -107,7 +108,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_Fill_NoTile()
+        public async Task ImageBrush_Fill_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -125,7 +126,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -134,7 +135,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_Uniform_NoTile()
+        public async Task ImageBrush_Uniform_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -152,7 +153,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -161,7 +162,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_UniformToFill_NoTile()
+        public async Task ImageBrush_UniformToFill_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -179,12 +180,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_NoTile_BottomRightQuarterSource()
+        public async Task ImageBrush_NoStretch_NoTile_BottomRightQuarterSource()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -203,7 +204,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -212,7 +213,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_NoStretch_NoTile_BottomRightQuarterDest()
+        public async Task ImageBrush_NoStretch_NoTile_BottomRightQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -231,7 +232,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -240,7 +241,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest()
+        public async Task ImageBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -260,12 +261,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest()
+        public async Task ImageBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -285,7 +286,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -294,7 +295,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_NoStretch_FlipX_TopLeftDest()
+        public async Task ImageBrush_NoStretch_FlipX_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -313,7 +314,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -322,7 +323,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void ImageBrush_NoStretch_FlipY_TopLeftDest()
+        public async Task ImageBrush_NoStretch_FlipY_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -341,12 +342,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void ImageBrush_NoStretch_FlipXY_TopLeftDest()
+        public async Task ImageBrush_NoStretch_FlipXY_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -365,7 +366,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 4 - 4
tests/Avalonia.RenderTests/Media/LinearGradientBrushTests.cs

@@ -29,7 +29,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void LinearGradientBrush_RedBlue_Horizontal_Fill()
+        public async Task LinearGradientBrush_RedBlue_Horizontal_Fill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -51,7 +51,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -60,7 +60,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void LinearGradientBrush_RedBlue_Vertical_Fill()
+        public async Task LinearGradientBrush_RedBlue_Vertical_Fill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -82,7 +82,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 31 - 30
tests/Avalonia.RenderTests/Media/VisualBrushTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Layout;
 using Avalonia.Layout;
@@ -61,7 +62,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
         }
         }
 
 
         [Fact]
         [Fact]
-        public void VisualBrush_NoStretch_NoTile_Alignment_TopLeft()
+        public async Task VisualBrush_NoStretch_NoTile_Alignment_TopLeft()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -81,7 +82,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -92,7 +93,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_NoTile_Alignment_Center()
+        public async Task VisualBrush_NoStretch_NoTile_Alignment_Center()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -112,12 +113,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void VisualBrush_NoStretch_NoTile_Alignment_BottomRight()
+        public async Task VisualBrush_NoStretch_NoTile_Alignment_BottomRight()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -137,7 +138,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -148,7 +149,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_Fill_NoTile()
+        public async Task VisualBrush_Fill_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -166,7 +167,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -177,7 +178,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_Uniform_NoTile()
+        public async Task VisualBrush_Uniform_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -195,7 +196,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -206,7 +207,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_UniformToFill_NoTile()
+        public async Task VisualBrush_UniformToFill_NoTile()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -224,12 +225,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void VisualBrush_NoStretch_NoTile_BottomRightQuarterSource()
+        public async Task VisualBrush_NoStretch_NoTile_BottomRightQuarterSource()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -248,7 +249,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -259,7 +260,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_NoTile_BottomRightQuarterDest()
+        public async Task VisualBrush_NoStretch_NoTile_BottomRightQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -278,7 +279,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -287,7 +288,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest()
+        public async Task VisualBrush_NoStretch_NoTile_BottomRightQuarterSource_BottomRightQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -307,12 +308,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void VisualBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest()
+        public async Task VisualBrush_NoStretch_Tile_BottomRightQuarterSource_CenterQuarterDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -332,7 +333,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -343,7 +344,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_FlipX_TopLeftDest()
+        public async Task VisualBrush_NoStretch_FlipX_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -362,7 +363,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -373,7 +374,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_FlipY_TopLeftDest()
+        public async Task VisualBrush_NoStretch_FlipY_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -392,7 +393,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -403,7 +404,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VisualBrush_NoStretch_FlipXY_TopLeftDest()
+        public async Task VisualBrush_NoStretch_FlipXY_TopLeftDest()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -422,12 +423,12 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void VisualBrush_InTree_Visual()
+        public async Task VisualBrush_InTree_Visual()
         {
         {
             Border source;
             Border source;
             Decorator target = new Decorator
             Decorator target = new Decorator
@@ -449,9 +450,9 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                                 Text = "Visual"
                                 Text = "Visual"
                             }
                             }
                         }),
                         }),
-                        new Rectangle
+                        new Border
                         {
                         {
-                            Fill = new VisualBrush
+                            Background = new VisualBrush
                             {
                             {
                                 Stretch = Stretch.Uniform,
                                 Stretch = Stretch.Uniform,
                                 Visual = source,
                                 Visual = source,
@@ -462,7 +463,7 @@ namespace Avalonia.Direct2D1.RenderTests.Media
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 3 - 2
tests/Avalonia.RenderTests/OpacityMaskTests.cs

@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 using Xunit;
 using Xunit;
+using System.Threading.Tasks;
 
 
 #if AVALONIA_CAIRO
 #if AVALONIA_CAIRO
 namespace Avalonia.Cairo.RenderTests
 namespace Avalonia.Cairo.RenderTests
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.RenderTests
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Opacity_Mask_Masks_Element()
+        public async Task Opacity_Mask_Masks_Element()
         {
         {
             var target = new Canvas
             var target = new Canvas
             {
             {
@@ -53,7 +54,7 @@ namespace Avalonia.Direct2D1.RenderTests
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 7 - 6
tests/Avalonia.RenderTests/Shapes/LineTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Media;
 using Avalonia.Media;
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Line_1px_Stroke()
+        public async Task Line_1px_Stroke()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -37,12 +38,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Line_1px_Stroke_Reversed()
+        public async Task Line_1px_Stroke_Reversed()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -57,12 +58,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Line_1px_Stroke_Vertical()
+        public async Task Line_1px_Stroke_Vertical()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -77,7 +78,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 31 - 30
tests/Avalonia.RenderTests/Shapes/PathTests.cs

@@ -15,6 +15,7 @@ namespace Avalonia.Skia.RenderTests
 namespace Avalonia.Direct2D1.RenderTests.Shapes
 namespace Avalonia.Direct2D1.RenderTests.Shapes
 #endif
 #endif
 {
 {
+    using System.Threading.Tasks;
     using Avalonia.Collections;
     using Avalonia.Collections;
 
 
     public class PathTests : TestBase
     public class PathTests : TestBase
@@ -29,7 +30,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Line_Absolute()
+        public async Task Line_Absolute()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -45,7 +46,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -54,7 +55,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Line_Relative()
+        public async Task Line_Relative()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -70,7 +71,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -79,7 +80,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void HorizontalLine_Absolute()
+        public async Task HorizontalLine_Absolute()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -95,7 +96,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -104,7 +105,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void HorizontalLine_Relative()
+        public async Task HorizontalLine_Relative()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -120,7 +121,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -129,7 +130,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VerticalLine_Absolute()
+        public async Task VerticalLine_Absolute()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -145,7 +146,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -154,7 +155,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void VerticalLine_Relative()
+        public async Task VerticalLine_Relative()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -170,7 +171,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -179,7 +180,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void CubicBezier_Absolute()
+        public async Task CubicBezier_Absolute()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -196,7 +197,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -205,7 +206,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void CubicBezier_Relative()
+        public async Task CubicBezier_Relative()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -222,7 +223,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -231,7 +232,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Arc_Absolute()
+        public async Task Arc_Absolute()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -248,7 +249,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -257,7 +258,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Arc_Relative()
+        public async Task Arc_Relative()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -274,12 +275,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Path_100px_Triangle_Centered()
+        public async Task Path_100px_Triangle_Centered()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -296,7 +297,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 #if AVALONIA_SKIA_SKIP_FAIL
 #if AVALONIA_SKIA_SKIP_FAIL
@@ -304,7 +305,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Path_Tick_Scaled()
+        public async Task Path_Tick_Scaled()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -322,7 +323,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -331,7 +332,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Path_Tick_Scaled_Stroke_8px()
+        public async Task Path_Tick_Scaled_Stroke_8px()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -349,12 +350,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Path_Expander_With_Border()
+        public async Task Path_Expander_With_Border()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -377,7 +378,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -388,7 +389,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Path_With_PenLineCap()
+        public async Task Path_With_PenLineCap()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -408,7 +409,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 5 - 4
tests/Avalonia.RenderTests/Shapes/PolygonTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Media;
 using Avalonia.Media;
@@ -28,7 +29,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Polygon_1px_Stroke()
+        public async Task Polygon_1px_Stroke()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -45,7 +46,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -56,7 +57,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Polygon_NonUniformFill()
+        public async Task Polygon_NonUniformFill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -73,7 +74,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 5 - 4
tests/Avalonia.RenderTests/Shapes/PolylineTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Media;
 using Avalonia.Media;
@@ -28,7 +29,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Polyline_1px_Stroke()
+        public async Task Polyline_1px_Stroke()
         {
         {
             var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
             var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
                 new Point(9, 1), new Point(10, 0), new Point(15, 0) };
                 new Point(9, 1), new Point(10, 0), new Point(15, 0) };
@@ -47,7 +48,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
@@ -58,7 +59,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
 #else
 #else
         [Fact]
         [Fact]
 #endif
 #endif
-        public void Polyline_10px_Stroke_PenLineJoin()
+        public async Task Polyline_10px_Stroke_PenLineJoin()
         {
         {
             var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
             var polylinePoints = new Point[] { new Point(0, 0), new Point(5, 0), new Point(6, -2), new Point(7, 3), new Point(8, -3),
                 new Point(9, 1), new Point(10, 0), new Point(15, 0) };
                 new Point(9, 1), new Point(10, 0), new Point(15, 0) };
@@ -80,7 +81,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 9 - 8
tests/Avalonia.RenderTests/Shapes/RectangleTests.cs

@@ -1,6 +1,7 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
 
+using System.Threading.Tasks;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
 using Avalonia.Controls.Shapes;
 using Avalonia.Media;
 using Avalonia.Media;
@@ -22,7 +23,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Rectangle_1px_Stroke()
+        public async Task Rectangle_1px_Stroke()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -36,12 +37,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Rectangle_2px_Stroke()
+        public async Task Rectangle_2px_Stroke()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -55,12 +56,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Rectangle_Stroke_Fill()
+        public async Task Rectangle_Stroke_Fill()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -75,12 +76,12 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
 
 
         [Fact]
         [Fact]
-        public void Rectangle_Stroke_Fill_ClipToBounds()
+        public async Task Rectangle_Stroke_Fill_ClipToBounds()
         {
         {
             Decorator target = new Decorator
             Decorator target = new Decorator
             {
             {
@@ -96,7 +97,7 @@ namespace Avalonia.Direct2D1.RenderTests.Shapes
                 }
                 }
             };
             };
 
 
-            RenderToFile(target);
+            await RenderToFile(target);
             CompareImages();
             CompareImages();
         }
         }
     }
     }

+ 43 - 2
tests/Avalonia.RenderTests/TestBase.cs

@@ -10,6 +10,9 @@ using Avalonia.Rendering;
 
 
 using Xunit;
 using Xunit;
 using Avalonia.Platform;
 using Avalonia.Platform;
+using System.Threading.Tasks;
+using System;
+using System.Threading;
 
 
 #if AVALONIA_CAIRO
 #if AVALONIA_CAIRO
 using Avalonia.Cairo;
 using Avalonia.Cairo;
@@ -29,6 +32,9 @@ namespace Avalonia.Direct2D1.RenderTests
 {
 {
     public class TestBase
     public class TestBase
     {
     {
+        private static readonly TestThreadingInterface threadingInterface =
+            new TestThreadingInterface();
+
         static TestBase()
         static TestBase()
         {
         {
 #if AVALONIA_CAIRO
 #if AVALONIA_CAIRO
@@ -38,6 +44,10 @@ namespace Avalonia.Direct2D1.RenderTests
 #else
 #else
             Direct2D1Platform.Initialize();
             Direct2D1Platform.Initialize();
 #endif
 #endif
+            AvaloniaLocator.CurrentMutable
+                .Bind<IPlatformThreadingInterface>()
+                .ToConstant(threadingInterface);
+
         }
         }
 
 
         public TestBase(string outputPath)
         public TestBase(string outputPath)
@@ -50,6 +60,8 @@ namespace Avalonia.Direct2D1.RenderTests
             string testFiles = Path.GetFullPath(@"..\..\tests\TestFiles\Direct2D1");
             string testFiles = Path.GetFullPath(@"..\..\tests\TestFiles\Direct2D1");
 #endif
 #endif
             OutputPath = Path.Combine(testFiles, outputPath);
             OutputPath = Path.Combine(testFiles, outputPath);
+
+            threadingInterface.MainThread = Thread.CurrentThread;
         }
         }
 
 
         public string OutputPath
         public string OutputPath
@@ -57,7 +69,7 @@ namespace Avalonia.Direct2D1.RenderTests
             get;
             get;
         }
         }
 
 
-        protected void RenderToFile(Control target, [CallerMemberName] string testName = "")
+        protected async Task RenderToFile(Control target, [CallerMemberName] string testName = "")
         {
         {
             if (!Directory.Exists(OutputPath))
             if (!Directory.Exists(OutputPath))
             {
             {
@@ -85,7 +97,12 @@ namespace Avalonia.Direct2D1.RenderTests
                 Size size = new Size(target.Width, target.Height);
                 Size size = new Size(target.Width, target.Height);
                 target.Measure(size);
                 target.Measure(size);
                 target.Arrange(new Rect(size));
                 target.Arrange(new Rect(size));
-                renderer.Render(target.Bounds);
+                renderer.UnitTestUpdateScene();
+
+                // Do the deferred render on a background thread to expose any threading errors in
+                // the deferred rendering path.
+                await Task.Run((Action)renderer.UnitTestRender);
+
                 rtb.Save(deferredPath);
                 rtb.Save(deferredPath);
             }
             }
         }
         }
@@ -114,5 +131,29 @@ namespace Avalonia.Direct2D1.RenderTests
                 }
                 }
             }
             }
         }
         }
+
+        private class TestThreadingInterface : IPlatformThreadingInterface
+        {
+            public bool CurrentThreadIsLoopThread => MainThread.ManagedThreadId == Thread.CurrentThread.ManagedThreadId;
+
+            public Thread MainThread { get; set; }
+
+            public event Action Signaled;
+
+            public void RunLoop(CancellationToken cancellationToken)
+            {
+                throw new NotImplementedException();
+            }
+
+            public void Signal()
+            {
+                throw new NotImplementedException();
+            }
+
+            public IDisposable StartTimer(TimeSpan interval, Action tick)
+            {
+                throw new NotImplementedException();
+            }
+        }
     }
     }
 }
 }