Browse Source

Added some threading checks

pull/9718/head
Nikita Tsukanov 4 years ago
parent
commit
cbb42d756c
  1. 39
      src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs
  2. 19
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs

39
src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs

@ -21,16 +21,45 @@ public abstract class CompositionCustomVisualHandler
public abstract void OnRender(ImmediateDrawingContext drawingContext); public abstract void OnRender(ImmediateDrawingContext drawingContext);
protected Vector2 EffectiveSize => _host?.Size ?? default; void VerifyAccess()
{
if (_host == null)
throw new InvalidOperationException("Object is not yet attached to the compositor");
_host.Compositor.VerifyAccess();
}
protected Vector2 EffectiveSize
{
get
{
VerifyAccess();
return _host!.Size;
}
}
protected TimeSpan CompositionNow
{
get
{
VerifyAccess();
return _host!.Compositor.ServerNow;
}
}
protected TimeSpan CompositionNow => _host?.Compositor.ServerNow ?? default;
public virtual Rect GetRenderBounds() => public virtual Rect GetRenderBounds() =>
new(0, 0, EffectiveSize.X, EffectiveSize.Y); new(0, 0, EffectiveSize.X, EffectiveSize.Y);
internal void Attach(ServerCompositionCustomVisual visual) => _host = visual; internal void Attach(ServerCompositionCustomVisual visual) => _host = visual;
protected void Invalidate() => _host?.HandlerInvalidate(); protected void Invalidate()
{
VerifyAccess();
_host!.HandlerInvalidate();
}
protected void RegisterForNextAnimationFrameUpdate() => _host?.HandlerRegisterForNextAnimationFrameUpdate(); protected void RegisterForNextAnimationFrameUpdate()
{
VerifyAccess();
_host!.HandlerRegisterForNextAnimationFrameUpdate();
}
} }

19
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositor.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering.Composition.Animations; using Avalonia.Rendering.Composition.Animations;
@ -31,6 +32,7 @@ namespace Avalonia.Rendering.Composition.Server
internal BatchStreamObjectPool<object?> BatchObjectPool; internal BatchStreamObjectPool<object?> BatchObjectPool;
internal BatchStreamMemoryPool BatchMemoryPool; internal BatchStreamMemoryPool BatchMemoryPool;
private object _lock = new object(); private object _lock = new object();
private Thread? _safeThread;
public PlatformRenderInterfaceContextManager RenderInterface { get; } public PlatformRenderInterfaceContextManager RenderInterface { get; }
internal static readonly object RenderThreadJobsStartMarker = new(); internal static readonly object RenderThreadJobsStartMarker = new();
internal static readonly object RenderThreadJobsEndMarker = new(); internal static readonly object RenderThreadJobsEndMarker = new();
@ -129,7 +131,15 @@ namespace Avalonia.Rendering.Composition.Server
{ {
lock (_lock) lock (_lock)
{ {
RenderCore(); try
{
_safeThread = Thread.CurrentThread;
RenderCore();
}
finally
{
_safeThread = null;
}
} }
} }
@ -180,5 +190,12 @@ namespace Avalonia.Rendering.Composition.Server
using (RenderInterface.EnsureCurrent()) using (RenderInterface.EnsureCurrent())
return RenderInterface.CreateRenderTarget(surfaces); return RenderInterface.CreateRenderTarget(surfaces);
} }
public bool CheckAccess() => _safeThread == Thread.CurrentThread;
public void VerifyAccess()
{
if (!CheckAccess())
throw new InvalidOperationException("This object can be only accessed under compositor lock");
}
} }
} }

Loading…
Cancel
Save