diff --git a/Cargo.lock b/Cargo.lock index f66040ae51b..0f5ee9f1977 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,6 +34,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + [[package]] name = "android_glue" version = "0.2.3" @@ -2101,6 +2107,7 @@ dependencies = [ name = "wgpu-hal" version = "0.12.0" dependencies = [ + "android-properties", "arrayvec", "ash", "bit-set", diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index d944613fa24..846afb5e51b 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -124,7 +124,10 @@ impl Global { let _ = device; let suf = A::get_surface_mut(surface); - let (texture_id, status) = match unsafe { suf.raw.acquire_texture(Some(Duration::from_millis(FRAME_TIMEOUT_MS as u64))) } { + let (texture_id, status) = match unsafe { + suf.raw + .acquire_texture(Some(Duration::from_millis(FRAME_TIMEOUT_MS as u64))) + } { Ok(Some(ast)) => { let clear_view_desc = hal::TextureViewDescriptor { label: Some("(wgpu internal) clear surface texture view"), diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index caad696d40c..020b39cc9ae 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -90,6 +90,9 @@ wasm-bindgen = { version = "0.2" } web-sys = { version = "0.3", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext"] } js-sys = { version = "0.3" } +[target.'cfg(target_os = "android")'.dependencies] +android-properties = "0.2" + [dependencies.naga] git = "https://github.com/gfx-rs/naga" rev = "571302e" diff --git a/wgpu-hal/src/dx11/mod.rs b/wgpu-hal/src/dx11/mod.rs index ff9c49e0b3e..a77bb95919a 100644 --- a/wgpu-hal/src/dx11/mod.rs +++ b/wgpu-hal/src/dx11/mod.rs @@ -124,7 +124,7 @@ impl crate::Surface for Surface { unsafe fn acquire_texture( &mut self, - timeout_ms: u32, + _timeout: Option, ) -> Result>, crate::SurfaceError> { todo!() } diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 448f8d67b77..089f8c9f435 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -527,10 +527,13 @@ impl SwapChain { self.raw } - unsafe fn wait(&mut self, timeout: Option) -> Result { + unsafe fn wait( + &mut self, + timeout: Option, + ) -> Result { let timeout_ms = match timeout { Some(duration) => duration.as_millis() as u32, - None => winbase::INFINITE + None => winbase::INFINITE, }; match synchapi::WaitForSingleObject(self.waitable, timeout_ms) { winbase::WAIT_ABANDONED | winbase::WAIT_FAILED => Err(crate::SurfaceError::Lost), diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 18b632d4cb8..811d86da071 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -214,10 +214,12 @@ impl super::Instance { /// - `raw_instance` must be created respecting `driver_api_version`, `extensions` and `flags` /// - `extensions` must be a superset of `required_extensions()` and must be created from the /// same entry, driver_api_version and flags. + #[allow(clippy::too_many_arguments)] pub unsafe fn from_raw( entry: ash::Entry, raw_instance: ash::Instance, driver_api_version: u32, + android_sdk_version: u32, extensions: Vec<&'static CStr>, flags: crate::InstanceFlags, has_nv_optimus: bool, @@ -283,6 +285,7 @@ impl super::Instance { entry, has_nv_optimus, driver_api_version, + android_sdk_version, }), extensions, }) @@ -557,6 +560,20 @@ impl crate::Instance for super::Instance { layers }; + #[cfg(target_os = "android")] + let android_sdk_version = { + // See: https://developer.android.com/reference/android/os/Build.VERSION_CODES + let mut prop = android_properties::getprop("ro.build.version.sdk"); + if let Some(val) = prop.value() { + u32::from_str_radix(&val, 10) + .expect("Failed to parse ro.build.version.sdk property") + } else { + panic!("Couldn't read ro.build.version.sdk system property"); + } + }; + #[cfg(not(target_os = "android"))] + let android_sdk_version = 0; + let vk_instance = { let str_pointers = layers .iter() @@ -583,6 +600,7 @@ impl crate::Instance for super::Instance { entry, vk_instance, driver_api_version, + android_sdk_version, extensions, desc.flags, has_nv_optimus, @@ -707,15 +725,28 @@ impl crate::Surface for super::Surface { unsafe fn acquire_texture( &mut self, - timeout: Option + timeout: Option, ) -> Result>, crate::SurfaceError> { let sc = self.swapchain.as_mut().unwrap(); - let timeout_ns = match timeout { + let mut timeout_ns = match timeout { Some(duration) => duration.as_nanos() as u64, - None => u64::MAX + None => u64::MAX, }; + // AcquireNextImageKHR on Android (prior to Android 11) doesn't support timeouts + // and will also log verbose warnings if tying to use a timeout. + // + // Android 10 implementation for reference: + // https://android.googlesource.com/platform/frameworks/native/+/refs/tags/android-mainline-10.0.0_r13/vulkan/libvulkan/swapchain.cpp#1426 + // Android 11 implementation for reference: + // https://android.googlesource.com/platform/frameworks/native/+/refs/tags/android-mainline-11.0.0_r45/vulkan/libvulkan/swapchain.cpp#1438 + // + // Android 11 corresponds to an SDK_INT/ro.build.version.sdk of 30 + if cfg!(target_os = "android") && self.instance.android_sdk_version < 30 { + timeout_ns = u64::MAX; + } + // will block if no image is available let (index, suboptimal) = match sc diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index b3e1a0aa7f7..f79d9e00eea 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -87,6 +87,7 @@ struct InstanceShared { get_physical_device_properties: Option, entry: ash::Entry, has_nv_optimus: bool, + android_sdk_version: u32, driver_api_version: u32, }