diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 344f3f8f2b..fd6b149837 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -28,7 +28,7 @@ namespace Avalonia.Rendering private readonly ISceneBuilder _sceneBuilder; private bool _running; - private Scene _scene; + private volatile IRef _scene; private DirtyVisuals _dirty; private IRef _overlay; private bool _updateQueued; @@ -128,7 +128,7 @@ namespace Avalonia.Rendering UpdateScene(); } - return _scene?.HitTest(p, root, filter) ?? Enumerable.Empty(); + return _scene?.Item.HitTest(p, root, filter) ?? Enumerable.Empty(); } /// @@ -180,7 +180,7 @@ namespace Avalonia.Rendering internal void UnitTestUpdateScene() => UpdateScene(); - internal void UnitTestRender() => Render(_scene); + internal void UnitTestRender() => Render(_scene.Item); private void Render(Scene scene) { @@ -381,7 +381,8 @@ namespace Avalonia.Rendering { if (_root.IsVisible) { - var scene = _scene?.Clone() ?? new Scene(_root); + var sceneRef = RefCountable.Create(_scene?.Item.CloneScene() ?? new Scene(_root)); + var scene = sceneRef.Item; if (_dirty == null) { @@ -396,7 +397,7 @@ namespace Avalonia.Rendering } } - var oldScene = Interlocked.Exchange(ref _scene, scene); + var oldScene = Interlocked.Exchange(ref _scene, sceneRef); oldScene?.Dispose(); _dirty.Clear(); @@ -425,10 +426,11 @@ namespace Avalonia.Rendering _updateQueued = true; _dispatcher.Post(UpdateScene, DispatcherPriority.Render); } - - Scene scene = null; - Interlocked.Exchange(ref scene, _scene); - Render(scene); + + using (var scene = _scene?.Clone()) + { + Render(scene?.Item); + } } catch { } finally diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs index f2e4f5fdbd..352d41d024 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/Scene.cs @@ -82,7 +82,7 @@ namespace Avalonia.Rendering.SceneGraph /// Clones the scene. /// /// The cloned scene. - public Scene Clone() + public Scene CloneScene() { var index = new Dictionary(); var root = Clone((VisualNode)Root, null, index); diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs index f44be3f82e..dda1d73649 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests.cs @@ -99,7 +99,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph Assert.Equal(new Rect(10, 20, 160, 240), canvasNode.ClipBounds); // Initial ClipBounds are correct, make sure they're still correct after updating canvas. - result = result.Clone(); + result = result.CloneScene(); Assert.True(sceneBuilder.Update(result, canvas)); canvasNode = result.FindNode(canvas); @@ -197,7 +197,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph canvas.Arrange(new Rect(tree.DesiredSize)); // Initial ClipBounds are correct, make sure they're still correct after updating canvas. - scene = scene.Clone(); + scene = scene.CloneScene(); Assert.True(sceneBuilder.Update(scene, canvas)); borderNode = scene.FindNode(border); @@ -309,7 +309,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph var borderNode = scene.FindNode(border); Assert.Equal(expectedTransform, borderNode.Transform); - scene = scene.Clone(); + scene = scene.CloneScene(); Assert.True(sceneBuilder.Update(scene, border)); borderNode = scene.FindNode(border); @@ -354,7 +354,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph border.Background = Brushes.Green; - var result = initial.Clone(); + var result = initial.CloneScene(); sceneBuilder.Update(result, border); var borderNode = (VisualNode)result.Root.Children[0]; @@ -402,7 +402,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph sceneBuilder.UpdateAll(initial); border.Child = decorator; - var result = initial.Clone(); + var result = initial.CloneScene(); Assert.True(sceneBuilder.Update(result, decorator)); @@ -457,7 +457,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph sceneBuilder.UpdateAll(initial); border.Child = null; - var result = initial.Clone(); + var result = initial.CloneScene(); Assert.True(sceneBuilder.Update(result, decorator)); Assert.False(sceneBuilder.Update(result, canvas)); @@ -501,7 +501,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph sceneBuilder.UpdateAll(initial); border.IsVisible = false; - var result = initial.Clone(); + var result = initial.CloneScene(); Assert.True(sceneBuilder.Update(result, border)); Assert.False(sceneBuilder.Update(result, canvas)); @@ -552,7 +552,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph decorator.Margin = new Thickness(0, 20, 0, 0); layout.ExecuteLayoutPass(); - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, decorator); borderNode = scene.FindNode(border); @@ -600,7 +600,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph decorator.Margin = new Thickness(0, 20, 0, 0); layout.ExecuteLayoutPass(); - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, decorator); @@ -640,7 +640,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph Assert.Equal(new Size(100, 100), scene.Size); tree.ClientSize = new Size(110, 120); - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, tree); Assert.Equal(new Size(110, 120), scene.Size); @@ -735,7 +735,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph tree.Child = new Decorator(); - using (var result = scene.Clone()) + using (var result = scene.CloneScene()) { sceneBuilder.Update(result, img); scene.Dispose(); diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs index f2d137249a..ac00b8ccfc 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs @@ -62,7 +62,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph Assert.Empty(scene.Layers.Select(x => x.LayerRoot).Except(new IVisual[] { tree, border })); animation.OnCompleted(); - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, border); @@ -160,7 +160,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph Assert.Equal(3, scene.Layers.Count); decorator.Child = null; - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, border); @@ -210,7 +210,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph Assert.Equal(3, scene.Layers.Count); border.IsVisible = false; - scene = scene.Clone(); + scene = scene.CloneScene(); sceneBuilder.Update(scene, border); diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneTests.cs index 9c0adc432d..bba0c8b8f3 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneTests.cs @@ -25,7 +25,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph scene.Layers[tree].Dirty.Add(new Rect(0, 0, 100, 100)); scene.Layers[decorator].Dirty.Add(new Rect(0, 0, 50, 100)); - scene = scene.Clone(); + scene = scene.CloneScene(); Assert.Equal(2, scene.Layers.Count()); Assert.Empty(scene.Layers[0].Dirty); Assert.Empty(scene.Layers[1].Dirty);