diff --git a/src/Avalonia.X11/X11ImmediateRendererProxy.cs b/src/Avalonia.X11/X11ImmediateRendererProxy.cs new file mode 100644 index 0000000000..f7bc7f9711 --- /dev/null +++ b/src/Avalonia.X11/X11ImmediateRendererProxy.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using Avalonia.Rendering; +using Avalonia.Threading; +using Avalonia.VisualTree; + +namespace Avalonia.X11 +{ + public class X11ImmediateRendererProxy : IRenderer, IRenderLoopTask + { + private readonly IRenderLoop _loop; + private ImmediateRenderer _renderer; + private bool _invalidated; + private object _lock = new object(); + + public X11ImmediateRendererProxy(IVisual root, IRenderLoop loop) + { + _loop = loop; + _renderer = new ImmediateRenderer(root); + + } + + public void Dispose() + { + _renderer.Dispose(); + } + + public bool DrawFps + { + get => _renderer.DrawFps; + set => _renderer.DrawFps = value; + } + + public bool DrawDirtyRects + { + get => _renderer.DrawDirtyRects; + set => _renderer.DrawDirtyRects = value; + } + + public event EventHandler SceneInvalidated + { + add => _renderer.SceneInvalidated += value; + remove => _renderer.SceneInvalidated -= value; + } + + public void AddDirty(IVisual visual) + { + lock (_lock) + _invalidated = true; + _renderer.AddDirty(visual); + } + + public IEnumerable HitTest(Point p, IVisual root, Func filter) + { + return _renderer.HitTest(p, root, filter); + } + + public IVisual HitTestFirst(Point p, IVisual root, Func filter) + { + return _renderer.HitTestFirst(p, root, filter); + } + + public void RecalculateChildren(IVisual visual) + { + _renderer.RecalculateChildren(visual); + } + + public void Resized(Size size) + { + _renderer.Resized(size); + } + + public void Paint(Rect rect) + { + _invalidated = false; + _renderer.Paint(rect); + } + + public void Start() + { + _loop.Add(this); + _renderer.Start(); + } + + public void Stop() + { + _loop.Remove(this); + _renderer.Stop(); + } + + public bool NeedsUpdate => false; + public void Update(TimeSpan time) + { + + } + + public void Render() + { + if (_invalidated) + { + lock (_lock) + _invalidated = false; + Dispatcher.UIThread.Post(() => Paint(new Rect(0, 0, 100000, 100000))); + } + } + } +} diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 8b531bd9c5..028c47c978 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -96,6 +96,7 @@ namespace Avalonia public bool UseGpu { get; set; } = true; public bool OverlayPopups { get; set; } public bool UseDBusMenu { get; set; } + public bool UseDeferredRendering { get; set; } = true; public List GlxRendererBlacklist { get; set; } = new List { diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index f56bb48f0f..60fd0346a3 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -27,7 +27,6 @@ namespace Avalonia.X11 private readonly IWindowImpl _popupParent; private readonly bool _popup; private readonly X11Info _x11; - private bool _invalidated; private XConfigureEvent? _configure; private PixelPoint? _configurePoint; private bool _triggeredExpose; @@ -309,8 +308,13 @@ namespace Avalonia.X11 public Action Closed { get; set; } public Action PositionChanged { get; set; } - public IRenderer CreateRenderer(IRenderRoot root) => - new DeferredRenderer(root, AvaloniaLocator.Current.GetService()); + public IRenderer CreateRenderer(IRenderRoot root) + { + var loop = AvaloniaLocator.Current.GetService(); + return _platform.Options.UseDeferredRendering ? + new DeferredRenderer(root, loop) : + (IRenderer)new X11ImmediateRendererProxy(root, loop); + } void OnEvent(XEvent ev) { @@ -684,20 +688,12 @@ namespace Avalonia.X11 void DoPaint() { - _invalidated = false; Paint?.Invoke(new Rect()); } public void Invalidate(Rect rect) { - if(_invalidated) - return; - _invalidated = true; - Dispatcher.UIThread.InvokeAsync(() => - { - if (_mapped) - DoPaint(); - }); + } public IInputRoot InputRoot => _inputRoot;