|
|
@@ -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());
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|