Browse Source

Simplified DeferredRendererTests,

pull/1306/head
Steven Kirk 9 years ago
parent
commit
e6b5df8d08
  1. 18
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  2. 18
      tests/Avalonia.UnitTests/TestRoot.cs
  3. 140
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

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

@ -25,7 +25,6 @@ namespace Avalonia.Rendering
private readonly IRenderLoop _renderLoop; private readonly IRenderLoop _renderLoop;
private readonly IVisual _root; private readonly IVisual _root;
private readonly ISceneBuilder _sceneBuilder; private readonly ISceneBuilder _sceneBuilder;
private readonly RenderLayers _layers;
private bool _running; private bool _running;
private Scene _scene; private Scene _scene;
@ -56,7 +55,7 @@ namespace Avalonia.Rendering
_dispatcher = dispatcher ?? Dispatcher.UIThread; _dispatcher = dispatcher ?? Dispatcher.UIThread;
_root = root; _root = root;
_sceneBuilder = sceneBuilder ?? new SceneBuilder(); _sceneBuilder = sceneBuilder ?? new SceneBuilder();
_layers = new RenderLayers(); Layers = new RenderLayers();
_renderLoop = renderLoop; _renderLoop = renderLoop;
} }
@ -80,7 +79,7 @@ namespace Avalonia.Rendering
_root = root; _root = root;
_renderTarget = renderTarget; _renderTarget = renderTarget;
_sceneBuilder = sceneBuilder ?? new SceneBuilder(); _sceneBuilder = sceneBuilder ?? new SceneBuilder();
_layers = new RenderLayers(); Layers = new RenderLayers();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -94,6 +93,11 @@ namespace Avalonia.Rendering
/// </summary> /// </summary>
public string DebugFramesPath { get; set; } public string DebugFramesPath { get; set; }
/// <summary>
/// Gets the render layers.
/// </summary>
internal RenderLayers Layers { get; }
/// <inheritdoc/> /// <inheritdoc/>
public void AddDirty(IVisual visual) public void AddDirty(IVisual visual)
{ {
@ -192,7 +196,7 @@ namespace Avalonia.Rendering
if (scene.Generation != _lastSceneId) if (scene.Generation != _lastSceneId)
{ {
context = _renderTarget.CreateDrawingContext(this); context = _renderTarget.CreateDrawingContext(this);
_layers.Update(scene, context); Layers.Update(scene, context);
RenderToLayers(scene); RenderToLayers(scene);
@ -262,7 +266,7 @@ namespace Avalonia.Rendering
{ {
foreach (var layer in scene.Layers) foreach (var layer in scene.Layers)
{ {
var renderTarget = _layers[layer.LayerRoot].Bitmap; var renderTarget = Layers[layer.LayerRoot].Bitmap;
var node = (VisualNode)scene.FindNode(layer.LayerRoot); var node = (VisualNode)scene.FindNode(layer.LayerRoot);
if (node != null) if (node != null)
@ -322,7 +326,7 @@ namespace Avalonia.Rendering
foreach (var layer in scene.Layers) foreach (var layer in scene.Layers)
{ {
var bitmap = _layers[layer.LayerRoot].Bitmap; var bitmap = Layers[layer.LayerRoot].Bitmap;
var sourceRect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight); var sourceRect = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight);
if (layer.GeometryClip != null) if (layer.GeometryClip != null)
@ -442,7 +446,7 @@ namespace Avalonia.Rendering
{ {
var index = 0; var index = 0;
foreach (var layer in _layers) foreach (var layer in Layers)
{ {
var fileName = Path.Combine(DebugFramesPath, $"frame-{id}-layer-{index++}.png"); var fileName = Path.Combine(DebugFramesPath, $"frame-{id}-layer-{index++}.png");
layer.Bitmap.Save(fileName); layer.Bitmap.Save(fileName);

18
tests/Avalonia.UnitTests/TestRoot.cs

@ -16,8 +16,6 @@ namespace Avalonia.UnitTests
public class TestRoot : Decorator, IFocusScope, ILayoutRoot, IInputRoot, INameScope, IRenderRoot, IStyleRoot public class TestRoot : Decorator, IFocusScope, ILayoutRoot, IInputRoot, INameScope, IRenderRoot, IStyleRoot
{ {
private readonly NameScope _nameScope = new NameScope(); private readonly NameScope _nameScope = new NameScope();
private readonly IRenderTarget _renderTarget = Mock.Of<IRenderTarget>(
x => x.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>()) == Mock.Of<IDrawingContextImpl>());
public TestRoot() public TestRoot()
{ {
@ -65,7 +63,21 @@ namespace Avalonia.UnitTests
IStyleHost IStyleHost.StylingParent => StylingParent; IStyleHost IStyleHost.StylingParent => StylingParent;
public IRenderTarget CreateRenderTarget() => _renderTarget; public IRenderTarget CreateRenderTarget()
{
var dc = new Mock<IDrawingContextImpl>();
dc.Setup(x => x.CreateLayer(It.IsAny<Size>())).Returns(() =>
{
var layerDc = new Mock<IDrawingContextImpl>();
var layer = new Mock<IRenderTargetBitmapImpl>();
layer.Setup(x => x.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>())).Returns(layerDc.Object);
return layer.Object;
});
var result = new Mock<IRenderTarget>();
result.Setup(x => x.CreateDrawingContext(It.IsAny<IVisualBrushRenderer>())).Returns(dc.Object);
return result.Object;
}
public void Invalidate(Rect rect) public void Invalidate(Rect rect)
{ {

140
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@ -21,28 +21,18 @@ namespace Avalonia.Visuals.UnitTests.Rendering
[Fact] [Fact]
public void First_Frame_Calls_UpdateScene_On_Dispatcher() public void First_Frame_Calls_UpdateScene_On_Dispatcher()
{ {
var loop = new Mock<IRenderLoop>();
var root = new TestRoot(); var root = new TestRoot();
var dispatcher = new Mock<IDispatcher>(); var dispatcher = new Mock<IDispatcher>();
dispatcher.Setup(x => x.InvokeAsync(It.IsAny<Action>(), DispatcherPriority.Render)) dispatcher.Setup(x => x.InvokeAsync(It.IsAny<Action>(), DispatcherPriority.Render))
.Callback<Action, DispatcherPriority>((a, p) => a()); .Callback<Action, DispatcherPriority>((a, p) => a());
var target = new DeferredRenderer( CreateTargetAndRunFrame(root, dispatcher: dispatcher.Object);
root,
loop.Object,
sceneBuilder: MockSceneBuilder(root).Object,
dispatcher: dispatcher.Object);
target.Start();
RunFrame(loop);
#if !NETCOREAPP1_1 // Delegate.Method is not available in netcoreapp1.1
dispatcher.Verify(x => dispatcher.Verify(x =>
x.InvokeAsync( x.InvokeAsync(
It.Is<Action>(a => a.Method.Name == "UpdateScene"), It.Is<Action>(a => a.Method.Name == "UpdateScene"),
DispatcherPriority.Render)); DispatcherPriority.Render));
#endif
} }
[Fact] [Fact]
@ -51,15 +41,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var loop = new Mock<IRenderLoop>(); var loop = new Mock<IRenderLoop>();
var root = new TestRoot(); var root = new TestRoot();
var sceneBuilder = MockSceneBuilder(root); var sceneBuilder = MockSceneBuilder(root);
var dispatcher = new ImmediateDispatcher();
var target = new DeferredRenderer(
root,
loop.Object,
sceneBuilder: sceneBuilder.Object,
dispatcher: dispatcher);
target.Start(); CreateTargetAndRunFrame(root, sceneBuilder: sceneBuilder.Object);
RunFrame(loop);
sceneBuilder.Verify(x => x.UpdateAll(It.IsAny<Scene>())); sceneBuilder.Verify(x => x.UpdateAll(It.IsAny<Scene>()));
} }
@ -70,12 +53,10 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var loop = new Mock<IRenderLoop>(); var loop = new Mock<IRenderLoop>();
var root = new TestRoot(); var root = new TestRoot();
var sceneBuilder = MockSceneBuilder(root); var sceneBuilder = MockSceneBuilder(root);
var dispatcher = new ImmediateDispatcher();
var target = new DeferredRenderer( var target = new DeferredRenderer(
root, root,
loop.Object, loop.Object,
sceneBuilder: sceneBuilder.Object, sceneBuilder: sceneBuilder.Object);
dispatcher: dispatcher);
target.Start(); target.Start();
IgnoreFirstFrame(loop, sceneBuilder); IgnoreFirstFrame(loop, sceneBuilder);
@ -145,24 +126,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity); root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize)); root.Arrange(new Rect(root.DesiredSize));
var rootLayer = CreateLayer(); var target = CreateTargetAndRunFrame(root);
var borderLayer = CreateLayer(); var context = GetLayerContext(target, root);
var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny<Size>()))
.Returns(rootLayer)
.Returns(borderLayer);
var loop = new Mock<IRenderLoop>();
var target = new DeferredRenderer(
root,
loop.Object,
dispatcher: new ImmediateDispatcher());
root.Renderer = target;
target.Start();
RunFrame(loop);
var context = Mock.Get(rootLayer.CreateDrawingContext(null));
var animation = new BehaviorSubject<double>(0.5); var animation = new BehaviorSubject<double>(0.5);
context.Verify(x => x.PushOpacity(0.5), Times.Once); context.Verify(x => x.PushOpacity(0.5), Times.Once);
@ -191,24 +156,8 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity); root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize)); root.Arrange(new Rect(root.DesiredSize));
var rootLayer = CreateLayer(); var target = CreateTargetAndRunFrame(root);
var borderLayer = CreateLayer(); var context = GetLayerContext(target, root);
var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny<Size>()))
.Returns(rootLayer)
.Returns(borderLayer);
var loop = new Mock<IRenderLoop>();
var target = new DeferredRenderer(
root,
loop.Object,
dispatcher: new ImmediateDispatcher());
root.Renderer = target;
target.Start();
RunFrame(loop);
var context = Mock.Get(rootLayer.CreateDrawingContext(null));
var animation = new BehaviorSubject<double>(0.5); var animation = new BehaviorSubject<double>(0.5);
context.Verify(x => x.PushOpacity(0.5), Times.Never); context.Verify(x => x.PushOpacity(0.5), Times.Never);
@ -217,12 +166,11 @@ namespace Avalonia.Visuals.UnitTests.Rendering
} }
[Fact] [Fact]
public void Frame_Should_Create_Layer_For_Root() public void Should_Create_Layer_For_Root()
{ {
var loop = new Mock<IRenderLoop>(); var loop = new Mock<IRenderLoop>();
var root = new TestRoot(); var root = new TestRoot();
var rootLayer = new Mock<IRenderTargetBitmapImpl>(); var rootLayer = new Mock<IRenderTargetBitmapImpl>();
var dispatcher = new ImmediateDispatcher();
var sceneBuilder = new Mock<ISceneBuilder>(); var sceneBuilder = new Mock<ISceneBuilder>();
sceneBuilder.Setup(x => x.UpdateAll(It.IsAny<Scene>())) sceneBuilder.Setup(x => x.UpdateAll(It.IsAny<Scene>()))
@ -233,18 +181,9 @@ namespace Avalonia.Visuals.UnitTests.Rendering
}); });
var renderInterface = new Mock<IPlatformRenderInterface>(); var renderInterface = new Mock<IPlatformRenderInterface>();
var target = CreateTargetAndRunFrame(root, sceneBuilder: sceneBuilder.Object);
var target = new DeferredRenderer( Assert.Single(target.Layers);
root,
loop.Object,
sceneBuilder: sceneBuilder.Object,
dispatcher: dispatcher);
target.Start();
RunFrame(loop);
var context = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
context.Verify(x => x.CreateLayer(root.ClientSize));
} }
[Fact] [Fact]
@ -269,49 +208,44 @@ namespace Avalonia.Visuals.UnitTests.Rendering
root.Measure(Size.Infinity); root.Measure(Size.Infinity);
root.Arrange(new Rect(root.DesiredSize)); root.Arrange(new Rect(root.DesiredSize));
var rootLayer = CreateLayer();
var borderLayer = CreateLayer();
var renderTargetContext = Mock.Get(root.CreateRenderTarget().CreateDrawingContext(null));
renderTargetContext.SetupSequence(x => x.CreateLayer(It.IsAny<Size>()))
.Returns(rootLayer)
.Returns(borderLayer);
var loop = new Mock<IRenderLoop>(); var loop = new Mock<IRenderLoop>();
var target = new DeferredRenderer( var target = CreateTargetAndRunFrame(root, loop: loop);
root,
loop.Object,
dispatcher: new ImmediateDispatcher());
root.Renderer = target;
target.Start(); Assert.Equal(new[] { root }, target.Layers.Select(x => x.LayerRoot));
RunFrame(loop);
var rootContext = Mock.Get(rootLayer.CreateDrawingContext(null));
var borderContext = Mock.Get(borderLayer.CreateDrawingContext(null));
var animation = new BehaviorSubject<double>(0.5); var animation = new BehaviorSubject<double>(0.5);
rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once);
rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
borderContext.Verify(x => x.FillRectangle(It.IsAny<IBrush>(), It.IsAny<Rect>(), It.IsAny<float>()), Times.Never);
rootContext.ResetCalls();
borderContext.ResetCalls();
border.Bind(Border.OpacityProperty, animation, BindingPriority.Animation); border.Bind(Border.OpacityProperty, animation, BindingPriority.Animation);
RunFrame(loop); RunFrame(loop);
rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once); Assert.Equal(new IVisual[] { root, border }, target.Layers.Select(x => x.LayerRoot));
rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Never);
borderContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
rootContext.ResetCalls();
borderContext.ResetCalls();
animation.OnCompleted(); animation.OnCompleted();
RunFrame(loop); RunFrame(loop);
Mock.Get(borderLayer).Verify(x => x.Dispose()); Assert.Equal(new[] { root }, target.Layers.Select(x => x.LayerRoot));
rootContext.Verify(x => x.FillRectangle(Brushes.Red, new Rect(0, 0, 100, 100), 0), Times.Once); }
rootContext.Verify(x => x.FillRectangle(Brushes.Green, new Rect(0, 0, 100, 100), 0), Times.Once);
borderContext.Verify(x => x.FillRectangle(It.IsAny<IBrush>(), It.IsAny<Rect>(), It.IsAny<float>()), Times.Never); private DeferredRenderer CreateTargetAndRunFrame(
TestRoot root,
Mock<IRenderLoop> loop = null,
ISceneBuilder sceneBuilder = null,
IDispatcher dispatcher = null)
{
loop = loop ?? new Mock<IRenderLoop>();
var target = new DeferredRenderer(
root,
loop.Object,
sceneBuilder: sceneBuilder,
dispatcher: dispatcher ?? new ImmediateDispatcher());
root.Renderer = target;
target.Start();
RunFrame(loop);
return target;
}
private Mock<IDrawingContextImpl> GetLayerContext(DeferredRenderer renderer, IControl layerRoot)
{
return Mock.Get(renderer.Layers[layerRoot].Bitmap.CreateDrawingContext(null));
} }
private void IgnoreFirstFrame(Mock<IRenderLoop> loop, Mock<ISceneBuilder> sceneBuilder) private void IgnoreFirstFrame(Mock<IRenderLoop> loop, Mock<ISceneBuilder> sceneBuilder)

Loading…
Cancel
Save