Browse Source

Properly fixed DrawingContextProxy transform tracking (#17101)

pull/17107/head
Nikita Tsukanov 1 year ago
committed by GitHub
parent
commit
7f208d0bde
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 35
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs
  2. 63
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

35
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs

@ -88,19 +88,21 @@ internal partial class CompositorDrawingContextProxy
}
private bool TryDiscard(PendingCommandType type)
private bool TryDiscardOrFlush(PendingCommandType type)
{
while (_commands.Count > 0 && _commands[_commands.Count - 1].Type == PendingCommandType.SetTransform)
_commands.RemoveAt(_commands.Count - 1);
if (_commands.Count == 0)
return false;
if (_commands[_commands.Count - 1].Type == type)
for (var c = _commands.Count - 1; c >= 0; c--)
{
_commands.RemoveAt(_commands.Count - 1);
return true;
if(_commands[c].Type == PendingCommandType.SetTransform)
continue;
if (_commands[c].Type == type)
{
_commands.RemoveRange(c, _commands.Count - c);
return true;
}
break;
}
// Not sure how exactly can we get here, but flush commands just in case
// We've failed to collapse PushX,SetTransform,PopX stack, so we need to execute any pending commands
Flush();
return false;
}
@ -116,8 +118,13 @@ internal partial class CompositorDrawingContextProxy
void ExecCommand(ref PendingCommand cmd)
{
if (cmd.Type == PendingCommandType.SetTransform)
{
SetImplTransform(cmd.DataUnion.Transform);
else if (cmd.Type == PendingCommandType.PushOpacity)
return;
}
SaveTransform();
if (cmd.Type == PendingCommandType.PushOpacity)
_impl.PushOpacity(cmd.DataUnion.Opacity, cmd.DataUnion.NullableOpacityRect);
else if (cmd.Type == PendingCommandType.PushOpacityMask)
_impl.PushOpacityMask(cmd.ObjectUnion.Mask!, cmd.DataUnion.NormalRect);
@ -148,10 +155,6 @@ internal partial class CompositorDrawingContextProxy
ExecCommand(ref commands[index]);
_commands.Clear();
if (Transform != _impl.Transform)
{
_impl.Transform = Transform;
}
}
}

63
src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Numerics;
using Avalonia.Media;
using Avalonia.Media.Imaging;
@ -6,6 +8,7 @@ using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.Rendering.Composition.Drawing;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
using Avalonia.Utilities;
namespace Avalonia.Rendering.Composition.Server;
@ -14,6 +17,8 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
IDrawingContextWithAcrylicLikeSupport, IDrawingContextImplWithEffects
{
private readonly IDrawingContextImpl _impl;
private static readonly ThreadSafeObjectPool<Stack<Matrix>> s_transformStackPool = new();
private Stack<Matrix>? _transformStack = s_transformStackPool.Get();
public CompositorDrawingContextProxy(IDrawingContextImpl impl)
{
@ -24,29 +29,46 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
{
Flush();
_commands.Dispose();
if (_transformStack != null)
{
Debug.Assert(_transformStack.Count == 0);
_transformStack.Clear();
}
s_transformStackPool.ReturnAndSetNull(ref _transformStack);
}
public Matrix? PostTransform { get; set; }
Matrix _transform;
// Transform that was most recently passed to set_Transform or restored by a PopXXX operation
// We use it to report the transform that would correspond to the current state if all commands were executed
Matrix _reportedTransform = Matrix.Identity;
// Transform that was most recently passed to SetImplTransform or restored by a PopXXX operation
// We use it to save the effective transform before executing a Push operation
Matrix _effectiveTransform = Matrix.Identity;
public Matrix Transform
{
get => _transform;
get => _reportedTransform;
set
{
_transform = value;
_reportedTransform = value;
SetTransform(value);
}
}
void SetImplTransform(Matrix m)
{
_transform = m;
_effectiveTransform = m;
if (PostTransform.HasValue)
m = m * PostTransform.Value;
_impl.Transform = m;
}
void SaveTransform() => _transformStack!.Push(_effectiveTransform);
void RestoreTransform() => _reportedTransform = _effectiveTransform = _transformStack!.Pop();
public void Clear(Color color)
{
Flush();
@ -139,8 +161,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopClip()
{
if (!TryDiscard(PendingCommandType.PushClip))
if (!TryDiscardOrFlush(PendingCommandType.PushClip))
{
_impl.PopClip();
RestoreTransform();
}
}
public void PushLayer(Rect bounds)
@ -170,8 +195,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopOpacity()
{
if (!TryDiscard(PendingCommandType.PushOpacity))
if (!TryDiscardOrFlush(PendingCommandType.PushOpacity))
{
_impl.PopOpacity();
RestoreTransform();
}
}
public void PushOpacityMask(IBrush mask, Rect bounds)
@ -192,8 +220,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopOpacityMask()
{
if (!TryDiscard(PendingCommandType.PushOpacityMask))
if (!TryDiscardOrFlush(PendingCommandType.PushOpacityMask))
{
_impl.PopOpacityMask();
RestoreTransform();
}
}
public void PushGeometryClip(IGeometryImpl clip)
@ -210,8 +241,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopGeometryClip()
{
if (!TryDiscard(PendingCommandType.PushGeometryClip))
if (!TryDiscardOrFlush(PendingCommandType.PushGeometryClip))
{
_impl.PopGeometryClip();
RestoreTransform();
}
}
public void PushRenderOptions(RenderOptions renderOptions)
@ -228,8 +262,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopRenderOptions()
{
if (!TryDiscard(PendingCommandType.PushRenderOptions))
if (!TryDiscardOrFlush(PendingCommandType.PushRenderOptions))
{
_impl.PopRenderOptions();
RestoreTransform();
}
}
public object? GetFeature(Type t)
@ -262,7 +299,11 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
public void PopEffect()
{
if (!TryDiscard(PendingCommandType.PushEffect) && _impl is IDrawingContextImplWithEffects effects)
effects.PopEffect();
if (!TryDiscardOrFlush(PendingCommandType.PushEffect))
{
if (_impl is IDrawingContextImplWithEffects effects)
effects.PopEffect();
RestoreTransform();
}
}
}

Loading…
Cancel
Save