From 289fa473041bb50649dc1f7fd1a2ac438eb2db35 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 4 Mar 2017 17:06:06 +0100 Subject: [PATCH] Reworked immediate renderer. It now doesn't use the render loop, but instead invalidates the window and reacts to paint events. --- .../Rendering/ImmediateRenderer.cs | 113 ++++++++---------- .../Avalonia.Direct2D1/Direct2D1Platform.cs | 2 +- src/Windows/Avalonia.Win32/WindowImpl.cs | 3 +- 3 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index fae16b129b..d189b91684 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using Avalonia.Threading; using Avalonia.Media; using System.Linq; -using Avalonia.Media.Imaging; namespace Avalonia.Rendering { @@ -22,45 +21,65 @@ namespace Avalonia.Rendering /// public class ImmediateRenderer : RendererBase, IRenderer, IVisualBrushRenderer { - private readonly IRenderLoop _renderLoop; private readonly IVisual _root; + private readonly IRenderRoot _renderRoot; private IRenderTarget _renderTarget; - private bool _dirty = true; - private bool _renderQueued; - - public ImmediateRenderer(IRenderRoot root, IRenderLoop renderLoop) - { - Contract.Requires(root != null); - Contract.Requires(renderLoop != null); - - _root = root; - _renderLoop = renderLoop; - _renderLoop.Tick += OnRenderLoopTick; - } /// /// Initializes a new instance of the class. /// /// The control to render. - private ImmediateRenderer(IVisual root) + public ImmediateRenderer(IVisual root) { Contract.Requires(root != null); _root = root; + _renderRoot = root as IRenderRoot; } /// public bool DrawFps { get; set; } - /// - /// Gets or sets a value indicating whether the renderer should a visual representation - /// of its dirty rectangles. Not currently supported in . - /// + /// public bool DrawDirtyRects { get; set; } /// public void Paint(Rect rect) { + if (_renderTarget == null) + { + _renderTarget = ((IRenderRoot)_root).CreateRenderTarget(this); + } + + try + { + using (var context = new DrawingContext(_renderTarget.CreateDrawingContext(this))) + { + using (context.PushTransformContainer()) + { + Render(context, _root, _root.Bounds); + } + + if (DrawDirtyRects) + { + var color = (uint)new Random().Next(0xffffff) | 0x44000000; + context.FillRectangle( + new SolidColorBrush(color), + rect); + } + + if (DrawFps) + { + RenderFps(context.PlatformImpl, _root.Bounds, true); + } + } + } + catch (RenderTargetCorruptedException ex) + { + Logging.Logger.Information("Renderer", this, "Render target was corrupted. Exception: {0}", ex); + _renderTarget.Dispose(); + _renderTarget = null; + } } /// @@ -98,7 +117,16 @@ namespace Avalonia.Rendering /// public void AddDirty(IVisual visual) { - _dirty = true; + if (visual.Bounds != Rect.Empty) + { + var m = visual.TransformToVisual(_root); + + if (m.HasValue) + { + var bounds = new Rect(visual.Bounds.Size).TransformToAABB(m.Value); + _renderRoot?.Invalidate(bounds); + } + } } /// @@ -106,10 +134,6 @@ namespace Avalonia.Rendering /// public void Dispose() { - if (_renderLoop != null) - { - _renderLoop.Tick -= OnRenderLoopTick; - } } /// @@ -184,38 +208,6 @@ namespace Avalonia.Rendering } } - private void Render() - { - if (_renderTarget == null) - { - _renderTarget = ((IRenderRoot)_root).CreateRenderTarget(this); - } - - try - { - using (var context = new DrawingContext(_renderTarget.CreateDrawingContext(this))) - { - Render(context, _root, _root.Bounds); - - if (DrawFps) - { - RenderFps(context.PlatformImpl, _root.Bounds, true); - } - } - } - catch (RenderTargetCorruptedException ex) - { - Logging.Logger.Information("Renderer", this, "Render target was corrupted. Exception: {0}", ex); - _renderTarget.Dispose(); - _renderTarget = null; - } - finally - { - _dirty = false; - _renderQueued = false; - } - } - private void Render(DrawingContext context, IVisual visual, Rect clipRect) { var opacity = visual.Opacity; @@ -283,14 +275,5 @@ namespace Avalonia.Rendering ClearTransformedBounds(visual); } } - - private void OnRenderLoopTick(object sender, EventArgs e) - { - if ((_dirty || DrawFps) && !_renderQueued) - { - _renderQueued = true; - Dispatcher.UIThread.InvokeAsync(() => Render()); - } - } } } diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index 93c4c0f24f..f3b38eec87 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -118,7 +118,7 @@ namespace Avalonia.Direct2D1 { if (UseImmediateRenderer) { - return new ImmediateRenderer(root, renderLoop); + return new ImmediateRenderer(root); } else { diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0000b5c0a9..f80e62ee2d 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -572,9 +572,8 @@ namespace Avalonia.Win32 if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero) { - UnmanagedMethods.RECT r; - UnmanagedMethods.GetUpdateRect(_hwnd, out r, false); var f = Scaling; + var r = ps.rcPaint; Paint?.Invoke(new Rect(r.left / f, r.top / f, (r.right - r.left) / f, (r.bottom - r.top) / f)); UnmanagedMethods.EndPaint(_hwnd, ref ps); }