|
|
|
@ -35,6 +35,7 @@ namespace Avalonia.Rendering |
|
|
|
private IRef<IDrawOperation> _currentDraw; |
|
|
|
private readonly IDeferredRendererLock _lock; |
|
|
|
private readonly object _sceneLock = new object(); |
|
|
|
private readonly Action _updateSceneIfNeededDelegate; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Initializes a new instance of the <see cref="DeferredRenderer"/> class.
|
|
|
|
@ -49,7 +50,7 @@ namespace Avalonia.Rendering |
|
|
|
IRenderLoop renderLoop, |
|
|
|
ISceneBuilder sceneBuilder = null, |
|
|
|
IDispatcher dispatcher = null, |
|
|
|
IDeferredRendererLock rendererLock = null) |
|
|
|
IDeferredRendererLock rendererLock = null) : base(true) |
|
|
|
{ |
|
|
|
Contract.Requires<ArgumentNullException>(root != null); |
|
|
|
|
|
|
|
@ -59,6 +60,7 @@ namespace Avalonia.Rendering |
|
|
|
Layers = new RenderLayers(); |
|
|
|
_renderLoop = renderLoop; |
|
|
|
_lock = rendererLock ?? new ManagedDeferredRendererLock(); |
|
|
|
_updateSceneIfNeededDelegate = UpdateSceneIfNeeded; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -73,7 +75,7 @@ namespace Avalonia.Rendering |
|
|
|
public DeferredRenderer( |
|
|
|
IVisual root, |
|
|
|
IRenderTarget renderTarget, |
|
|
|
ISceneBuilder sceneBuilder = null) |
|
|
|
ISceneBuilder sceneBuilder = null) : base(true) |
|
|
|
{ |
|
|
|
Contract.Requires<ArgumentNullException>(root != null); |
|
|
|
Contract.Requires<ArgumentNullException>(renderTarget != null); |
|
|
|
@ -83,6 +85,7 @@ namespace Avalonia.Rendering |
|
|
|
_sceneBuilder = sceneBuilder ?? new SceneBuilder(); |
|
|
|
Layers = new RenderLayers(); |
|
|
|
_lock = new ManagedDeferredRendererLock(); |
|
|
|
_updateSceneIfNeededDelegate = UpdateSceneIfNeeded; |
|
|
|
} |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
@ -261,7 +264,8 @@ namespace Avalonia.Rendering |
|
|
|
try |
|
|
|
{ |
|
|
|
var (scene, updated) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context); |
|
|
|
|
|
|
|
if (updated) |
|
|
|
FpsTick(); |
|
|
|
using (scene) |
|
|
|
{ |
|
|
|
if (scene?.Item != null) |
|
|
|
@ -318,17 +322,25 @@ namespace Avalonia.Rendering |
|
|
|
_lastSceneId = scene.Generation; |
|
|
|
|
|
|
|
|
|
|
|
var isUiThread = Dispatcher.UIThread.CheckAccess(); |
|
|
|
// 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
|
|
|
|
// rebuild before rendering anything on-screen
|
|
|
|
// We are calling the same method recursively here
|
|
|
|
if (!recursiveCall && Dispatcher.UIThread.CheckAccess() && NeedsUpdate) |
|
|
|
if (!recursiveCall && isUiThread && NeedsUpdate) |
|
|
|
{ |
|
|
|
UpdateScene(); |
|
|
|
var (rs, _) = UpdateRenderLayersAndConsumeSceneIfNeeded(ref context, 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
|
|
|
|
return (sceneRef.Clone(), true); |
|
|
|
} |
|
|
|
@ -534,6 +546,12 @@ namespace Avalonia.Rendering |
|
|
|
context = RenderTarget.CreateDrawingContext(this); |
|
|
|
} |
|
|
|
|
|
|
|
private void UpdateSceneIfNeeded() |
|
|
|
{ |
|
|
|
if(NeedsUpdate) |
|
|
|
UpdateScene(); |
|
|
|
} |
|
|
|
|
|
|
|
private void UpdateScene() |
|
|
|
{ |
|
|
|
Dispatcher.UIThread.VerifyAccess(); |
|
|
|
|