diff --git a/src/Avalonia.Base/Platform/RenderTargetProperties.cs b/src/Avalonia.Base/Platform/RenderTargetProperties.cs index de4f3f4345..22dc2cb918 100644 --- a/src/Avalonia.Base/Platform/RenderTargetProperties.cs +++ b/src/Avalonia.Base/Platform/RenderTargetProperties.cs @@ -16,6 +16,13 @@ public readonly struct PlatformRenderTargetState /// public bool IsReady { get; init; } + /// + /// Indicates that the render target is currently not ready but will wake up the render loop + /// when it becomes ready (e.g. waiting for a compositor frame callback). + /// When true, the compositor should not keep polling for readiness. + /// + public bool WillWakeUpRenderLoopWhenReady { get; init; } + /// /// Indicates if the render target is no longer usable and needs to be recreated /// @@ -31,6 +38,12 @@ public readonly struct PlatformRenderTargetState public static PlatformRenderTargetState Corrupted => new() { IsCorrupted = true, IsReady = true}; public static PlatformRenderTargetState Disposed => new() { IsCorrupted = true}; + + public static PlatformRenderTargetState NotReadyWillWakeupRenderLoop => new PlatformRenderTargetState() + { + WillWakeUpRenderLoopWhenReady = true + }; + } [PrivateApi] diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs index fe857ac466..c7e0de469c 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionTarget.cs @@ -44,6 +44,12 @@ namespace Avalonia.Rendering.Composition.Server /// Returns true if the target is enabled and has pending work but its render target was not ready. /// internal bool IsWaitingForReadyRenderTarget { get; private set; } + + /// + /// Returns true if the target's render target is waiting for a render loop wakeup + /// (i.e. the platform will call Wakeup() when ready, no need to keep polling). + /// + internal bool IsWaitingForRenderLoopWakeup { get; private set; } public ServerCompositionTarget(ServerCompositor compositor, Func> surfaces) : base(compositor) @@ -131,6 +137,7 @@ namespace Avalonia.Rendering.Composition.Server public void Render() { IsWaitingForReadyRenderTarget = false; + IsWaitingForRenderLoopWakeup = false; if (_disposed) return; @@ -181,6 +188,7 @@ namespace Avalonia.Rendering.Composition.Server if (!_renderTarget.PlatformRenderTargetState.IsReady) { IsWaitingForReadyRenderTarget = IsEnabled; + IsWaitingForRenderLoopWakeup = IsEnabled && _renderTarget.PlatformRenderTargetState.WillWakeUpRenderLoopWhenReady; return; } @@ -310,5 +318,7 @@ namespace Avalonia.Rendering.Composition.Server if (_attachedVisuals.Remove(visual) && IsEnabled) visual.Deactivate(); } + + public void RequestFullRedraw() => _redrawRequested = true; } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs index e440ffab26..c66964bbbf 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.UserApis.cs @@ -83,4 +83,10 @@ internal partial class ServerCompositor } } } + + public void InvalidateAllCompositionTargets() + { + foreach(var target in _activeTargets) + target.RequestFullRedraw(); + } } diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs index b8cc5afca2..bc78912960 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs @@ -281,8 +281,9 @@ namespace Avalonia.Rendering.Composition.Server return true; // Request a tick if we had unready targets in the last tick, to check if they are ready next time + // But skip targets that are waiting for a render loop wakeup from the platform foreach (var target in _activeTargets) - if (target.IsWaitingForReadyRenderTarget) + if (target.IsWaitingForReadyRenderTarget && !target.IsWaitingForRenderLoopWakeup) return true; // Otherwise there is no need to waste CPU cycles, tell the timer to pause