Browse Source

baseline benchmark

feature/backdrop-experiment
Nikita Tsukanov 3 months ago
parent
commit
c7e41c3d85
  1. 46
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  2. 121
      tests/Avalonia.Benchmarks/Compositor/CompositionTargetUpdate.cs

46
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs

@ -83,6 +83,31 @@ namespace Avalonia.Rendering.Composition.Server
_redrawRequested = true;
_fullRedrawRequested = true;
}
public void Update()
{
Revision++;
_overlays.MarkUpdateCallStart();
using (Diagnostic.BeginCompositorUpdatePass())
{
var transform = Matrix.CreateScale(Scaling, Scaling);
// Update happens in a separate phase to extend dirty rect if needed
Root!.Update(this, transform);
while (_adornerUpdateQueue.Count > 0)
{
var adorner = _adornerUpdateQueue.Dequeue();
adorner.Update(this, transform);
}
_updateRequested = false;
Readback.CompleteWrite(Revision);
_overlays.MarkUpdateCallEnd();
}
}
public void Render()
{
@ -120,26 +145,7 @@ namespace Avalonia.Rendering.Composition.Server
if (DirtyRects.IsEmpty && !_redrawRequested && !_updateRequested)
return;
Revision++;
_overlays.MarkUpdateCallStart();
using (Diagnostic.BeginCompositorUpdatePass())
{
var transform = Matrix.CreateScale(Scaling, Scaling);
// Update happens in a separate phase to extend dirty rect if needed
Root.Update(this, transform);
while (_adornerUpdateQueue.Count > 0)
{
var adorner = _adornerUpdateQueue.Dequeue();
adorner.Update(this, transform);
}
_updateRequested = false;
Readback.CompleteWrite(Revision);
_overlays.MarkUpdateCallEnd();
}
Update();
if (!_redrawRequested)
return;

121
tests/Avalonia.Benchmarks/Compositor/CompositionTargetUpdate.cs

@ -0,0 +1,121 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Controls.Platform.Surfaces;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Avalonia.Rendering.Composition.Drawing;
using Avalonia.Rendering.Composition.Server;
using Avalonia.Threading;
using Avalonia.UnitTests;
using BenchmarkDotNet.Attributes;
namespace Avalonia.Benchmarks;
public class CompositionTargetUpdateOnly : IDisposable
{
private readonly bool _includeRender;
private readonly IDisposable _app;
private readonly Compositor _compositor;
private readonly CompositionTarget _target;
class Timer : IRenderTimer
{
public event Action<TimeSpan> Tick;
public bool RunsInBackground { get; }
}
class ManualScheduler : ICompositorScheduler
{
public void CommitRequested(Compositor compositor)
{
}
}
class NullFramebuffer : IFramebufferPlatformSurface
{
private static readonly IntPtr Buffer = Marshal.AllocHGlobal(4);
public IFramebufferRenderTarget CreateFramebufferRenderTarget() =>
new FuncFramebufferRenderTarget(() => new LockedFramebuffer(Buffer, new PixelSize(1, 1), 4, new Vector(96, 96), PixelFormat.Rgba8888,
null));
}
public CompositionTargetUpdateOnly() : this(false)
{
}
protected CompositionTargetUpdateOnly(bool includeRender)
{
_includeRender = includeRender;
_app = UnitTestApplication.Start(TestServices.StyledWindow);
_compositor = new Compositor(new RenderLoop(new Timer()), null, true, new ManualScheduler(), true,
Dispatcher.UIThread, null);
_target = _compositor.CreateCompositionTarget(() => [new NullFramebuffer()]);
_target.PixelSize = new PixelSize(1000, 1000);
_target.Scaling = 1;
var root = _compositor.CreateContainerVisual();
root.Size = new Vector(1000, 1000);
_target.Root = root;
if (includeRender)
_target.IsEnabled = true;
CreatePyramid(root, 7);
_compositor.Commit();
}
void CreatePyramid(CompositionContainerVisual visual, int depth)
{
for (var c = 0; c < 4; c++)
{
var child = new CompositionDrawListVisual(visual.Compositor,
new ServerCompositionDrawListVisual(visual.Compositor.Server, null!), null!);
double right = c == 1 || c == 3 ? 1 : 0;
double bottom = c > 1 ? 1 : 0;
var rect = new Rect(
visual.Size.X / 2 * right,
visual.Size.Y / 2 * bottom,
visual.Size.X / 2,
visual.Size.Y / 2
);
child.Offset = new(rect.X, rect.Y, 0);
child.Size = new Vector(rect.Width, rect.Height);
var ctx = new RenderDataDrawingContext(child.Compositor);
ctx.DrawRectangle(Brushes.Aqua, null, new Rect(rect.Size));
child.DrawList = ctx.GetRenderResults();
child.Visible = true;
visual.Children.Add(child);
if (depth > 0)
CreatePyramid(child, depth - 1);
}
}
[Benchmark]
public void TargetUpdate()
{
_target.Root.Offset = new Vector3D(_target.Root.Offset.X == 0 ? 1 : 0, 0, 0);
_compositor.Commit();
_compositor.Server.Render();
if (!_includeRender)
_target.Server.Update();
}
public void Dispose()
{
_app.Dispose();
}
}
public class CompositionTargetUpdateWithRender : CompositionTargetUpdateOnly
{
public CompositionTargetUpdateWithRender() : base(true)
{
}
}
Loading…
Cancel
Save