Browse Source

Merge pull request #2092 from AvaloniaUI/deferred-renderer-forced-frame

Enforce DeferredRenderer to produce a frame when requested by OS
pull/2107/head
Nikita Tsukanov 8 years ago
committed by GitHub
parent
commit
4607d47937
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs
  2. 108
      src/Avalonia.Native/DeferredRendererProxy.cs
  3. 8
      src/Avalonia.Native/WindowImplBase.cs
  4. 26
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  5. 9
      src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs
  6. 17
      src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs
  7. 2
      src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs
  8. 9
      src/Windows/Avalonia.Win32/Win32Platform.cs
  9. 1
      src/Windows/Avalonia.Win32/WindowImpl.cs

23
src/Avalonia.Native/AvaloniaNativeDeferredRendererLock.cs

@ -0,0 +1,23 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Native.Interop;
using Avalonia.Rendering;
namespace Avalonia.Native
{
public class AvaloniaNativeDeferredRendererLock : IDeferredRendererLock
{
private readonly IAvnWindowBase _window;
public AvaloniaNativeDeferredRendererLock(IAvnWindowBase window)
{
_window = window;
}
public IDisposable TryLock()
{
if (_window.TryLock())
return Disposable.Create(() => _window.Unlock());
return null;
}
}
}

108
src/Avalonia.Native/DeferredRendererProxy.cs

@ -1,108 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Native.Interop;
using Avalonia.Rendering;
using Avalonia.VisualTree;
namespace Avalonia.Native
{
public class DeferredRendererProxy : IRenderer, IRenderLoopTask, IRenderLoop
{
public DeferredRendererProxy(IRenderRoot root, IAvnWindowBase window)
{
if (window != null)
{
_useLock = true;
window.AddRef();
_window = new IAvnWindowBase(window.NativePointer);
}
_renderer = new DeferredRenderer(root, this);
_rendererTask = (IRenderLoopTask)_renderer;
}
void IRenderLoop.Add(IRenderLoopTask i)
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Add(this);
}
void IRenderLoop.Remove(IRenderLoopTask i)
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Remove(this);
}
private DeferredRenderer _renderer;
private IRenderLoopTask _rendererTask;
private IAvnWindowBase _window;
private bool _useLock;
public bool DrawFps{
get => _renderer.DrawFps;
set => _renderer.DrawFps = value;
}
public bool DrawDirtyRects
{
get => _renderer.DrawDirtyRects;
set => _renderer.DrawDirtyRects = value;
}
public bool NeedsUpdate => _rendererTask.NeedsUpdate;
public void AddDirty(IVisual visual) => _renderer.AddDirty(visual);
public void Dispose()
{
_renderer.Dispose();
_window?.Dispose();
_window = null;
}
public IEnumerable<IVisual> HitTest(Point p, IVisual root, Func<IVisual, bool> filter)
{
return _renderer.HitTest(p, root, filter);
}
public void Paint(Rect rect)
{
if (NeedsUpdate)
{
Update(TimeSpan.FromMilliseconds(Environment.TickCount));
}
Render();
}
public void Resized(Size size) => _renderer.Resized(size);
public void Start() => _renderer.Start();
public void Stop() => _renderer.Stop();
public void Update(TimeSpan time)
{
_rendererTask.Update(time);
}
public void Render()
{
if(_useLock)
{
_rendererTask.Render();
return;
}
if (_window == null)
return;
if (!_window.TryLock())
return;
try
{
_rendererTask.Render();
}
finally
{
_window.Unlock();
}
}
}
}

8
src/Avalonia.Native/WindowImplBase.cs

@ -186,10 +186,6 @@ namespace Avalonia.Native
void IAvnWindowBaseEvents.RunRenderPriorityJobs()
{
if (_parent._deferredRendering
&& _parent._lastRenderedLogicalSize != _parent.ClientSize)
// Hack to trigger Paint event on the renderer
_parent.Paint?.Invoke(new Rect());
Dispatcher.UIThread.RunJobs(DispatcherPriority.Render);
}
}
@ -245,7 +241,9 @@ namespace Avalonia.Native
public IRenderer CreateRenderer(IRenderRoot root)
{
if (_deferredRendering)
return new DeferredRendererProxy(root, _gpu ? _native : null);
return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>(),
rendererLock:
_gpu ? new AvaloniaNativeDeferredRendererLock(_native) : null);
return new ImmediateRenderer(root);
}

26
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -36,6 +36,7 @@ namespace Avalonia.Rendering
private int _lastSceneId = -1;
private DisplayDirtyRects _dirtyRectsDisplay = new DisplayDirtyRects();
private IRef<IDrawOperation> _currentDraw;
private readonly IDeferredRendererLock _lock;
/// <summary>
/// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
@ -44,11 +45,13 @@ namespace Avalonia.Rendering
/// <param name="renderLoop">The render loop.</param>
/// <param name="sceneBuilder">The scene builder to use. Optional.</param>
/// <param name="dispatcher">The dispatcher to use. Optional.</param>
/// <param name="rendererLock">Lock object used before trying to access render target</param>
public DeferredRenderer(
IRenderRoot root,
IRenderLoop renderLoop,
ISceneBuilder sceneBuilder = null,
IDispatcher dispatcher = null)
IDispatcher dispatcher = null,
IDeferredRendererLock rendererLock = null)
{
Contract.Requires<ArgumentNullException>(root != null);
@ -57,6 +60,7 @@ namespace Avalonia.Rendering
_sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers();
_renderLoop = renderLoop;
_lock = rendererLock ?? new ManagedDeferredRendererLock();
}
/// <summary>
@ -137,6 +141,10 @@ namespace Avalonia.Rendering
/// <inheritdoc/>
public void Paint(Rect rect)
{
var t = (IRenderLoopTask)this;
if(t.NeedsUpdate)
UpdateScene();
t.Render();
}
/// <inheritdoc/>
@ -170,10 +178,9 @@ namespace Avalonia.Rendering
void IRenderLoopTask.Render()
{
using (var scene = _scene?.Clone())
{
Render(scene?.Item);
}
using (var l = _lock.TryLock())
if (l != null)
Render();
}
/// <inheritdoc/>
@ -197,6 +204,14 @@ namespace Avalonia.Rendering
internal void UnitTestRender() => Render(_scene.Item);
private void Render()
{
using (var scene = _scene?.Clone())
{
Render(scene?.Item);
}
}
private void Render(Scene scene)
{
bool renderOverlay = DrawDirtyRects || DrawFps;
@ -415,7 +430,6 @@ namespace Avalonia.Rendering
oldScene?.Dispose();
_dirty.Clear();
(_root as IRenderRoot)?.Invalidate(new Rect(scene.Size));
}
else
{

9
src/Avalonia.Visuals/Rendering/IDeferredRendererLock.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.Rendering
{
public interface IDeferredRendererLock
{
IDisposable TryLock();
}
}

17
src/Avalonia.Visuals/Rendering/ManagedDeferredRendererLock.cs

@ -0,0 +1,17 @@
using System;
using System.Reactive.Disposables;
using System.Threading;
namespace Avalonia.Rendering
{
public class ManagedDeferredRendererLock : IDeferredRendererLock
{
private readonly object _lock = new object();
public IDisposable TryLock()
{
if (Monitor.TryEnter(_lock))
return Disposable.Create(() => Monitor.Exit(_lock));
return null;
}
}
}

2
src/Gtk/Avalonia.Gtk3/WindowBaseImpl.cs

@ -265,6 +265,8 @@ namespace Avalonia.Gtk3
Paint?.Invoke(new Rect(ClientSize));
CurrentCairoContext = IntPtr.Zero;
}
else
Paint?.Invoke(new Rect(ClientSize));
return true;
}

9
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -27,11 +27,11 @@ namespace Avalonia
{
public static T UseWin32<T>(
this T builder,
bool deferredRendering = true)
bool deferredRendering = true, bool allowEgl = false)
where T : AppBuilderBase<T>, new()
{
return builder.UseWindowingSubsystem(
() => Win32.Win32Platform.Initialize(deferredRendering),
() => Win32.Win32Platform.Initialize(deferredRendering, allowEgl),
"Win32");
}
}
@ -66,7 +66,7 @@ namespace Avalonia.Win32
Initialize(true);
}
public static void Initialize(bool deferredRendering = true)
public static void Initialize(bool deferredRendering = true, bool allowEgl = false)
{
AvaloniaLocator.CurrentMutable
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
@ -80,7 +80,8 @@ namespace Avalonia.Win32
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformIconLoader>().ToConstant(s_instance);
Win32GlManager.Initialize();
if (allowEgl)
Win32GlManager.Initialize();
UseDeferredRendering = deferredRendering;
_uiThread = Thread.CurrentThread;

1
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -633,7 +633,6 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_PAINT:
UnmanagedMethods.PAINTSTRUCT ps;
if (UnmanagedMethods.BeginPaint(_hwnd, out ps) != IntPtr.Zero)
{
var f = Scaling;

Loading…
Cancel
Save