Browse Source

Improve effect render performance by providing Skia with information about subscene bounds (#20191)

* Improve effect render performance by providing Skia with information about subscene bounds

* Fixed test

* apidiff

* Update API diff

---------

Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
release/11.3.10
Nikita Tsukanov 2 months ago
committed by Julien Lebosquain
parent
commit
d88a94bc1c
No known key found for this signature in database GPG Key ID: 1833CAD10ACC46FD
  1. 2
      api/Avalonia.nupkg.xml
  2. 5
      src/Avalonia.Base/Platform/IDrawingContextImpl.cs
  3. 6
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.PendingCommands.cs
  4. 8
      src/Avalonia.Base/Rendering/Composition/Server/DrawingContextProxy.cs
  5. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
  6. 23
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
  7. 7
      src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs

2
api/Avalonia.nupkg.xml

@ -187,4 +187,4 @@
<Left>baseline/netstandard2.0/Avalonia.Controls.dll</Left>
<Right>target/netstandard2.0/Avalonia.Controls.dll</Right>
</Suppression>
</Suppressions>
</Suppressions>

5
src/Avalonia.Base/Platform/IDrawingContextImpl.cs

@ -201,9 +201,10 @@ namespace Avalonia.Platform
object? GetFeature(Type t);
}
public interface IDrawingContextImplWithEffects
[PrivateApi]
public interface IDrawingContextImplWithEffects : IDrawingContextImpl
{
void PushEffect(IEffect effect);
void PushEffect(Rect? clipRect, IEffect effect);
void PopEffect();
}

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

@ -48,6 +48,10 @@ internal partial class CompositorDrawingContextProxy
[FieldOffset(0)] public bool IsRoundRect;
[FieldOffset(4)] public RoundedRect RoundRect;
[FieldOffset(4)] public Rect NormalRect;
// PushEffect
[FieldOffset(0)]
public Rect? EffectClipRect;
}
struct PendingCommand
@ -140,7 +144,7 @@ internal partial class CompositorDrawingContextProxy
else if (cmd.Type == PendingCommandType.PushEffect)
{
if (_impl is IDrawingContextImplWithEffects effects)
effects.PushEffect(cmd.ObjectUnion.Effect!);
effects.PushEffect(cmd.DataUnion.EffectClipRect, cmd.ObjectUnion.Effect!);
}
else if (cmd.Type == PendingCommandType.PushRenderOptions)
_impl.PushRenderOptions(cmd.DataUnion.RenderOptions);

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

@ -285,14 +285,18 @@ internal partial class CompositorDrawingContextProxy : IDrawingContextImpl,
_impl.DrawRectangle(new ImmutableSolidColorBrush(material.FallbackColor), null, rect);
}
public void PushEffect(IEffect effect)
public void PushEffect(Rect? clipRect, IEffect effect)
{
AddCommand(new()
{
Type = PendingCommandType.PushEffect,
ObjectUnion =
{
Effect = effect
Effect = effect,
},
DataUnion =
{
EffectClipRect = clipRect
}
});
}

2
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs

@ -65,6 +65,8 @@ namespace Avalonia.Rendering.Composition.Server
return new(_transformedContentBounds, oldInvalidated, newInvalidated);
}
protected override LtrbRect GetEffectBounds() => _transformedContentBounds ?? default;
void AddEffectPaddedDirtyRect(IImmutableEffect effect, LtrbRect transformedBounds)
{
var padding = effect.GetEffectOutputPadding();

23
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

@ -62,9 +62,8 @@ namespace Avalonia.Rendering.Composition.Server
if (applyRenderOptions)
canvas.PushRenderOptions(RenderOptions);
if (Effect != null)
canvas.PushEffect(Effect);
var needPopEffect = PushEffect(canvas);
if (Opacity != 1)
canvas.PushOpacity(Opacity, ClipToBounds ? boundsRect : null);
if (ClipToBounds && !HandlesClipToBounds)
@ -87,12 +86,28 @@ namespace Avalonia.Rendering.Composition.Server
if (Opacity != 1)
canvas.PopOpacity();
if (Effect != null)
if (needPopEffect)
canvas.PopEffect();
if(applyRenderOptions)
canvas.PopRenderOptions();
}
protected virtual LtrbRect GetEffectBounds() => TransformedOwnContentBounds;
private bool PushEffect(CompositorDrawingContextProxy canvas)
{
if (Effect == null)
return false;
var clip = GetEffectBounds();
if (clip.IsZeroSize)
return false;
var oldMatrix = canvas.Transform;
canvas.Transform = Matrix.Identity;
canvas.PushEffect(GetEffectBounds().ToRect(), Effect!);
canvas.Transform = oldMatrix;
return true;
}
protected virtual bool HandlesClipToBounds => false;
private ReadbackData _readback0, _readback1, _readback2;

7
src/Skia/Avalonia.Skia/DrawingContextImpl.Effects.cs

@ -7,13 +7,16 @@ namespace Avalonia.Skia;
partial class DrawingContextImpl
{
public void PushEffect(IEffect effect)
public void PushEffect(Rect? effectClipRect, IEffect effect)
{
CheckLease();
using var filter = CreateEffect(effect);
var paint = SKPaintCache.Shared.Get();
paint.ImageFilter = filter;
Canvas.SaveLayer(paint);
if (effectClipRect.HasValue)
Canvas.SaveLayer(effectClipRect.Value.ToSKRect(), paint);
else
Canvas.SaveLayer(paint);
SKPaintCache.Shared.ReturnReset(paint);
}

Loading…
Cancel
Save