Browse Source

fix segfault crash when native surface is destroyed while there's rendering queued on vulkan android (#17921)

pull/17932/head
Emmanuel Hansen 1 year ago
committed by GitHub
parent
commit
53e8d99758
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      src/Android/Avalonia.Android/Platform/SkiaPlatform/InvalidationAwareSurfaceView.cs
  2. 2
      src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs
  3. 12
      src/Avalonia.Vulkan/Interop/VulkanDisplay.cs

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

@ -14,12 +14,13 @@ namespace Avalonia.Android
{
bool _invalidateQueued;
private bool _isDisposed;
private bool _isSurfaceValid;
readonly object _lock = new object();
private readonly Handler _handler;
internal event EventHandler? SurfaceWindowCreated;
IntPtr IPlatformHandle.Handle => Holder?.Surface?.Handle is { } handle ?
IntPtr IPlatformHandle.Handle => _isSurfaceValid && Holder?.Surface?.Handle is { } handle ?
AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, handle) :
default;
@ -63,12 +64,14 @@ namespace Avalonia.Android
public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
_isSurfaceValid = true;
Log.Info("AVALONIA", "Surface Changed");
DoDraw();
}
public void SurfaceCreated(ISurfaceHolder holder)
{
_isSurfaceValid = true;
Log.Info("AVALONIA", "Surface Created");
SurfaceWindowCreated?.Invoke(this, EventArgs.Empty);
DoDraw();
@ -76,6 +79,7 @@ namespace Avalonia.Android
public void SurfaceDestroyed(ISurfaceHolder holder)
{
_isSurfaceValid = false;
Log.Info("AVALONIA", "Surface Destroyed");
}

2
src/Android/Avalonia.Android/Platform/Vulkan/VulkanSupport.cs

@ -53,6 +53,8 @@ namespace Avalonia.Android.Platform.Vulkan
private static ulong CreateAndroidSurface(nint handle, IVulkanInstance instance)
{
if(handle == IntPtr.Zero)
throw new ArgumentException("Surface handle can't be 0x0", nameof(handle));
var vulkanAndroid = new AndroidVulkanInterface(instance);
var createInfo = new VkAndroidSurfaceCreateInfoKHR()
{

12
src/Avalonia.Vulkan/Interop/VulkanDisplay.cs

@ -13,7 +13,7 @@ internal class VulkanDisplay : IDisposable
private IVulkanPlatformGraphicsContext _context;
private VulkanSemaphorePair _semaphorePair;
private uint _nextImage;
private VulkanKhrSurface _surface;
private VulkanKhrSurface? _surface;
private VkSurfaceFormatKHR _surfaceFormat;
private VkSwapchainKHR _swapchain;
private VkExtent2D _swapchainExtent;
@ -40,7 +40,7 @@ internal class VulkanDisplay : IDisposable
{
get
{
if (_surfaceFormat.format == VkFormat.VK_FORMAT_UNDEFINED)
if (_surfaceFormat.format == VkFormat.VK_FORMAT_UNDEFINED && _surface != null)
_surfaceFormat = _surface.GetSurfaceFormat();
return _surfaceFormat;
}
@ -193,6 +193,11 @@ internal class VulkanDisplay : IDisposable
private void RecreateSwapchain()
{
if (_surface == null)
{
RecreateSurface();
return;
}
_context.DeviceApi.DeviceWaitIdle(_context.DeviceHandle);
_swapchain = CreateSwapchain(_context, _surface, out var extent, this);
_swapchainExtent = extent;
@ -202,6 +207,7 @@ internal class VulkanDisplay : IDisposable
private void RecreateSurface()
{
_surface?.Dispose();
_surface = null;
_surface = new VulkanKhrSurface(_context, _platformSurface);
DestroySwapchain();
RecreateSwapchain();
@ -209,7 +215,7 @@ internal class VulkanDisplay : IDisposable
public bool EnsureSwapchainAvailable()
{
if (Size != _surface.Size)
if (Size != _surface?.Size)
{
RecreateSwapchain();
return true;

Loading…
Cancel
Save