Browse Source

Merge branch 'master' into logical-extensions

pull/3869/head
Dariusz Komosiński 7 years ago
committed by GitHub
parent
commit
78b8e66b9a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  2. 9
      src/Avalonia.Visuals/Rendering/RendererBase.cs
  3. 2
      tests/Avalonia.RenderTests/TestBase.cs

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

@ -35,6 +35,7 @@ namespace Avalonia.Rendering
private IRef<IDrawOperation> _currentDraw; private IRef<IDrawOperation> _currentDraw;
private readonly IDeferredRendererLock _lock; private readonly IDeferredRendererLock _lock;
private readonly object _sceneLock = new object(); private readonly object _sceneLock = new object();
private readonly Action _updateSceneIfNeededDelegate;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DeferredRenderer"/> class. /// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
@ -49,7 +50,7 @@ namespace Avalonia.Rendering
IRenderLoop renderLoop, IRenderLoop renderLoop,
ISceneBuilder sceneBuilder = null, ISceneBuilder sceneBuilder = null,
IDispatcher dispatcher = null, IDispatcher dispatcher = null,
IDeferredRendererLock rendererLock = null) IDeferredRendererLock rendererLock = null) : base(true)
{ {
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -59,6 +60,7 @@ namespace Avalonia.Rendering
Layers = new RenderLayers(); Layers = new RenderLayers();
_renderLoop = renderLoop; _renderLoop = renderLoop;
_lock = rendererLock ?? new ManagedDeferredRendererLock(); _lock = rendererLock ?? new ManagedDeferredRendererLock();
_updateSceneIfNeededDelegate = UpdateSceneIfNeeded;
} }
/// <summary> /// <summary>
@ -73,7 +75,7 @@ namespace Avalonia.Rendering
public DeferredRenderer( public DeferredRenderer(
IVisual root, IVisual root,
IRenderTarget renderTarget, IRenderTarget renderTarget,
ISceneBuilder sceneBuilder = null) ISceneBuilder sceneBuilder = null) : base(true)
{ {
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
Contract.Requires<ArgumentNullException>(renderTarget != null); Contract.Requires<ArgumentNullException>(renderTarget != null);
@ -83,6 +85,7 @@ namespace Avalonia.Rendering
_sceneBuilder = sceneBuilder ?? new SceneBuilder(); _sceneBuilder = sceneBuilder ?? new SceneBuilder();
Layers = new RenderLayers(); Layers = new RenderLayers();
_lock = new ManagedDeferredRendererLock(); _lock = new ManagedDeferredRendererLock();
_updateSceneIfNeededDelegate = UpdateSceneIfNeeded;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -261,7 +264,8 @@ namespace Avalonia.Rendering
try try
{ {
var (scene, updated) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context); var (scene, updated) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context);
if (updated)
FpsTick();
using (scene) using (scene)
{ {
if (scene?.Item != null) if (scene?.Item != null)
@ -318,17 +322,25 @@ namespace Avalonia.Rendering
_lastSceneId = scene.Generation; _lastSceneId = scene.Generation;
var isUiThread = Dispatcher.UIThread.CheckAccess();
// We have consumed the previously available scene, but there might be some dirty // We have consumed the previously available scene, but there might be some dirty
// rects since the last update. *If* we are on UI thread, we can force immediate scene // rects since the last update. *If* we are on UI thread, we can force immediate scene
// rebuild before rendering anything on-screen // rebuild before rendering anything on-screen
// We are calling the same method recursively here // We are calling the same method recursively here
if (!recursiveCall && Dispatcher.UIThread.CheckAccess() && NeedsUpdate) if (!recursiveCall && isUiThread && NeedsUpdate)
{ {
UpdateScene(); UpdateScene();
var (rs, _) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context, true); var (rs, _) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context, true);
return (rs, true); return (rs, true);
} }
// We are rendering a new scene version, so it's highly likely
// that there is already a pending update for animations
// So we are scheduling an update call so UI thread could prepare a scene before
// the next render timer tick
if (!recursiveCall && !isUiThread)
Dispatcher.UIThread.Post(_updateSceneIfNeededDelegate, DispatcherPriority.Render);
// Indicate that we have updated the layers // Indicate that we have updated the layers
return (sceneRef.Clone(), true); return (sceneRef.Clone(), true);
} }
@ -534,6 +546,12 @@ namespace Avalonia.Rendering
context = RenderTarget.CreateDrawingContext(this); context = RenderTarget.CreateDrawingContext(this);
} }
private void UpdateSceneIfNeeded()
{
if(NeedsUpdate)
UpdateScene();
}
private void UpdateScene() private void UpdateScene()
{ {
Dispatcher.UIThread.VerifyAccess(); Dispatcher.UIThread.VerifyAccess();

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

@ -7,6 +7,7 @@ namespace Avalonia.Rendering
{ {
public class RendererBase public class RendererBase
{ {
private readonly bool _useManualFpsCounting;
private static int s_fontSize = 18; private static int s_fontSize = 18;
private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private int _framesThisSecond; private int _framesThisSecond;
@ -14,8 +15,9 @@ namespace Avalonia.Rendering
private FormattedText _fpsText; private FormattedText _fpsText;
private TimeSpan _lastFpsUpdate; private TimeSpan _lastFpsUpdate;
public RendererBase() public RendererBase(bool useManualFpsCounting = false)
{ {
_useManualFpsCounting = useManualFpsCounting;
_fpsText = new FormattedText _fpsText = new FormattedText
{ {
Typeface = FontManager.Current?.GetOrAddTypeface(FontFamily.Default), Typeface = FontManager.Current?.GetOrAddTypeface(FontFamily.Default),
@ -23,12 +25,15 @@ namespace Avalonia.Rendering
}; };
} }
protected void FpsTick() => _framesThisSecond++;
protected void RenderFps(IDrawingContextImpl context, Rect clientRect, int? layerCount) protected void RenderFps(IDrawingContextImpl context, Rect clientRect, int? layerCount)
{ {
var now = _stopwatch.Elapsed; var now = _stopwatch.Elapsed;
var elapsed = now - _lastFpsUpdate; var elapsed = now - _lastFpsUpdate;
++_framesThisSecond; if (!_useManualFpsCounting)
++_framesThisSecond;
if (elapsed.TotalSeconds > 1) if (elapsed.TotalSeconds > 1)
{ {

2
tests/Avalonia.RenderTests/TestBase.cs

@ -184,7 +184,7 @@ namespace Avalonia.Direct2D1.RenderTests
public void Signal(DispatcherPriority prio) public void Signal(DispatcherPriority prio)
{ {
throw new NotImplementedException(); // No-op
} }
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick) public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)

Loading…
Cancel
Save