Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkatz6 authored Mar 25, 2024
2 parents 26a5d95 + e79d62a commit 12b6244
Show file tree
Hide file tree
Showing 16 changed files with 556 additions and 143 deletions.
18 changes: 18 additions & 0 deletions src/Avalonia.Base/Controls/ResourceDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,24 @@ public bool TryGetValue(object key, out object? value)
return false;
}

/// <summary>
/// Ensures that the resource dictionary can hold up to <paramref name="capacity"/> entries without
/// any further expansion of its backing storage.
/// </summary>
/// <remarks>This method may have no effect when targeting .NET Standard 2.0.</remarks>
public void EnsureCapacity(int capacity)
{
if (_inner is null)
{
_inner = new(capacity);
return;
}

#if !NETSTANDARD2_0
Inner.EnsureCapacity(capacity);
#endif
}

public IEnumerator<KeyValuePair<object, object?>> GetEnumerator()
{
return _inner?.GetEnumerator() ?? Enumerable.Empty<KeyValuePair<object, object?>>().GetEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,22 @@ public virtual void Activate()
{
if (_trackedObjects != null)
foreach (var tracked in _trackedObjects)
tracked.obj.SubscribeToInvalidation(tracked.member, this);
tracked.obj.GetOrCreateAnimations().SubscribeToInvalidation(tracked.member, this);
}

public virtual void Deactivate()
{
if (_trackedObjects != null)
foreach (var tracked in _trackedObjects)
tracked.obj.UnsubscribeFromInvalidation(tracked.member, this);
tracked.obj.Animations?.UnsubscribeFromInvalidation(tracked.member, this);
}

public void Invalidate()
{
if (_invalidated)
return;
_invalidated = true;
TargetObject.NotifyAnimatedValueChanged(Property);
TargetObject.Animations?.NotifyAnimationInstanceInvalidated(Property);
}

public void OnTick() => Invalidate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ protected override ExpressionVariant EvaluateCore(TimeSpan now, ExpressionVarian
&& elapsed > _totalDuration)
{
// Active check?
TargetObject.Compositor.RemoveFromClock(this);
TargetObject.Compositor.Animations.RemoveFromClock(this);
_finished = true;
}
return res;
Expand Down Expand Up @@ -177,13 +177,13 @@ public override void Activate()
{
return;
}
TargetObject.Compositor.AddToClock(this);
TargetObject.Compositor.Animations.AddToClock(this);
base.Activate();
}

public override void Deactivate()
{
TargetObject.Compositor.RemoveFromClock(this);
TargetObject.Compositor.Animations.RemoveFromClock(this);
base.Deactivate();
}
}
Expand Down
110 changes: 105 additions & 5 deletions src/Avalonia.Base/Rendering/Composition/Server/CompositionProperty.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Avalonia.Rendering.Composition.Expressions;

namespace Avalonia.Rendering.Composition.Server;

internal class CompositionProperty
{
private static volatile int s_NextId = 1;
public int Id { get; private set; }
private static int s_nextId = 1;
private static readonly object _lock = new();

public static CompositionProperty Register() => new()
private static Dictionary<Type, List<CompositionProperty>> s_dynamicRegistry = new();

class ReadOnlyRegistry : Dictionary<Type, IReadOnlyDictionary<string, CompositionProperty>>
{

}

private static volatile ReadOnlyRegistry? s_ReadOnlyRegistry;

public CompositionProperty(int id, string name, Type owner, Func<SimpleServerObject, ExpressionVariant>? getVariant)
{
Id = id;
Name = name;
Owner = owner;
GetVariant = getVariant;
}

public int Id { get; }
public string Name { get; }
public Type Owner { get; }
public Func<SimpleServerObject, ExpressionVariant>? GetVariant { get; }

public static CompositionProperty<TField> Register<TOwner, TField>(string name, Func<SimpleServerObject, TField> getField, Action<SimpleServerObject, TField> setField,
Func<SimpleServerObject, ExpressionVariant>? getVariant)
{
CompositionProperty<TField> prop;
lock (_lock)
{
var id = s_nextId++;
prop = new CompositionProperty<TField>(id, name, typeof(TOwner), getField, setField, getVariant);
}

s_ReadOnlyRegistry = null;
return prop;
}

static void PopulatePropertiesForType(Type type, List<CompositionProperty> l)
{
Id = Interlocked.Increment(ref s_NextId)
};
Type? t = type;
while (t != null && t != typeof(object))
{
if (s_dynamicRegistry.TryGetValue(t, out var lst))
l.AddRange(lst);
t = t.BaseType;
}
}

static ReadOnlyRegistry Build()
{
var reg = new ReadOnlyRegistry();
foreach (var type in s_dynamicRegistry.Keys)
{
var lst = new List<CompositionProperty>();
PopulatePropertiesForType(type, lst);
reg[type] = lst.ToDictionary(x => x.Name);
}

return reg;
}

public static IReadOnlyDictionary<string, CompositionProperty>? TryGetPropertiesForType(Type t)
{
GetRegistry().TryGetValue(t, out var rv);
return rv;
}

public static CompositionProperty? Find(Type owner, string name)
{
if (TryGetPropertiesForType(owner)?.TryGetValue(name, out var prop) == true)
return prop;
return null;
}

static ReadOnlyRegistry GetRegistry()
{
var reg = s_ReadOnlyRegistry;
if (reg != null)
return reg;
lock (_lock)
{
// ReSharper disable once NonAtomicCompoundOperator
// This is the only line ever that would set the field to a not-null value, and we are inside of a lock
return s_ReadOnlyRegistry ??= Build();
}
}
}

internal class CompositionProperty<T> : CompositionProperty
{
public Func<SimpleServerObject, T> GetField { get; }
public Action<SimpleServerObject, T> SetField { get; }

public CompositionProperty(int id, string name, Type owner,
Func<SimpleServerObject, T> getField,
Action<SimpleServerObject, T> setField,
Func<SimpleServerObject, ExpressionVariant>? getVariant)
: base(id, name, owner, getVariant)
{
GetField = getField;
SetField = setField;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ internal class CompositionTargetOverlays
{
private FpsCounter? _fpsCounter;
private FrameTimeGraph? _renderTimeGraph;
private FrameTimeGraph? _updateTimeGraph;
private FrameTimeGraph? _layoutTimeGraph;
private Rect? _oldFpsCounterRect;
private long _updateStarted;
Expand All @@ -35,6 +36,11 @@ private FrameTimeGraph? LayoutTimeGraph

private FrameTimeGraph? RenderTimeGraph
=> _renderTimeGraph ??= CreateTimeGraph("Render");

private FrameTimeGraph? UpdateTimeGraph
=> _updateTimeGraph ??= CreateTimeGraph("RUpdate");



public bool RequireLayer => DebugOverlays.HasAnyFlag(RendererDebugOverlays.DirtyRects);

Expand Down Expand Up @@ -91,7 +97,17 @@ public void Draw(IDrawingContextImpl targetContext, bool hasLayer)
}
}

public void MarkUpdateCallStart() => _updateStarted = CaptureTiming ? Stopwatch.GetTimestamp() : 0L;
public void MarkUpdateCallStart()
{
if (CaptureTiming)
_updateStarted = CaptureTiming ? Stopwatch.GetTimestamp() : 0L;
}

public void MarkUpdateCallEnd()
{
if (CaptureTiming)
UpdateTimeGraph?.AddFrameValue(StopwatchHelper.GetElapsedTime(_updateStarted).TotalMilliseconds);
}

private void DrawOverlays(ImmediateDrawingContext targetContext, bool hasLayer, Size logicalSize)
{
Expand Down Expand Up @@ -129,7 +145,10 @@ void DrawTimeGraph(FrameTimeGraph? graph)
DrawTimeGraph(LayoutTimeGraph);

if (DebugOverlays.HasFlag(RendererDebugOverlays.RenderTimeGraph))
{
DrawTimeGraph(RenderTimeGraph);
DrawTimeGraph(UpdateTimeGraph);
}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public void Render()
_updateRequested = false;
Readback.CompleteWrite(Revision);

_overlays.MarkUpdateCallEnd();

if (!_redrawRequested)
return;
_redrawRequested = false;
Expand Down
19 changes: 4 additions & 15 deletions src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ internal partial class ServerCompositor : IRenderLoopTask
public Stopwatch Clock { get; } = Stopwatch.StartNew();
public TimeSpan ServerNow { get; private set; }
private readonly List<ServerCompositionTarget> _activeTargets = new();
private readonly HashSet<IServerClockItem> _clockItems = new();
private readonly List<IServerClockItem> _clockItemsToUpdate = new();
internal BatchStreamObjectPool<object?> BatchObjectPool;
internal BatchStreamMemoryPool BatchMemoryPool;
private readonly object _lock = new object();
Expand All @@ -39,12 +37,14 @@ internal partial class ServerCompositor : IRenderLoopTask
internal static readonly object RenderThreadJobsStartMarker = new();
internal static readonly object RenderThreadJobsEndMarker = new();
public CompositionOptions Options { get; }
public ServerCompositorAnimations Animations { get; }

public ServerCompositor(IRenderLoop renderLoop, IPlatformGraphics? platformGraphics,
CompositionOptions options,
BatchStreamObjectPool<object?> batchObjectPool, BatchStreamMemoryPool batchMemoryPool)
{
Options = options;
Animations = new();
_renderLoop = renderLoop;
RenderInterface = new PlatformRenderInterfaceContextManager(platformGraphics);
RenderInterface.ContextDisposed += RT_OnContextDisposed;
Expand Down Expand Up @@ -210,14 +210,9 @@ private void RenderCore(bool catchExceptions)
UpdateServerTime();
ApplyPendingBatches();
NotifyBatchesProcessed();

foreach(var animation in _clockItems)
_clockItemsToUpdate.Add(animation);

foreach (var animation in _clockItemsToUpdate)
animation.OnTick();

_clockItemsToUpdate.Clear();
Animations.Process();


ApplyEnqueuedRenderResourceChanges();

Expand All @@ -244,12 +239,6 @@ public void RemoveCompositionTarget(ServerCompositionTarget target)
_activeTargets.Remove(target);
}

public void AddToClock(IServerClockItem item) =>
_clockItems.Add(item);

public void RemoveFromClock(IServerClockItem item) =>
_clockItems.Remove(item);

public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
{
using (RenderInterface.EnsureCurrent())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Collections.Generic;

namespace Avalonia.Rendering.Composition.Server;

internal class ServerCompositorAnimations
{
private readonly HashSet<IServerClockItem> _clockItems = new();
private readonly List<IServerClockItem> _clockItemsToUpdate = new();
private readonly HashSet<ServerObjectAnimations> _dirtyAnimatedObjects = new();
private readonly Queue<ServerObjectAnimations> _dirtyAnimatedObjectQueue = new();

public void AddToClock(IServerClockItem item) =>
_clockItems.Add(item);

public void RemoveFromClock(IServerClockItem item) =>
_clockItems.Remove(item);

public void Process()
{
foreach (var animation in _clockItems)
_clockItemsToUpdate.Add(animation);

foreach (var animation in _clockItemsToUpdate)
animation.OnTick();

_clockItemsToUpdate.Clear();

while (_dirtyAnimatedObjectQueue.Count > 0)
_dirtyAnimatedObjectQueue.Dequeue().EvaluateAnimations();
_dirtyAnimatedObjects.Clear();
}

public void AddDirtyAnimatedObject(ServerObjectAnimations obj)
{
if (_dirtyAnimatedObjects.Add(obj))
_dirtyAnimatedObjectQueue.Enqueue(obj);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ public void OnTick()
_wantsNextAnimationFrameAfterTick = false;
_handler.OnAnimationFrameUpdate();
if (!_wantsNextAnimationFrameAfterTick)
Compositor.RemoveFromClock(this);
Compositor.Animations.RemoveFromClock(this);
}

public override Rect OwnContentBounds => _handler.GetRenderBounds();

protected override void OnAttachedToRoot(ServerCompositionTarget target)
{
if (_wantsNextAnimationFrameAfterTick)
Compositor.AddToClock(this);
Compositor.Animations.AddToClock(this);
base.OnAttachedToRoot(target);
}

protected override void OnDetachedFromRoot(ServerCompositionTarget target)
{
Compositor.RemoveFromClock(this);
Compositor.Animations.RemoveFromClock(this);
base.OnDetachedFromRoot(target);
}

Expand All @@ -67,7 +67,7 @@ internal void HandlerRegisterForNextAnimationFrameUpdate()
{
_wantsNextAnimationFrameAfterTick = true;
if (Root != null)
Compositor.AddToClock(this);
Compositor.Animations.AddToClock(this);
}

protected override void RenderCore(CompositorDrawingContextProxy canvas, Rect currentTransformedClip,
Expand Down
Loading

0 comments on commit 12b6244

Please sign in to comment.