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

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

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Rendering.SceneGraph.Media; using Avalonia.Rendering.SceneGraph.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -8,6 +10,8 @@ namespace Avalonia.Rendering.SceneGraph
{ {
public abstract Rect Bounds { get; } public abstract Rect Bounds { get; }
public abstract bool HitTest(Point p); public abstract bool HitTest(Point p);
public abstract IDictionary<IVisual, Scene> ChildScenes { get; }
public abstract void Render(IDrawingContextImpl context); public abstract void Render(IDrawingContextImpl context);
protected IBrush Convert(IBrush brush) 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
internal class DeferredDrawingContextImpl : IDrawingContextImpl internal class DeferredDrawingContextImpl : IDrawingContextImpl
{ {
private readonly ISceneBuilder _sceneBuilder;
private VisualNode _node; private VisualNode _node;
private int _childIndex; private int _childIndex;
private int _drawOperationindex; private int _drawOperationindex;
public DeferredDrawingContextImpl(SceneLayers layers) public DeferredDrawingContextImpl(ISceneBuilder sceneBuilder, SceneLayers layers)
{ {
_sceneBuilder = sceneBuilder;
Layers = layers; Layers = layers;
} }
@ -67,7 +71,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, brush, pen, geometry)) 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 else
{ {
@ -109,7 +113,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, null, pen, rect, cornerRadius)) 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 else
{ {
@ -137,7 +141,7 @@ namespace Avalonia.Rendering.SceneGraph
if (next == null || !next.Equals(Transform, brush, null, rect, cornerRadius)) 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 else
{ {
@ -239,5 +243,25 @@ namespace Avalonia.Rendering.SceneGraph
{ {
return _drawOperationindex < _node.DrawOperations.Count ? _node.DrawOperations[_drawOperationindex] as T : null; 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
public class GeometryNode : BrushDrawOperation 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); Bounds = geometry.GetRenderBounds(pen.Thickness).TransformToAABB(transform);
Transform = transform; Transform = transform;
Brush = Convert(brush); Brush = Convert(brush);
Pen = Convert(pen); Pen = Convert(pen);
Geometry = geometry; Geometry = geometry;
ChildScenes = childScenes;
} }
public override Rect Bounds { get; } public override Rect Bounds { get; }
@ -23,6 +31,7 @@ namespace Avalonia.Rendering.SceneGraph
public IBrush Brush { get; } public IBrush Brush { get; }
public Pen Pen { get; } public Pen Pen { get; }
public IGeometryImpl Geometry { get; } public IGeometryImpl Geometry { get; }
public override IDictionary<IVisual, Scene> ChildScenes { get; }
public bool Equals(Matrix transform, IBrush brush, Pen pen, IGeometryImpl geometry) 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -25,6 +27,7 @@ namespace Avalonia.Rendering.SceneGraph
public double Opacity { get; } public double Opacity { get; }
public Rect SourceRect { get; } public Rect SourceRect { get; }
public Rect DestRect { get; } public Rect DestRect { get; }
public IDictionary<VisualBrush, Scene> ChildScenes => null;
public bool Equals(Matrix transform, IBitmapImpl source, double opacity, Rect sourceRect, Rect destRect) 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -22,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
public Pen Pen { get; } public Pen Pen { get; }
public Point P1 { get; } public Point P1 { get; }
public Point P2 { get; } public Point P2 { get; }
public override IDictionary<IVisual, Scene> ChildScenes => null;
public bool Equals(Matrix transform, Pen pen, Point p1, Point p2) 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
public class RectangleNode : BrushDrawOperation 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); Bounds = rect.TransformToAABB(transform).Inflate(pen?.Thickness ?? 0);
Transform = transform; Transform = transform;
@ -16,6 +24,7 @@ namespace Avalonia.Rendering.SceneGraph
Pen = Convert(pen); Pen = Convert(pen);
Rect = rect; Rect = rect;
CornerRadius = cornerRadius; CornerRadius = cornerRadius;
ChildScenes = childScenes;
} }
public override Rect Bounds { get; } public override Rect Bounds { get; }
@ -24,6 +33,7 @@ namespace Avalonia.Rendering.SceneGraph
public Pen Pen { get; } public Pen Pen { get; }
public Rect Rect { get; } public Rect Rect { get; }
public float CornerRadius { 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) 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); UpdateSize(scene);
scene.Layers.GetOrAdd(scene.Root.Visual); 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)) using (var context = new DrawingContext(impl))
{ {
Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true); Update(context, scene, (VisualNode)scene.Root, scene.Root.Visual.Bounds, true);
@ -55,7 +55,7 @@ namespace Avalonia.Rendering.SceneGraph
// descendents too. // descendents too.
var recurse = node.Visual != visual; 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)) using (var context = new DrawingContext(impl))
{ {
var clip = scene.Root.Visual.Bounds; 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. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph namespace Avalonia.Rendering.SceneGraph
{ {
@ -23,6 +25,7 @@ namespace Avalonia.Rendering.SceneGraph
public IBrush Foreground { get; } public IBrush Foreground { get; }
public Point Origin { get; } public Point Origin { get; }
public IFormattedTextImpl Text { get; } public IFormattedTextImpl Text { get; }
public IDictionary<VisualBrush, Scene> ChildScenes => null;
public void Render(IDrawingContextImpl context) 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); Contract.Requires<ArgumentNullException>(visual != null);
if (parent == null && visual.VisualParent != null)
{
throw new AvaloniaInternalException(
"Attempted to create root VisualNode for parented visual.");
}
Visual = visual; Visual = visual;
Parent = parent; 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 parent = new VisualNode(new TestRoot(), null);
var child = new VisualNode(Mock.Of<IVisual>(), null); var child = new VisualNode(Mock.Of<IVisual>(), null);
var layers = new SceneLayers(parent.Visual); var layers = new SceneLayers(parent.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent); target.BeginUpdate(parent);
target.BeginUpdate(child); target.BeginUpdate(child);
@ -35,7 +35,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
parent.AddChild(child); parent.AddChild(child);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent); target.BeginUpdate(parent);
target.BeginUpdate(child); target.BeginUpdate(child);
@ -54,7 +54,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
parent.AddChild(child1); parent.AddChild(child1);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
target.BeginUpdate(parent); target.BeginUpdate(parent);
target.BeginUpdate(child2); target.BeginUpdate(child2);
@ -75,7 +75,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
node.AddChild(new VisualNode(Mock.Of<IVisual>(), node) { LayerRoot = root }); node.AddChild(new VisualNode(Mock.Of<IVisual>(), node) { LayerRoot = root });
var layers = new SceneLayers(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 child1 = new VisualNode(Mock.Of<IVisual>(), null) { LayerRoot = root };
var child2 = 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 node = new VisualNode(new TestRoot(), null);
var layers = new SceneLayers(node.Visual); var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual; node.LayerRoot = node.Visual;
@ -113,7 +113,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null); var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0); var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual); var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual; node.LayerRoot = node.Visual;
node.AddDrawOperation(operation); node.AddDrawOperation(operation);
@ -135,7 +135,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null); var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0); var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual); var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual; node.LayerRoot = node.Visual;
node.AddDrawOperation(operation); node.AddDrawOperation(operation);
@ -157,7 +157,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
var node = new VisualNode(new TestRoot(), null); var node = new VisualNode(new TestRoot(), null);
var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0); var operation = new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 100, 100), 0);
var layers = new SceneLayers(node.Visual); var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
node.LayerRoot = node.Visual; 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)); node.AddDrawOperation(new RectangleNode(Matrix.Identity, Brushes.Red, null, new Rect(0, 0, 40, 100), 0));
var layers = new SceneLayers(node.Visual); var layers = new SceneLayers(node.Visual);
var target = new DeferredDrawingContextImpl(layers); var target = new DeferredDrawingContextImpl(null, layers);
using (target.BeginUpdate(node)) using (target.BeginUpdate(node))
{ {

Loading…
Cancel
Save