Browse Source

Remove ancient renderer support with Invalidate/Paint calls, drastically simplify InvalidationAwareSurfaceView

pull/19045/head
Max Katz 8 months ago
parent
commit
78b47a61ae
  1. 98
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  2. 39
      src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

98
src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs

@ -1,30 +1,28 @@
using System; using System;
using Android.Content; using Android.Content;
using Android.Graphics; using Android.Graphics;
using Android.OS;
using Android.Runtime; using Android.Runtime;
using Android.Util;
using Android.Views; using Android.Views;
using Avalonia.Android.Platform.SkiaPlatform; using Avalonia.Android.Platform.SkiaPlatform;
using Avalonia.Logging;
using Avalonia.Platform; using Avalonia.Platform;
namespace Avalonia.Android namespace Avalonia.Android
{ {
internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, INativePlatformHandleSurface internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHolderCallback, INativePlatformHandleSurface
{ {
bool _invalidateQueued; private IntPtr _nativeWindowHandle = IntPtr.Zero;
private bool _isDisposed; private PixelSize _size = new(1, 1);
private bool _isSurfaceValid; private double _scaling = 1;
readonly object _lock = new object();
private readonly Handler _handler;
internal event EventHandler? SurfaceWindowCreated; public event EventHandler? SurfaceWindowCreated;
public PixelSize Size => _size;
public double Scaling => _scaling;
IntPtr IPlatformHandle.Handle => _isSurfaceValid && Holder?.Surface?.Handle is { } handle ? IntPtr IPlatformHandle.Handle => _nativeWindowHandle;
AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, handle) : string IPlatformHandle.HandleDescriptor => "SurfaceView";
default;
public InvalidationAwareSurfaceView(Context context) : base(context) protected InvalidationAwareSurfaceView(Context context) : base(context)
{ {
if (Holder is null) if (Holder is null)
throw new InvalidOperationException( throw new InvalidOperationException(
@ -32,71 +30,59 @@ namespace Avalonia.Android
Holder.AddCallback(this); Holder.AddCallback(this);
Holder.SetFormat(global::Android.Graphics.Format.Transparent); Holder.SetFormat(global::Android.Graphics.Format.Transparent);
_handler = new Handler(context.MainLooper!);
} }
public override void Invalidate() protected override void Dispose(bool disposing)
{ {
lock (_lock) ReleaseNativeWindowHandle();
{ base.Dispose(disposing);
if (_invalidateQueued)
return;
_handler.Post(() =>
{
if (_isDisposed || Holder?.Surface?.IsValid != true)
return;
try
{
DoDraw();
}
catch (Exception e)
{
Log.WriteLine(LogPriority.Error, "Avalonia", e.ToString());
}
});
}
}
internal new void Dispose()
{
_isDisposed = true;
} }
public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) public virtual void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{ {
_isSurfaceValid = true; CacheSurfaceProperties(holder);
Log.Info("AVALONIA", "Surface Changed"); Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
DoDraw(); .Log(this, "InvalidationAwareSurfaceView Changed");
} }
public void SurfaceCreated(ISurfaceHolder holder) public void SurfaceCreated(ISurfaceHolder holder)
{ {
_isSurfaceValid = true; CacheSurfaceProperties(holder);
Log.Info("AVALONIA", "Surface Created"); Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "InvalidationAwareSurfaceView Created");
SurfaceWindowCreated?.Invoke(this, EventArgs.Empty); SurfaceWindowCreated?.Invoke(this, EventArgs.Empty);
DoDraw();
} }
public void SurfaceDestroyed(ISurfaceHolder holder) public void SurfaceDestroyed(ISurfaceHolder holder)
{ {
_isSurfaceValid = false; ReleaseNativeWindowHandle();
Log.Info("AVALONIA", "Surface Destroyed"); _size = new PixelSize(1, 1);
_scaling = 1;
Logger.TryGet(LogEventLevel.Verbose, LogArea.AndroidPlatform)?
.Log(this, "InvalidationAwareSurfaceView Destroyed");
}
private void CacheSurfaceProperties(ISurfaceHolder holder)
{
ReleaseNativeWindowHandle();
var surface = holder?.Surface;
if (surface?.Handle is { } handle)
_nativeWindowHandle = AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, handle);
else
_nativeWindowHandle = IntPtr.Zero;
var frame = holder?.SurfaceFrame;
_size = frame != null ? new PixelSize(frame.Width(), frame.Height()) : new PixelSize(1, 1);
_scaling = Resources?.DisplayMetrics?.Density ?? 1;
} }
protected void DoDraw() private void ReleaseNativeWindowHandle()
{ {
lock (_lock) if (_nativeWindowHandle != IntPtr.Zero)
{ {
_invalidateQueued = false; AndroidFramebuffer.ANativeWindow_release(_nativeWindowHandle);
_nativeWindowHandle = IntPtr.Zero;
} }
Draw();
} }
protected abstract void Draw();
public string HandleDescriptor => "SurfaceView";
public PixelSize Size => new(Holder?.SurfaceFrame?.Width() ?? 1, Holder?.SurfaceFrame?.Height() ?? 1);
public double Scaling => Resources?.DisplayMetrics?.Density ?? 1;
} }
} }

39
src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs

@ -124,11 +124,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
InputRoot = inputRoot; InputRoot = inputRoot;
} }
void Draw()
{
Paint?.Invoke(new Rect(new Point(0, 0), ClientSize));
}
public virtual void Dispose() public virtual void Dispose()
{ {
_systemNavigationManager.Dispose(); _systemNavigationManager.Dispose();
@ -146,10 +141,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Resized?.Invoke(size, WindowResizeReason.Layout); Resized?.Invoke(size, WindowResizeReason.Layout);
} }
class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo sealed class ViewImpl : InvalidationAwareSurfaceView, IInitEditorInfo
{ {
private readonly TopLevelImpl _tl; private readonly TopLevelImpl _tl;
private Size _oldSize; private Size _oldSize;
private double _oldScaling;
public ViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context) public ViewImpl(Context context, TopLevelImpl tl, bool placeOnTop) : base(context)
{ {
@ -158,13 +154,6 @@ namespace Avalonia.Android.Platform.SkiaPlatform
SetZOrderOnTop(true); SetZOrderOnTop(true);
} }
public TopLevelImpl TopLevelImpl => _tl;
protected override void Draw()
{
_tl.Draw();
}
protected override void DispatchDraw(global::Android.Graphics.Canvas canvas) protected override void DispatchDraw(global::Android.Graphics.Canvas canvas)
{ {
// Workaround issue #9230 on where screen remains gray after splash screen. // Workaround issue #9230 on where screen remains gray after splash screen.
@ -211,17 +200,24 @@ namespace Avalonia.Android.Platform.SkiaPlatform
return res ?? baseResult; return res ?? baseResult;
} }
void ISurfaceHolderCallback.SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height) public override void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{ {
var newSize = new PixelSize(width, height).ToSize(_tl.RenderScaling); base.SurfaceChanged(holder, format, width, height);
var newSize = Size.ToSize(Scaling);
var newScaling = Scaling;
if (newSize != _oldSize) if (newSize != _oldSize)
{ {
_oldSize = newSize; _oldSize = newSize;
_tl.OnResized(newSize); _tl.OnResized(newSize);
} }
// ReSharper disable once CompareOfFloatsByEqualityOperator
base.SurfaceChanged(holder, format, width, height); if (newScaling != _oldScaling)
{
_oldScaling = newScaling;
_tl.ScalingChanged?.Invoke(newScaling);
}
} }
public sealed override bool OnCheckIsTextEditor() public sealed override bool OnCheckIsTextEditor()
@ -236,11 +232,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_initEditorInfo = init; _initEditorInfo = init;
} }
public sealed override IInputConnection OnCreateInputConnection(EditorInfo? outAttrs) public override IInputConnection OnCreateInputConnection(EditorInfo? outAttrs)
{ {
return _initEditorInfo?.Invoke(_tl, outAttrs!)!; return _initEditorInfo?.Invoke(_tl, outAttrs!)!;
} }
} }
public IPopupImpl? CreatePopup() => null; public IPopupImpl? CreatePopup() => null;
@ -280,10 +275,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => ((IPlatformHandle)_view).Handle; IntPtr EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Handle => ((IPlatformHandle)_view).Handle;
bool EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfoWithWaitPolicy.SkipWaits => true; bool EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfoWithWaitPolicy.SkipWaits => true;
PixelSize EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Size => _view.Size;
public PixelSize Size => _view.Size; double EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo.Scaling => _view.Scaling;
public double Scaling => RenderScaling;
public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels) public void SetTransparencyLevelHint(IReadOnlyList<WindowTransparencyLevel> transparencyLevels)
{ {

Loading…
Cancel
Save