Browse Source

Reworked immediate renderer.

It now doesn't use the render loop, but instead invalidates the window
and reacts to paint events.
Steven Kirk 8 years ago
parent
commit
289fa47304

+ 48 - 65
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
     /// </remarks>
     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<ArgumentNullException>(root != null);
-            Contract.Requires<ArgumentNullException>(renderLoop != null);
-
-            _root = root;
-            _renderLoop = renderLoop;
-            _renderLoop.Tick += OnRenderLoopTick;
-        }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="ImmediateRenderer"/> class.
         /// </summary>
         /// <param name="root">The control to render.</param>
-        private ImmediateRenderer(IVisual root)
+        public ImmediateRenderer(IVisual root)
         {
             Contract.Requires<ArgumentNullException>(root != null);
 
             _root = root;
+            _renderRoot = root as IRenderRoot;
         }
 
         /// <inheritdoc/>
         public bool DrawFps { get; set; }
 
-        /// <summary>
-        /// Gets or sets a value indicating whether the renderer should a visual representation
-        /// of its dirty rectangles. Not currently supported in <see cref="ImmediateRenderer"/>.
-        /// </summary>
+        /// <inheritdoc/>
         public bool DrawDirtyRects { get; set; }
 
         /// <inheritdoc/>
         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;
+            }
         }
 
         /// <inheritdoc/>
@@ -98,7 +117,16 @@ namespace Avalonia.Rendering
         /// <inheritdoc/>
         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);
+                }
+            }
         }
 
         /// <summary>
@@ -106,10 +134,6 @@ namespace Avalonia.Rendering
         /// </summary>
         public void Dispose()
         {
-            if (_renderLoop != null)
-            {
-                _renderLoop.Tick -= OnRenderLoopTick;
-            }
         }
 
         /// <inheritdoc/>
@@ -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());
-            }
-        }
     }
 }

+ 1 - 1
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
             {

+ 1 - 2
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);
                     }