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