Browse Source

Throw on attempt to invalidate a visual during a render pass

pull/8863/head
Nikita Tsukanov 4 years ago
parent
commit
ec164ea0c3
  1. 22
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  2. 33
      src/Avalonia.Base/Rendering/DirtyVisuals.cs

22
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -29,6 +29,7 @@ public class CompositingRenderer : IRendererWithCompositor
private bool _queuedUpdate; private bool _queuedUpdate;
private Action _update; private Action _update;
private Action _invalidateScene; private Action _invalidateScene;
private bool _updating;
internal CompositionTarget CompositionTarget; internal CompositionTarget CompositionTarget;
@ -77,6 +78,8 @@ public class CompositingRenderer : IRendererWithCompositor
/// <inheritdoc/> /// <inheritdoc/>
public void AddDirty(IVisual visual) public void AddDirty(IVisual visual)
{ {
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
_dirty.Add((Visual)visual); _dirty.Add((Visual)visual);
QueueUpdate(); QueueUpdate();
} }
@ -107,6 +110,8 @@ public class CompositingRenderer : IRendererWithCompositor
/// <inheritdoc/> /// <inheritdoc/>
public void RecalculateChildren(IVisual visual) public void RecalculateChildren(IVisual visual)
{ {
if (_updating)
throw new InvalidOperationException("Visual was invalidated during the render pass");
_recalculateChildren.Add((Visual)visual); _recalculateChildren.Add((Visual)visual);
QueueUpdate(); QueueUpdate();
} }
@ -191,7 +196,7 @@ public class CompositingRenderer : IRendererWithCompositor
private void InvalidateScene() => private void InvalidateScene() =>
SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs(_root, new Rect(_root.ClientSize))); SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs(_root, new Rect(_root.ClientSize)));
private void Update() private void UpdateCore()
{ {
_queuedUpdate = false; _queuedUpdate = false;
foreach (var visual in _dirty) foreach (var visual in _dirty)
@ -240,6 +245,21 @@ public class CompositingRenderer : IRendererWithCompositor
CompositionTarget.Scaling = _root.RenderScaling; CompositionTarget.Scaling = _root.RenderScaling;
Compositor.InvokeOnNextCommit(_invalidateScene); Compositor.InvokeOnNextCommit(_invalidateScene);
} }
private void Update()
{
if(_updating)
return;
_updating = true;
try
{
UpdateCore();
}
finally
{
_updating = false;
}
}
public void Resized(Size size) public void Resized(Size size)
{ {

33
src/Avalonia.Base/Rendering/DirtyVisuals.cs

@ -17,8 +17,7 @@ namespace Avalonia.Rendering
{ {
private SortedDictionary<int, List<IVisual>> _inner = new SortedDictionary<int, List<IVisual>>(); private SortedDictionary<int, List<IVisual>> _inner = new SortedDictionary<int, List<IVisual>>();
private Dictionary<IVisual, int> _index = new Dictionary<IVisual, int>(); private Dictionary<IVisual, int> _index = new Dictionary<IVisual, int>();
private List<IVisual> _deferredChanges = new List<IVisual>(); private int _enumerating;
private int _deferring;
/// <summary> /// <summary>
/// Gets the number of dirty visuals. /// Gets the number of dirty visuals.
@ -31,10 +30,9 @@ namespace Avalonia.Rendering
/// <param name="visual">The dirty visual.</param> /// <param name="visual">The dirty visual.</param>
public void Add(IVisual visual) public void Add(IVisual visual)
{ {
if (_deferring > 0) if (_enumerating > 0)
{ {
_deferredChanges.Add(visual); throw new InvalidOperationException("Visual was invalidated during a render pass");
return;
} }
var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot); var distance = visual.CalculateDistanceFromAncestor(visual.VisualRoot);
@ -65,7 +63,7 @@ namespace Avalonia.Rendering
/// </summary> /// </summary>
public void Clear() public void Clear()
{ {
if (_deferring > 0) if (_enumerating > 0)
{ {
throw new InvalidOperationException("Cannot clear while enumerating"); throw new InvalidOperationException("Cannot clear while enumerating");
} }
@ -80,7 +78,7 @@ namespace Avalonia.Rendering
/// <returns>A collection of visuals.</returns> /// <returns>A collection of visuals.</returns>
public IEnumerator<IVisual> GetEnumerator() public IEnumerator<IVisual> GetEnumerator()
{ {
BeginDefer(); _enumerating++;
try try
{ {
foreach (var i in _inner) foreach (var i in _inner)
@ -93,27 +91,10 @@ namespace Avalonia.Rendering
} }
finally finally
{ {
EndDefer(); _enumerating--;
} }
} }
private void BeginDefer()
{
++_deferring;
}
private void EndDefer()
{
if (--_deferring > 0) return;
foreach (var visual in _deferredChanges)
{
Add(visual);
}
_deferredChanges.Clear();
}
/// <summary> /// <summary>
/// Gets the dirty visuals, in ascending order of distance to their root. /// Gets the dirty visuals, in ascending order of distance to their root.
/// </summary> /// </summary>

Loading…
Cancel
Save