Browse Source

Got VisualBrushes working again.

scenegraph-after-breakage
Steven Kirk 9 years ago
parent
commit
69bca2cf89
  1. 57
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  2. 4
      src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs
  3. 32
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  4. 11
      src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs
  5. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/IDrawOperation.cs
  6. 3
      src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
  7. 3
      src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs
  8. 12
      src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs
  9. 4
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  10. 3
      src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs
  11. 6
      src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs
  12. 18
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs

57
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -30,6 +30,7 @@ namespace Avalonia.Rendering
private bool _rendering;
private int _lastSceneId = -1;
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
private IDrawOperation _currentDraw;
public DeferredRenderer(
IRenderRoot root,
@ -107,20 +108,16 @@ namespace Avalonia.Rendering
Size IVisualBrushRenderer.GetRenderTargetSize(IVisualBrush brush)
{
if (brush.Visual != null)
{
return _scene.FindNode(brush.Visual)?.ClipBounds.Size ?? Size.Empty;
}
return Size.Empty;
return (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual]?.Size ?? Size.Empty;
}
void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, IVisualBrush brush)
{
if (brush.Visual != null)
var childScene = (_currentDraw as BrushDrawOperation)?.ChildScenes?[brush.Visual];
if (childScene != null)
{
var node = (VisualNode)_scene.FindNode(brush.Visual);
Render(context, node, null, node.ClipBounds);
Render(context, (VisualNode)childScene.Root, null, new Rect(childScene.Size));
}
}
@ -130,29 +127,37 @@ namespace Avalonia.Rendering
private void Render(Scene scene)
{
_rendering = true;
_dirtyRectsDisplay.Tick();
if (scene.Size != Size.Empty)
if (!_rendering)
{
if (scene.Id != _lastSceneId)
try
{
_layers.Update(scene);
RenderToLayers(scene);
_rendering = true;
_dirtyRectsDisplay.Tick();
if (DebugFramesPath != null)
if (scene.Size != Size.Empty)
{
SaveDebugFrames(scene.Id);
}
if (scene.Id != _lastSceneId)
{
_layers.Update(scene);
RenderToLayers(scene);
_lastSceneId = scene.Id;
}
if (DebugFramesPath != null)
{
SaveDebugFrames(scene.Id);
}
RenderOverlay(scene);
RenderComposite(scene);
}
_lastSceneId = scene.Id;
}
_rendering = false;
RenderOverlay(scene);
RenderComposite(scene);
}
}
finally
{
_rendering = false;
}
}
}
private void Render(IDrawingContextImpl context, VisualNode node, IVisual layer, Rect clipBounds)
@ -167,7 +172,9 @@ namespace Avalonia.Rendering
foreach (var operation in node.DrawOperations)
{
_currentDraw = operation;
operation.Render(context);
_currentDraw = null;
}
foreach (var child in node.Children)

4
src/Avalonia.Visuals/Rendering/SceneGraph/BrushDrawOperation.cs

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Rendering.SceneGraph.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
@ -8,6 +10,8 @@ namespace Avalonia.Rendering.SceneGraph
{
public abstract Rect Bounds { get; }
public abstract bool HitTest(Point p);
public abstract IDictionary<IVisual, Scene> ChildScenes { get; }
public abstract void Render(IDrawingContextImpl context);
protected IBrush Convert(IBrush brush)

32
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -2,19 +2,23 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
internal class DeferredDrawingContextImpl : IDrawingContextImpl
{
private readonly ISceneBuilder _sceneBuilder;
private VisualNode _node;
private int _childIndex;
private int _drawOperationindex;
public DeferredDrawingContextImpl(SceneLayers layers)
public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers)
{
_sceneBuilder = sceneBuilder;
Layers = layers;
}
@ -67,7 +71,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, brush, pen, geometry))
{
Add(new GeometryNode(Transform, brush, pen, geometry));
Add(new GeometryNode(Transform, brush, pen, geometry, CreateChildScene(brush)));
}
else
{
@ -109,7 +113,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, null, pen, rect, cornerRadius))
{
Add(new RectangleNode(Transform, null, pen, rect, cornerRadius));
Add(new RectangleNode(Transform, null, pen, rect, cornerRadius, CreateChildScene(pen.Brush)));
}
else
{
@ -137,7 +141,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, brush, null, rect, cornerRadius))
{
Add(new RectangleNode(Transform, brush, null, rect, cornerRadius));
Add(new RectangleNode(Transform, brush, null, rect, cornerRadius, CreateChildScene(brush)));
}
else
{
@ -239,5 +243,25 @@ namespace Avalonia.Rendering.SceneGraph
{
return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as T : null;
}
private IDictionary<IVisual, Scene> CreateChildScene(IBrush brush)
{
var visualBrush = brush as VisualBrush;
if (visualBrush != null)
{
var visual = visualBrush.Visual;
if (visual != null)
{
(visual as IVisualBrushInitialize)?.EnsureInitialized();
var scene = new Scene(visual);
_sceneBuilder.UpdateAll(scene);
return new Dictionary<IVisual, Scene> { { visualBrush.Visual, scene } };
}
}
return null;
}
}
}

11
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryNode.cs

@ -2,20 +2,28 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
public class GeometryNode : BrushDrawOperation
{
public GeometryNode(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
public GeometryNode(
Matrix transform,
IBrush brush,
Pen pen,
IGeometryImpl geometry,
IDictionary<IVisual, Scene> childScenes = null)
{
Bounds = geometry.GetRenderBounds(pen.Thickness).TransformToAABB(transform);
Transform = transform;
Brush = Convert(brush);
Pen = Convert(pen);
Geometry = geometry;
ChildScenes = childScenes;
}
public override Rect Bounds { get; }
@ -23,6 +31,7 @@ namespace Avalonia.Rendering.SceneGraph
public IBrush Brush { get; }
public Pen Pen { get; }
public IGeometryImpl Geometry { get; }
public override IDictionary<IVisual, Scene> ChildScenes { get; }
public bool Equals(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry)
{

2
src/Avalonia.Visuals/Rendering/SceneGraph/IDrawOperation.cs

@ -2,7 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{

3
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@ -2,8 +2,10 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
@ -25,6 +27,7 @@ namespace Avalonia.Rendering.SceneGraph
public double Opacity { get; }
public Rect SourceRect { get; }
public Rect DestRect { get; }
public IDictionary<VisualBrush, Scene> ChildScenes => null;
public bool Equals(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect)
{

3
src/Avalonia.Visuals/Rendering/SceneGraph/LineNode.cs

@ -2,7 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
@ -22,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
public Pen Pen { get; }
public Point P1 { get; }
public Point P2 { get; }
public override IDictionary<IVisual, Scene> ChildScenes => null;
public bool Equals(Matrix transform, Pen pen, Point p1, Point p2)
{

12
src/Avalonia.Visuals/Rendering/SceneGraph/RectangleNode.cs

@ -2,13 +2,21 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
public class RectangleNode : BrushDrawOperation
{
public RectangleNode(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
public RectangleNode(
Matrix transform,
IBrush brush,
Pen pen,
Rect rect,
float cornerRadius,
IDictionary<IVisual, Scene> childScenes = null)
{
Bounds = rect.TransformToAABB(transform).Inflate(pen?.Thickness ?? 0);
Transform = transform;
@ -16,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
Pen = Convert(pen);
Rect = rect;
CornerRadius = cornerRadius;
ChildScenes = childScenes;
}
public override Rect Bounds { get; }
@ -24,6 +33,7 @@ namespace Avalonia.Rendering.SceneGraph
public Pen Pen { get; }
public Rect Rect { get; }
public float CornerRadius { get; }
public override IDictionary<IVisual, Scene> ChildScenes { get; }
public bool Equals(Matrix transform, IBrush brush, Pen pen, Rect rect, float cornerRadius)
{

4
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -19,7 +19,7 @@ namespace Avalonia.Rendering.SceneGraph
UpdateSize(scene);
scene.Layers.GetOrAdd(scene.Root.Visual);
using (var impl = new DeferredDrawingContextImpl(scene.Layers))
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
@ -55,7 +55,7 @@ namespace Avalonia.Rendering.SceneGraph
// descendents too.
var recurse = node.Visual != visual;
using (var impl = new DeferredDrawingContextImpl(scene.Layers))
using (var impl = new DeferredDrawingContextImpl(this, scene.Layers))
using (var context = new DrawingContext(impl))
{
var clip = scene.Root.Visual.Bounds;

3
src/Avalonia.Visuals/Rendering/SceneGraph/TextNode.cs

@ -2,8 +2,10 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
@ -23,6 +25,7 @@ namespace Avalonia.Rendering.SceneGraph
public IBrush Foreground { get; }
public Point Origin { get; }
public IFormattedTextImpl Text { get; }
public IDictionary<VisualBrush, Scene> ChildScenes => null;
public void Render(IDrawingContextImpl context)
{

6
src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs

@ -31,12 +31,6 @@ namespace Avalonia.Rendering.SceneGraph
{
Contract.Requires<ArgumentNullException>(visual != null);
if (parent == null && visual.VisualParent != null)
{
throw new AvaloniaInternalException(
"Attempted to create root VisualNode for parented visual.");
}
Visual = visual;
Parent = parent;
}

18
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DeferredDrawingContextImplTests.cs

@ -17,7 +17,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var parent = new VisualNode(new TestRoot(), null);
var child = new VisualNode(Mock.Of<IVisual>(), null);
var layers = new SceneLayers(parent.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent);
target.BeginUpdate(child);
@ -35,7 +35,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
parent.AddChild(child);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent);
target.BeginUpdate(child);
@ -54,7 +54,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
parent.AddChild(child1);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent);
target.BeginUpdate(child2);
@ -75,7 +75,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
node.AddChild(new VisualNode(Mock.Of<IVisual>(), node) { LayerRoot = root });
var layers = new SceneLayers(root);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
var child1 = new VisualNode(Mock.Of<IVisual>(), null) { LayerRoot = root };
var child2 = new VisualNode(Mock.Of<IVisual>(), null) { LayerRoot = root };
@ -92,7 +92,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
{
var node = new VisualNode(new TestRoot(), null);
var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual;
@ -113,7 +113,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual;
node.AddDrawOperation(operation);
@ -135,7 +135,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual;
node.AddDrawOperation(operation);
@ -157,7 +157,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual;
@ -181,7 +181,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
node.AddDrawOperation(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 40, 100), 0));
var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers);
var target = new DeferredDrawingContextImpl(null, layers);
using (target.BeginUpdate(node))
{

Loading…
Cancel
Save