Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Send dispose command for CompositionTarget as an OOB batch #18119

Merged
merged 6 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions src/Avalonia.Base/Media/MediaContext.Compositor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,24 @@ private void SyncCommit(Compositor compositor, bool waitFullRender, bool catchEx
if (AvaloniaLocator.Current.GetService<IPlatformRenderInterface>() == null)
return;

using var _ = NonPumpingLockHelper.Use();
SyncWaitCompositorBatch(compositor, CommitCompositor(compositor), waitFullRender, catchExceptions);
}

private void SyncWaitCompositorBatch(Compositor compositor, CompositionBatch batch,
bool waitFullRender, bool catchExceptions)
{
using var _ = NonPumpingLockHelper.Use();
if (compositor is
{
UseUiThreadForSynchronousCommits: false,
Loop.RunsInBackground: true
})
{
var batch = CommitCompositor(compositor);
(waitFullRender ? batch.Rendered : batch.Processed).Wait();
}
else
{
CommitCompositor(compositor);
compositor.Server.Render(catchExceptions);
}
}
Expand All @@ -132,10 +137,15 @@ public void ImmediateRenderRequested(CompositionTarget target, bool catchExcepti
/// </summary>
public void SyncDisposeCompositionTarget(CompositionTarget compositionTarget)
{
compositionTarget.Dispose();
using var _ = NonPumpingLockHelper.Use();

// TODO: We are sending a dispose command outside of the normal commit cycle and we might
// want to ask the compositor to skip any actual rendering and return the control ASAP
// Not sure if we should do that for background thread rendering since it might affect the animation
// smoothness of other windows

// TODO: introduce a way to skip any actual rendering for other targets and only do a dispose?
SyncCommit(compositionTarget.Compositor, false, true);
var oobBatch = compositionTarget.Compositor.OobDispose(compositionTarget);
SyncWaitCompositorBatch(compositionTarget.Compositor, oobBatch, false, true);
}

/// <summary>
Expand Down
22 changes: 22 additions & 0 deletions src/Avalonia.Base/Rendering/Composition/Compositor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,28 @@ static void SerializeServerJobs(BatchStreamWriter writer, List<Action> list, obj
return commit;
}
}

/// <summary>
/// This method submits a composition with a single dispose command outside the normal
/// commit cycle. This is currently used for disposing CompositionTargets since we need to do that ASAP
/// and without affecting the not yet completed composition batch
/// </summary>
internal CompositionBatch OobDispose(CompositionObject obj)
{
using var _ = NonPumpingLockHelper.Use();
obj.Dispose();
var batch = new CompositionBatch();
using (var writer = new BatchStreamWriter(batch.Changes, _batchMemoryPool, _batchObjectPool))
{
writer.WriteObject(ServerCompositor.RenderThreadDisposeStartMarker);
writer.Write(1);
writer.WriteObject(obj.Server);
}

batch.CommittedAt = Server.Clock.Elapsed;
_server.EnqueueBatch(batch);
return batch;
}

internal void RegisterForSerialization(ICompositorSerializable compositionObject)
{
Expand Down
4 changes: 3 additions & 1 deletion tests/Avalonia.Base.UnitTests/Input/PointerOverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;

using Avalonia.Controls;
using Avalonia.Headless;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Rendering;
Expand All @@ -22,7 +23,8 @@ public void Close_Should_Remove_PointerOver()
{
using var app = UnitTestApplication.Start(new TestServices(
inputManager: new InputManager(),
focusManager: new FocusManager()));
focusManager: new FocusManager(),
renderInterface: new HeadlessPlatformRenderInterface()));

var renderer = new Mock<IHitTester>();
var device = CreatePointerDeviceMock().Object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public void Activation_For_View_Fetcher_Should_Support_When_Activated()
[Fact]
public void Activation_For_View_Fetcher_Should_Support_Windows()
{
using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new TestWindowWithWhenActivated();
Assert.False(window.Active);
Expand All @@ -171,7 +171,7 @@ public void Activation_For_View_Fetcher_Should_Support_Windows()
[Fact]
public void Activatable_Window_View_Model_Is_Activated_And_Deactivated()
{
using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var viewModel = new ActivatableViewModel();
var window = new ActivatableWindow { ViewModel = viewModel };
Expand Down
Loading