authorclover caruso <git@paperclover.net> 2026-10-15 16:02:00-07:00
committerclover caruso <git@paperclover.net> 2026-10-15 16:23:52-07:00
log4a299856128bcf7cbc8c36eefe3f9fdf31a588a6
tree82e303242b492cbe55651e615cf8cd6514a236e4
parent5d52a7a3ed5060df052284db1bd6cd66fe57db96
signature Signed by SSH key SHA256:52mNGHRsVFBDED9IAX5pe+LRWUefqTbxEReunq21QvU (~clover)

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

1 files changed, 22 insertions(+), 1 deletions(-)

crates/mobile/src/lib.rs+22-1
......@@ -671,6 +671,27 @@ fn view_pixels(size: [f32; 2], scale: f32, limit: u32) -> Result<[u32; 2]> {
671671 Ok(pixels.map(|side| side as u32))
672672}
673673
674/// The GPU instance the first view starts. On Android it offers one backend, Vulkan where the
675/// device has it, else GL: Android's Vulkan loader connects a window to make its surface, and
676/// EGL then can't make one on the same window.
677fn instance() -> wgpu::Instance {
678 let with = |backends| {
679 wgpu::Instance::new(wgpu::InstanceDescriptor {
680 backends,
681 ..wgpu::InstanceDescriptor::new_without_display_handle()
682 })
683 };
684 if !cfg!(target_os = "android") {
685 return with(wgpu::Backends::all());
686 }
687 let vulkan = with(wgpu::Backends::VULKAN);
688 if pollster::block_on(vulkan.enumerate_adapters(wgpu::Backends::VULKAN)).is_empty() {
689 with(wgpu::Backends::GL)
690 } else {
691 vulkan
692 }
693}
694
674695struct Presentation {
675696 surface: wgpu::Surface<'static>,
676697 /// Field order keeps the acquired window alive until the surface has dropped.
......@@ -700,7 +721,7 @@ impl Presentation {
700721 let mut gpu = gpu();
701722 let instance = match &*gpu {
702723 Some(gpu) => gpu.instance.clone(),
703 None => wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle()),
724 None => instance(),
704725 };
705726 // SAFETY: Android retains its window; the Apple caller keeps its layer alive.
706727 let surface = unsafe { instance.create_surface_unsafe(target) }?;