From f4f4fc34946e09b19dc57f30dddf22d6424c99c3 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Mon, 4 Mar 2024 17:36:18 +0500 Subject: [PATCH] Various changes --- .../IPlatformRenderInterfaceRegion.cs | 1 + .../Composition/CompositionCustomVisual.cs | 32 +++++++++------ .../CompositionCustomVisualHandler.cs | 41 +++++++------------ .../Composition/Server/DirtyRectTracker.cs | 4 ++ .../ServerCompositionTarget.DirtyRects.cs | 8 ++-- .../Server/ServerCompositionTarget.cs | 18 ++++---- .../Server/ServerCustomCompositionVisual.cs | 13 +++--- src/Skia/Avalonia.Skia/SkiaRegionImpl.cs | 1 + 8 files changed, 60 insertions(+), 58 deletions(-) diff --git a/src/Avalonia.Base/Platform/IPlatformRenderInterfaceRegion.cs b/src/Avalonia.Base/Platform/IPlatformRenderInterfaceRegion.cs index 3e03f71e97..682609391c 100644 --- a/src/Avalonia.Base/Platform/IPlatformRenderInterfaceRegion.cs +++ b/src/Avalonia.Base/Platform/IPlatformRenderInterfaceRegion.cs @@ -13,4 +13,5 @@ public interface IPlatformRenderInterfaceRegion : IDisposable PixelRect Bounds { get; } IList Rects { get; } bool Intersects(Rect rect); + bool Contains(Point pt); } \ No newline at end of file diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs index 1d7887cd0e..79f2cc3fb9 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisual.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; using System.Numerics; +using Avalonia.Media; using Avalonia.Rendering.Composition.Server; using Avalonia.Rendering.Composition.Transport; +using Avalonia.Threading; namespace Avalonia.Rendering.Composition; public sealed class CompositionCustomVisual : CompositionContainerVisual { + private static readonly ThreadSafeObjectPool> s_messageListPool = new(); private List? _messages; internal CompositionCustomVisual(Compositor compositor, CompositionCustomVisualHandler handler) @@ -17,21 +20,26 @@ public sealed class CompositionCustomVisual : CompositionContainerVisual public void SendHandlerMessage(object message) { - (_messages ??= new()).Add(message); - RegisterForSerialization(); + if (_messages == null) + { + _messages = s_messageListPool.Get(); + Compositor.RequestCompositionUpdate(OnCompositionUpdate); + } + _messages.Add(message); } - private protected override void SerializeChangesCore(BatchStreamWriter writer) + private void OnCompositionUpdate() { - base.SerializeChangesCore(writer); - if (_messages == null || _messages.Count == 0) - writer.Write(0); - else + if(_messages == null) + return; + + var messages = _messages; + _messages = null; + Compositor.PostServerJob(()=> { - writer.Write(_messages.Count); - foreach (var m in _messages) - writer.WriteObject(m); - _messages.Clear(); - } + ((ServerCompositionCustomVisual)Server).DispatchMessages(messages); + messages.Clear(); + s_messageListPool.ReturnAndSetNull(ref messages); + }); } } diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs index 13ad6bebdc..638c18af49 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs @@ -10,8 +10,8 @@ namespace Avalonia.Rendering.Composition; public abstract class CompositionCustomVisualHandler { private ServerCompositionCustomVisual? _host; - private PooledList? _dirtyRects; private bool _inRender; + private Rect _currentTransformedClip; public virtual void OnMessage(object message) { @@ -23,9 +23,10 @@ public abstract class CompositionCustomVisualHandler } - internal void Render(ImmediateDrawingContext drawingContext) + internal void Render(ImmediateDrawingContext drawingContext, Rect currentTransformedClip) { _inRender = true; + _currentTransformedClip = currentTransformedClip; try { OnRender(drawingContext); @@ -34,11 +35,8 @@ public abstract class CompositionCustomVisualHandler { _inRender = false; } - - _dirtyRects?.Dispose(); - _dirtyRects = null; } - + public abstract void OnRender(ImmediateDrawingContext drawingContext); void VerifyAccess() @@ -96,26 +94,17 @@ public abstract class CompositionCustomVisualHandler _host!.HandlerRegisterForNextAnimationFrameUpdate(); } - protected IList DirtyRects + protected bool RenderClipContains(Point pt) { - get - { - VerifyInRender(); - - if (_host?.Root == null) - return Array.Empty(); - if (_dirtyRects == null) - { - if (!_host.GlobalTransformMatrix.TryInvert(out var inverted)) - return Array.Empty(); - - _dirtyRects = new(); - foreach (var r in _host.Root.ThisFrameDirtyRects) - { - _dirtyRects.Add(r.ToRectWithDpi(1).TransformToAABB(inverted)); - } - } - return _dirtyRects; - } + VerifyInRender(); + pt *= _host.GlobalTransformMatrix; + return _currentTransformedClip.Contains(pt) && _host.Root.DirtyRects.Contains(pt); + } + + protected bool RenderClipIntersectes(Rect rc) + { + VerifyInRender(); + rc = rc.TransformToAABB(_host.GlobalTransformMatrix); + return _currentTransformedClip.Intersects(rc) && _host.Root.DirtyRects.Intersects(rc); } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/DirtyRectTracker.cs b/src/Avalonia.Base/Rendering/Composition/Server/DirtyRectTracker.cs index 872a28224e..e9b4071d79 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/DirtyRectTracker.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/DirtyRectTracker.cs @@ -14,6 +14,7 @@ internal interface IDirtyRectTracker IDisposable BeginDraw(IDrawingContextImpl ctx); bool IsEmpty { get; } bool Intersects(Rect rect); + bool Contains(Point pt); void Reset(); void Visualize(IDrawingContextImpl context); PixelRect CombinedRect { get; } @@ -40,6 +41,8 @@ internal class DirtyRectTracker : IDirtyRectTracker public bool IsEmpty => _rect.Width == 0 | _rect.Height == 0; public bool Intersects(Rect rect) => _doubleRect.Intersects(rect); + public bool Contains(Point pt) => _rect.Contains(PixelPoint.FromPoint(pt, 1)); + public void Reset() => _rect = default; public void Visualize(IDrawingContextImpl context) { @@ -83,6 +86,7 @@ internal class RegionDirtyRectTracker : IDirtyRectTracker public bool IsEmpty => _region.IsEmpty; public bool Intersects(Rect rect) => _region.Intersects(rect); + public bool Contains(Point pt) => _region.Contains(pt); public void Reset() => _region.Reset(); diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.DirtyRects.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.DirtyRects.cs index 777ece89f1..317452e658 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.DirtyRects.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.DirtyRects.cs @@ -6,7 +6,7 @@ namespace Avalonia.Rendering.Composition.Server; internal partial class ServerCompositionTarget { - private readonly IDirtyRectTracker _dirtyRect; + public readonly IDirtyRectTracker DirtyRects; public void AddDirtyRect(Rect rect) { @@ -14,7 +14,7 @@ internal partial class ServerCompositionTarget return; var snapped = PixelRect.FromRect(SnapToDevicePixels(rect, Scaling), 1); DebugEvents?.RectInvalidated(rect); - _dirtyRect.AddRect(snapped); + DirtyRects.AddRect(snapped); _redrawRequested = true; } @@ -30,6 +30,6 @@ internal partial class ServerCompositionTarget Math.Ceiling(rect.Right * scale) / scale, Math.Ceiling(rect.Bottom * scale) / scale)); } - - public IList ThisFrameDirtyRects => _dirtyRect.Rects; + + } \ No newline at end of file diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs index 853ac8e51b..e39ffc5e7f 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs @@ -57,7 +57,7 @@ namespace Avalonia.Rendering.Composition.Server _surfaces = surfaces; _diagnosticTextRenderer = diagnosticTextRenderer; var platformRender = AvaloniaLocator.Current.GetService(); - _dirtyRect = compositor.Options.UseRegionDirtyRectClipping == true && + DirtyRects = compositor.Options.UseRegionDirtyRectClipping == true && platformRender?.SupportsRegions == true ? new RegionDirtyRectTracker(platformRender) : new DirtyRectTracker(); @@ -151,7 +151,7 @@ namespace Avalonia.Rendering.Composition.Server return; } - if (_dirtyRect.IsEmpty && !_redrawRequested && !_updateRequested) + if (DirtyRects.IsEmpty && !_redrawRequested && !_updateRequested) return; Revision++; @@ -183,23 +183,23 @@ namespace Avalonia.Rendering.Composition.Server _layer = null; _layer = targetContext.CreateLayer(PixelSize); _layerSize = PixelSize; - _dirtyRect.AddRect(new PixelRect(_layerSize)); + DirtyRects.AddRect(new PixelRect(_layerSize)); } - if (!_dirtyRect.IsEmpty) + if (!DirtyRects.IsEmpty) { var useLayerClip = Compositor.Options.UseSaveLayerRootClip ?? Compositor.RenderInterface.GpuContext != null; using (var context = _layer.CreateDrawingContext(false)) { - using (_dirtyRect.BeginDraw(context)) + using (DirtyRects.BeginDraw(context)) { context.Clear(Colors.Transparent); if (useLayerClip) - context.PushLayer(_dirtyRect.CombinedRect.ToRect(1)); + context.PushLayer(DirtyRects.CombinedRect.ToRect(1)); - Root.Render(new CompositorDrawingContextProxy(context), null, _dirtyRect); + Root.Render(new CompositorDrawingContextProxy(context), null, DirtyRects); if (useLayerClip) context.PopLayer(); @@ -230,14 +230,14 @@ namespace Avalonia.Rendering.Composition.Server RenderedVisuals = 0; - _dirtyRect.Reset(); + DirtyRects.Reset(); } } private void DrawOverlays(IDrawingContextImpl targetContext, Size logicalSize) { if ((DebugOverlays & RendererDebugOverlays.DirtyRects) != 0) - _dirtyRect.Visualize(targetContext); + DirtyRects.Visualize(targetContext); targetContext.Transform = Matrix.CreateScale(Scaling, Scaling); diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs index e25e24702e..e7d6fb7599 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCustomCompositionVisual.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Numerics; using Avalonia.Logging; using Avalonia.Media; @@ -16,15 +17,13 @@ internal sealed class ServerCompositionCustomVisual : ServerCompositionContainer _handler.Attach(this); } - protected override void DeserializeChangesCore(BatchStreamReader reader, TimeSpan committedAt) + public void DispatchMessages(List messages) { - base.DeserializeChangesCore(reader, committedAt); - var count = reader.Read(); - for (var c = 0; c < count; c++) + foreach(var message in messages) { try { - _handler.OnMessage(reader.ReadObject()!); + _handler.OnMessage(message); } catch (Exception e) { @@ -33,7 +32,7 @@ internal sealed class ServerCompositionCustomVisual : ServerCompositionContainer } } } - + public void OnTick() { _wantsNextAnimationFrameAfterTick = false; @@ -77,7 +76,7 @@ internal sealed class ServerCompositionCustomVisual : ServerCompositionContainer using var context = new ImmediateDrawingContext(canvas, false); try { - _handler.Render(context); + _handler.Render(context, currentTransformedClip); } catch (Exception e) { diff --git a/src/Skia/Avalonia.Skia/SkiaRegionImpl.cs b/src/Skia/Avalonia.Skia/SkiaRegionImpl.cs index 1b8060ba5b..317cd932aa 100644 --- a/src/Skia/Avalonia.Skia/SkiaRegionImpl.cs +++ b/src/Skia/Avalonia.Skia/SkiaRegionImpl.cs @@ -49,4 +49,5 @@ internal class SkiaRegionImpl : IPlatformRenderInterfaceRegion } public bool Intersects(Rect rect) => Region.Intersects(PixelRect.FromRect(rect, 1).ToSKRectI()); + public bool Contains(Point pt) => Region.Contains((int)pt.X, (int)pt.Y); } \ No newline at end of file