Skip to content

Commit 53e8d99

Browse files
authored
fix segfault crash when native surface is destroyed while there's rendering queued on vulkan android (#17921)
1 parent 0dd628f commit 53e8d99

File tree

3 files changed

+16
-4
lines changed

3 files changed

+16
-4
lines changed

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ internal abstract class InvalidationAwareSurfaceView : SurfaceView, ISurfaceHold
1414
{
1515
bool _invalidateQueued;
1616
private bool _isDisposed;
17+
private bool _isSurfaceValid;
1718
readonly object _lock = new object();
1819
private readonly Handler _handler;
1920

2021
internal event EventHandler? SurfaceWindowCreated;
2122

22-
IntPtr IPlatformHandle.Handle => Holder?.Surface?.Handle is { } handle ?
23+
IntPtr IPlatformHandle.Handle => _isSurfaceValid && Holder?.Surface?.Handle is { } handle ?
2324
AndroidFramebuffer.ANativeWindow_fromSurface(JNIEnv.Handle, handle) :
2425
default;
2526

@@ -63,19 +64,22 @@ public override void Invalidate()
6364

6465
public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
6566
{
67+
_isSurfaceValid = true;
6668
Log.Info("AVALONIA", "Surface Changed");
6769
DoDraw();
6870
}
6971

7072
public void SurfaceCreated(ISurfaceHolder holder)
7173
{
74+
_isSurfaceValid = true;
7275
Log.Info("AVALONIA", "Surface Created");
7376
SurfaceWindowCreated?.Invoke(this, EventArgs.Empty);
7477
DoDraw();
7578
}
7679

7780
public void SurfaceDestroyed(ISurfaceHolder holder)
7881
{
82+
_isSurfaceValid = false;
7983
Log.Info("AVALONIA", "Surface Destroyed");
8084

8185
}

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

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public void Dispose()
5353

5454
private static ulong CreateAndroidSurface(nint handle, IVulkanInstance instance)
5555
{
56+
if(handle == IntPtr.Zero)
57+
throw new ArgumentException("Surface handle can't be 0x0", nameof(handle));
5658
var vulkanAndroid = new AndroidVulkanInterface(instance);
5759
var createInfo = new VkAndroidSurfaceCreateInfoKHR()
5860
{

src/Avalonia.Vulkan/Interop/VulkanDisplay.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal class VulkanDisplay : IDisposable
1313
private IVulkanPlatformGraphicsContext _context;
1414
private VulkanSemaphorePair _semaphorePair;
1515
private uint _nextImage;
16-
private VulkanKhrSurface _surface;
16+
private VulkanKhrSurface? _surface;
1717
private VkSurfaceFormatKHR _surfaceFormat;
1818
private VkSwapchainKHR _swapchain;
1919
private VkExtent2D _swapchainExtent;
@@ -40,7 +40,7 @@ internal VkSurfaceFormatKHR SurfaceFormat
4040
{
4141
get
4242
{
43-
if (_surfaceFormat.format == VkFormat.VK_FORMAT_UNDEFINED)
43+
if (_surfaceFormat.format == VkFormat.VK_FORMAT_UNDEFINED && _surface != null)
4444
_surfaceFormat = _surface.GetSurfaceFormat();
4545
return _surfaceFormat;
4646
}
@@ -193,6 +193,11 @@ private VkImageView CreateSwapchainImageView(VkImage swapchainImage, VkFormat fo
193193

194194
private void RecreateSwapchain()
195195
{
196+
if (_surface == null)
197+
{
198+
RecreateSurface();
199+
return;
200+
}
196201
_context.DeviceApi.DeviceWaitIdle(_context.DeviceHandle);
197202
_swapchain = CreateSwapchain(_context, _surface, out var extent, this);
198203
_swapchainExtent = extent;
@@ -202,14 +207,15 @@ private void RecreateSwapchain()
202207
private void RecreateSurface()
203208
{
204209
_surface?.Dispose();
210+
_surface = null;
205211
_surface = new VulkanKhrSurface(_context, _platformSurface);
206212
DestroySwapchain();
207213
RecreateSwapchain();
208214
}
209215

210216
public bool EnsureSwapchainAvailable()
211217
{
212-
if (Size != _surface.Size)
218+
if (Size != _surface?.Size)
213219
{
214220
RecreateSwapchain();
215221
return true;

0 commit comments

Comments
 (0)