From 740532ebb64551d7dcb5b120f8ca9402f129911f Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Fri, 22 Apr 2022 10:17:08 +0100 Subject: [PATCH] Switch from android_glue to ndk-glue Additionally remove the Android lifecycle handling code, as winit no longer provides the required callback meaning it does not compile. This fixes compilation on Android. However, there is a caveat: Glutin is no longer able to automatically destroy and create the Surface in response to Android lifecycle events. The application must therefore ensure they only create a Context following a winit Event::Resumed, and they destroy the context when receiving an Event::Suspended. --- CHANGELOG.md | 1 + README.md | 2 +- glutin/Cargo.toml | 2 +- glutin/src/api/android/mod.rs | 55 +++-------------------------------- glutin/src/api/egl/mod.rs | 50 ------------------------------- 5 files changed, 7 insertions(+), 103 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e21090f2a61..3ed09583463 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Add `buffer_age` method on `WindowedContext`. - On Android, switched from `StaticStructGenerator` to `StructGenerator`, fixing some compilation errors. - Return an `Err` instead of panicking when surfaceless GLX context creation fails on Linux. +- On Android, replace `android_glue` dependency with `ndk-glue`, and remove broken lifecycle event handling. # Version 0.28.0 (2021-12-02) diff --git a/README.md b/README.md index 1132bfc34fd..5ee2ea85d18 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ Glutin is only officially supported on the latest stable version of the Rust com To compile the examples for android, you have to use the `cargo apk` utility. -See [the `android-rs-glue` repository](https://github.com/rust-windowing/android-rs-glue) for instructions. +See [the `android-nd-rs` repository](https://github.com/rust-windowing/android-ndk-rs/cargo-apk) for instructions. ### Emscripten with asmjs diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml index 5daaf418395..c8e3cf41445 100644 --- a/glutin/Cargo.toml +++ b/glutin/Cargo.toml @@ -25,9 +25,9 @@ lazy_static = "1.3" winit = { version = "0.26", default-features = false } [target.'cfg(target_os = "android")'.dependencies] -android_glue = "0.2" glutin_egl_sys = { version = "0.1.5", path = "../glutin_egl_sys" } libloading = "0.7" +ndk-glue = "0.5" # Keep in sync with winit parking_lot = "0.11" [target.'cfg(target_os = "emscripten")'.dependencies] diff --git a/glutin/src/api/android/mod.rs b/glutin/src/api/android/mod.rs index 76056e6177c..df761cc1644 100644 --- a/glutin/src/api/android/mod.rs +++ b/glutin/src/api/android/mod.rs @@ -4,7 +4,6 @@ use crate::api::egl::{Context as EglContext, NativeDisplay, SurfaceType as EglSu use crate::CreationError::{self, OsError}; use crate::{Api, ContextError, GlAttributes, PixelFormat, PixelFormatRequirements, Rect}; -use crate::platform::android::EventLoopExtAndroid; use glutin_egl_sys as ffi; use parking_lot::Mutex; use winit; @@ -23,30 +22,6 @@ struct AndroidContext { #[derive(Debug)] pub struct Context(Arc); -#[derive(Debug)] -struct AndroidSyncEventHandler(Arc); - -impl android_glue::SyncEventHandler for AndroidSyncEventHandler { - fn handle(&mut self, event: &android_glue::Event) { - match *event { - // 'on_surface_destroyed' Android event can arrive with some delay - // because multithreading communication. Because of - // that, swap_buffers can be called before processing - // 'on_surface_destroyed' event, with the native window - // surface already destroyed. EGL generates a BAD_SURFACE error in - // this situation. Set stop to true to prevent - // swap_buffer call race conditions. - android_glue::Event::TermWindow => { - let mut stopped = self.0.stopped.as_ref().unwrap().lock(); - *stopped = true; - } - _ => { - return; - } - }; - } -} - impl Context { #[inline] pub fn new_windowed( @@ -57,41 +32,19 @@ impl Context { ) -> Result<(winit::window::Window, Self), CreationError> { let win = wb.build(el)?; let gl_attr = gl_attr.clone().map_sharing(|c| &c.0.egl_context); - let nwin = unsafe { android_glue::get_native_window() }; - if nwin.is_null() { - return Err(OsError("Android's native window is null".to_string())); - } + let nwin = ndk_glue::native_window(); + let nwin = + nwin.as_ref().ok_or_else(|| OsError("Android's native window is null".to_string()))?; let native_display = NativeDisplay::Android; let egl_context = EglContext::new(pf_reqs, &gl_attr, native_display, EglSurfaceType::Window, |c, _| { Ok(c[0]) }) - .and_then(|p| p.finish(nwin as *const _))?; + .and_then(|p| p.finish(nwin.ptr().as_ptr() as *const _))?; let ctx = Arc::new(AndroidContext { egl_context, stopped: Some(Mutex::new(false)) }); - let handler = Box::new(AndroidSyncEventHandler(ctx.clone())); - android_glue::add_sync_event_handler(handler); let context = Context(ctx.clone()); - el.set_suspend_callback(Some(Box::new(move |suspended| { - let mut stopped = ctx.stopped.as_ref().unwrap().lock(); - *stopped = suspended; - if suspended { - // Android has stopped the activity or sent it to background. - // Release the EGL surface and stop the animation loop. - unsafe { - ctx.egl_context.on_surface_destroyed(); - } - } else { - // Android has started the activity or sent it to foreground. - // Restore the EGL surface and animation loop. - unsafe { - let nwin = android_glue::get_native_window(); - ctx.egl_context.on_surface_created(nwin as *const _); - } - } - }))); - Ok((win, context)) } diff --git a/glutin/src/api/egl/mod.rs b/glutin/src/api/egl/mod.rs index 1b9134c7d8a..fad3fb89124 100644 --- a/glutin/src/api/egl/mod.rs +++ b/glutin/src/api/egl/mod.rs @@ -161,8 +161,6 @@ pub struct Context { surface: Option>, api: Api, pixel_format: PixelFormat, - #[cfg(target_os = "android")] - config_id: ffi::egl::types::EGLConfig, } fn get_egl_version( @@ -511,52 +509,6 @@ impl Context { self.display } - // Handle Android Life Cycle. - // Android has started the activity or sent it to foreground. - // Create a new surface and attach it to the recreated ANativeWindow. - // Restore the EGLContext. - #[cfg(target_os = "android")] - pub unsafe fn on_surface_created(&self, nwin: ffi::EGLNativeWindowType) { - let egl = EGL.as_ref().unwrap(); - let mut surface = self.surface.as_ref().unwrap().lock(); - if *surface != ffi::egl::NO_SURFACE { - return; - } - *surface = egl.CreateWindowSurface(self.display, self.config_id, nwin, std::ptr::null()); - if surface.is_null() { - panic!("on_surface_created: eglCreateWindowSurface failed with 0x{:x}", egl.GetError()) - } - let ret = egl.MakeCurrent(self.display, *surface, *surface, self.context); - if ret == 0 { - panic!("on_surface_created: eglMakeCurrent failed with 0x{:x}", egl.GetError()) - } - } - - // Handle Android Life Cycle. - // Android has stopped the activity or sent it to background. - // Release the surface attached to the destroyed ANativeWindow. - // The EGLContext is not destroyed so it can be restored later. - #[cfg(target_os = "android")] - pub unsafe fn on_surface_destroyed(&self) { - let egl = EGL.as_ref().unwrap(); - let mut surface = self.surface.as_ref().unwrap().lock(); - if *surface == ffi::egl::NO_SURFACE { - return; - } - let ret = egl.MakeCurrent( - self.display, - ffi::egl::NO_SURFACE, - ffi::egl::NO_SURFACE, - ffi::egl::NO_CONTEXT, - ); - if ret == 0 { - panic!("on_surface_destroyed: eglMakeCurrent failed with 0x{:x}", egl.GetError()) - } - - egl.DestroySurface(self.display, *surface); - *surface = ffi::egl::NO_SURFACE; - } - #[inline] pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void { let egl = EGL.as_ref().unwrap(); @@ -991,8 +943,6 @@ impl<'a> ContextPrototype<'a> { surface: surface.map(|s| Mutex::new(s)), api: self.api, pixel_format: self.pixel_format, - #[cfg(target_os = "android")] - config_id: self.config_id, }) } }