Browse Source

Fix opacity (and other composition-affected properties) invalidation

pull/8105/head
Nikita Tsukanov 4 years ago
parent
commit
7d0651f643
  1. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawListVisual.cs
  2. 2
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs
  3. 73
      src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs

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

@ -29,7 +29,7 @@ internal class ServerCompositionDrawListVisual : ServerCompositionContainerVisua
Rect? _contentBounds; Rect? _contentBounds;
public override Rect ContentBounds public override Rect OwnContentBounds
{ {
get get
{ {

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

@ -191,7 +191,7 @@ namespace Avalonia.Rendering.Composition.Server
if (_attachedVisuals.Remove(visual) && IsEnabled) if (_attachedVisuals.Remove(visual) && IsEnabled)
visual.Deactivate(); visual.Deactivate();
if(visual.IsVisibleInFrame) if(visual.IsVisibleInFrame)
AddDirtyRect(visual.TransformedBounds); AddDirtyRect(visual.TransformedOwnContentBounds);
} }
public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual); public void EnqueueAdornerUpdate(ServerCompositionVisual visual) => _adornerUpdateQueue.Enqueue(visual);

73
src/Avalonia.Base/Rendering/Composition/Server/ServerVisual.cs

@ -1,4 +1,6 @@
using System;
using System.Numerics; using System.Numerics;
using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering.Composition.Transport; using Avalonia.Rendering.Composition.Transport;
@ -13,6 +15,8 @@ namespace Avalonia.Rendering.Composition.Server
partial class ServerCompositionVisual : ServerObject partial class ServerCompositionVisual : ServerObject
{ {
private bool _isDirty; private bool _isDirty;
private bool _isDirtyComposition;
private CompositionProperties _oldCompositionProperties;
private bool _isBackface; private bool _isBackface;
protected virtual void RenderCore(CompositorDrawingContextProxy canvas) protected virtual void RenderCore(CompositorDrawingContextProxy canvas)
{ {
@ -21,7 +25,8 @@ namespace Avalonia.Rendering.Composition.Server
public void Render(CompositorDrawingContextProxy canvas) public void Render(CompositorDrawingContextProxy canvas)
{ {
if(Visible == false) _isDirtyComposition = false;
if(Visible == false || IsVisibleInFrame == false)
return; return;
if(Opacity == 0) if(Opacity == 0)
return; return;
@ -38,7 +43,6 @@ namespace Avalonia.Rendering.Composition.Server
if(OpacityMaskBrush != null) if(OpacityMaskBrush != null)
canvas.PushOpacityMask(OpacityMaskBrush, boundsRect); canvas.PushOpacityMask(OpacityMaskBrush, boundsRect);
//TODO: Check clip
RenderCore(canvas); RenderCore(canvas);
// Hack to force invalidation of SKMatrix // Hack to force invalidation of SKMatrix
@ -93,30 +97,34 @@ namespace Avalonia.Rendering.Composition.Server
} }
var wasVisible = IsVisibleInFrame; var wasVisible = IsVisibleInFrame;
//TODO: check effective opacity too
IsVisibleInFrame = Visible && Opacity > 0 && !_isBackface; EffectiveOpacity = Opacity * (Parent?.EffectiveOpacity ?? 1);
IsVisibleInFrame = Visible && EffectiveOpacity > 0.04 && !_isBackface;
// Invalidate previous rect and queue new rect based on visibility // Invalidate previous rect and queue new rect based on visibility
if (positionChanged) if (positionChanged)
{ {
if(wasVisible) if(wasVisible)
Root!.AddDirtyRect(TransformedBounds); Root!.AddDirtyRect(TransformedOwnContentBounds);
if (IsVisibleInFrame) if (IsVisibleInFrame)
_isDirty = true; _isDirty = true;
} }
if (wasVisible != IsVisibleInFrame)
_isDirty = true;
if (_parent.Value?._isDirtyComposition == true)
_isDirty = true;
GlobalTransformMatrix = newTransform; GlobalTransformMatrix = newTransform;
//TODO: Cache //TODO: Cache
TransformedBounds = ContentBounds.TransformToAABB(MatrixUtils.ToMatrix(GlobalTransformMatrix)); TransformedOwnContentBounds = OwnContentBounds.TransformToAABB(MatrixUtils.ToMatrix(GlobalTransformMatrix));
if (!IsVisibleInFrame) if (IsVisibleInFrame && _isDirty)
_isDirty = false; Root!.AddDirtyRect(TransformedOwnContentBounds);
else if (_isDirty)
{ _isDirty = false;
Root!.AddDirtyRect(TransformedBounds);
_isDirty = false;
}
// Update readback indices // Update readback indices
var i = Root!.Readback; var i = Root!.Readback;
@ -126,6 +134,14 @@ namespace Avalonia.Rendering.Composition.Server
readback.TargetId = Root.Id; readback.TargetId = Root.Id;
readback.Visible = IsVisibleInFrame; readback.Visible = IsVisibleInFrame;
// Forcefully mark any children visuals are dirty if any of the composition
// properties were changed since the last update
var newProps = GetCompositionProperties();
if (!newProps.Equals(_oldCompositionProperties))
{
_isDirtyComposition = true;
_oldCompositionProperties = newProps;
}
} }
/// <summary> /// <summary>
@ -160,13 +176,38 @@ namespace Avalonia.Rendering.Composition.Server
{ {
_isDirty = true; _isDirty = true;
if (IsVisibleInFrame) if (IsVisibleInFrame)
Root?.AddDirtyRect(TransformedBounds); Root?.AddDirtyRect(TransformedOwnContentBounds);
else else
Root?.Invalidate(); Root?.Invalidate();
} }
struct CompositionProperties
{
public double EffectiveOpacity { get; set; }
public Vector2? ClipSize { get; set; }
public IGeometryImpl? Clip { get; set; }
public IBrush? OpacityMaskBrush { get; set; }
public bool Equals(CompositionProperties other) =>
EffectiveOpacity == other.EffectiveOpacity
&& ClipSize == other.ClipSize
&& Clip == other.Clip
&& OpacityMaskBrush == other.OpacityMaskBrush;
}
private CompositionProperties GetCompositionProperties() => new CompositionProperties
{
EffectiveOpacity = EffectiveOpacity,
Clip = Clip,
ClipSize = ClipToBounds ? Size : null,
OpacityMaskBrush = OpacityMaskBrush
};
public bool IsVisibleInFrame { get; set; } public bool IsVisibleInFrame { get; set; }
public Rect TransformedBounds { get; set; } public double EffectiveOpacity { get; set; }
public virtual Rect ContentBounds => new Rect(0, 0, Size.X, Size.Y); public Rect TransformedOwnContentBounds { get; set; }
public virtual Rect OwnContentBounds => new Rect(0, 0, Size.X, Size.Y);
} }

Loading…
Cancel
Save