From 7de42e02e1c5d6af042c3b4b97e842e4f9cec159 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 19 Aug 2017 17:11:07 +0200 Subject: [PATCH] Clear scene for invisible root visuals. When a root visual is hidden, clear `DeferredRenderer._scene` and completely rebuild it if it is shown again. Fixes #1096 --- .../Rendering/DeferredRenderer.cs | 42 +++++++++++-------- .../Rendering/SceneGraph/SceneBuilder.cs | 6 +++ .../SceneGraph/SceneBuilderTests_Layers.cs | 27 ------------ 3 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index d3d6776efa3..c30fb3bdc3f 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -11,6 +11,7 @@ using System.IO; using Avalonia.Media.Immutable; using System.Threading; +using System.Linq; namespace Avalonia.Rendering { @@ -58,7 +59,6 @@ public DeferredRenderer( _dispatcher = dispatcher ?? Dispatcher.UIThread; _root = root; _sceneBuilder = sceneBuilder ?? new SceneBuilder(); - _scene = new Scene(root); _layerFactory = layerFactory ?? new DefaultRenderLayerFactory(); _layers = new RenderLayers(_layerFactory); _renderLoop = renderLoop; @@ -86,7 +86,6 @@ public DeferredRenderer( _root = root; _renderTarget = renderTarget; _sceneBuilder = sceneBuilder ?? new SceneBuilder(); - _scene = new Scene(root); _layerFactory = layerFactory ?? new DefaultRenderLayerFactory(); _layers = new RenderLayers(_layerFactory); } @@ -122,7 +121,7 @@ public IEnumerable HitTest(Point p, Func filter) UpdateScene(); } - return _scene.HitTest(p, filter); + return _scene?.HitTest(p, filter) ?? Enumerable.Empty(); } /// @@ -186,7 +185,7 @@ private void Render(Scene scene) _dirtyRectsDisplay.Tick(); } - if (scene.Size != Size.Empty) + if (scene != null && scene.Size != Size.Empty) { if (scene.Generation != _lastSceneId) { @@ -366,25 +365,32 @@ private void UpdateScene() try { - var scene = _scene.Clone(); - - if (_dirty == null) - { - _dirty = new DirtyVisuals(); - _sceneBuilder.UpdateAll(scene); - } - else if (_dirty.Count > 0) + if (_root.IsVisible) { - foreach (var visual in _dirty) + var scene = _scene?.Clone() ?? new Scene(_root); + + if (_dirty == null) { - _sceneBuilder.Update(scene, visual); + _dirty = new DirtyVisuals(); + _sceneBuilder.UpdateAll(scene); + } + else if (_dirty.Count > 0) + { + foreach (var visual in _dirty) + { + _sceneBuilder.Update(scene, visual); + } } - } - Interlocked.Exchange(ref _scene, scene); + Interlocked.Exchange(ref _scene, scene); - _dirty.Clear(); - (_root as IRenderRoot)?.Invalidate(new Rect(scene.Size)); + _dirty.Clear(); + (_root as IRenderRoot)?.Invalidate(new Rect(scene.Size)); + } + else + { + Interlocked.Exchange(ref _scene, null); + } } finally { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs index afdf488b313..10455eb1470 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs @@ -36,8 +36,14 @@ public bool Update(Scene scene, IVisual visual) { Contract.Requires(scene != null); Contract.Requires(visual != null); + Dispatcher.UIThread.VerifyAccess(); + if (!scene.Root.Visual.IsVisible) + { + throw new AvaloniaInternalException("Cannot update the scene for an invisible root visual."); + } + var node = (VisualNode)scene.FindNode(visual); if (visual == scene.Root.Visual) diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs index 13f28018db8..e65487ac44f 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/SceneBuilderTests_Layers.cs @@ -273,32 +273,5 @@ public void GeometryClip_Should_Affect_Child_Layers() ((MockStreamGeometryImpl)borderLayer.GeometryClip).Transform); } } - - [Fact] - public void Hiding_Root_Should_Not_Remove_Root_Layer() - { - using (TestApplication()) - { - Border border; - var tree = new TestRoot - { - Child = border = new Border() - }; - - var layout = AvaloniaLocator.Current.GetService(); - layout.ExecuteInitialLayoutPass(tree); - - var scene = new Scene(tree); - var sceneBuilder = new SceneBuilder(); - sceneBuilder.UpdateAll(scene); - - tree.IsVisible = false; - - scene = scene.Clone(); - sceneBuilder.Update(scene, tree); - - Assert.Equal(1, scene.Layers.Count); - } - } } }