diff --git a/CHANGELOG.md b/CHANGELOG.md index e21090f2a6..88d525b5bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,11 @@ - Fix crash when creating OpenGLES context without explicit version. - 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. +- Fix compilation on Android: + - Switch from `StaticStructGenerator` to `StructGenerator` to dynamically load symbols. + - Replace `android_glue` dependency with `ndk-glue`, and remove broken lifecycle event handling. + - Glutin can now be used on Android, however, the application must ensure it only creates the `Context` following a winit `Event::Resumed` event, and destroys the `Context` in response to a `Event::Suspended` event. # Version 0.28.0 (2021-12-02) diff --git a/README.md b/README.md index 1132bfc34f..589104bbd3 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 [`cargo-apk` in the `android-ndk-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 5daaf41839..c8e3cf4144 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 76056e6177..df761cc164 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 1b9134c7d8..fad3fb8912 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, }) } }