From 4a299856128bcf7cbc8c36eefe3f9fdf31a588a6 Mon Sep 17 00:00:00 2001 From: clover caruso Date: Thu, 15 Oct 2026 16:02:00 -0700 Subject: [PATCH] fix(mobile): draw on Android devices without Vulkan The first view opened a GPU instance with every backend, so on a device without a Vulkan driver, as the emulator is before Android 10, Vulkan still made a surface on the window and GL, the backend actually chosen, could not make its own: the app aborted on launch. On Android the instance now offers one backend, Vulkan where a device has it and GL otherwise. Refs #24 Assisted-by: claude-opus-5.5 --- crates/mobile/src/lib.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/mobile/src/lib.rs b/crates/mobile/src/lib.rs index 2e4a0859f92268f5ad2961767f0041a2c78f1728..4a35d430df620a5f1de86be3ab5ad761d4e9370c 100644 --- a/crates/mobile/src/lib.rs +++ b/crates/mobile/src/lib.rs @@ -671,6 +671,27 @@ fn view_pixels(size: [f32; 2], scale: f32, limit: u32) -> Result<[u32; 2]> { Ok(pixels.map(|side| side as u32)) } +/// The GPU instance the first view starts. On Android it offers one backend, Vulkan where the +/// device has it, else GL: Android's Vulkan loader connects a window to make its surface, and +/// EGL then can't make one on the same window. +fn instance() -> wgpu::Instance { + let with = |backends| { + wgpu::Instance::new(wgpu::InstanceDescriptor { + backends, + ..wgpu::InstanceDescriptor::new_without_display_handle() + }) + }; + if !cfg!(target_os = "android") { + return with(wgpu::Backends::all()); + } + let vulkan = with(wgpu::Backends::VULKAN); + if pollster::block_on(vulkan.enumerate_adapters(wgpu::Backends::VULKAN)).is_empty() { + with(wgpu::Backends::GL) + } else { + vulkan + } +} + struct Presentation { surface: wgpu::Surface<'static>, /// Field order keeps the acquired window alive until the surface has dropped. @@ -700,7 +721,7 @@ impl Presentation { let mut gpu = gpu(); let instance = match &*gpu { Some(gpu) => gpu.instance.clone(), - None => wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle()), + None => instance(), }; // SAFETY: Android retains its window; the Apple caller keeps its layer alive. let surface = unsafe { instance.create_surface_unsafe(target) }?; -- 2.54.0