From 3a61f4b4fb18cd9444eca223261f131a87d65c65 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Thu, 13 Apr 2023 00:40:57 +0200 Subject: [PATCH] ndk/native_window: Add `lock()` to blit raw pixel data --- README.md | 7 ++-- ndk/CHANGELOG.md | 1 + ndk/src/hardware_buffer_format.rs | 32 +++++++++++++++++ ndk/src/native_activity.rs | 4 +-- ndk/src/native_window.rs | 57 +++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cd049720..13ab3b1f 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,13 @@ > ndk-build | https://github.com/rust-mobile/cargo-apk | > cargo-apk | https://github.com/rust-mobile/cargo-apk | -[![Rust](https://github.com/rust-mobile/ndk/workflows/Rust/badge.svg)](https://github.com/rust-mobile/ndk/actions) ![MIT license](https://img.shields.io/badge/License-MIT-green.svg) ![APACHE2 license](https://img.shields.io/badge/License-APACHE2-green.svg) +[![ci](https://github.com/rust-mobile/ndk/actions/workflows/rust.yml/badge.svg)](https://github.com/rust-mobile/ndk/actions/workflows/rust.yml) ![MIT license](https://img.shields.io/badge/License-MIT-green.svg) ![APACHE2 license](https://img.shields.io/badge/License-APACHE2-green.svg) Rust bindings to the [Android NDK](https://developer.android.com/ndk) Name | Description | Badges --- | --- | --- -[`ndk-sys`](./ndk-sys) | Raw FFI bindings to the NDK | [![crates.io](https://img.shields.io/crates/v/ndk-sys.svg)](https://crates.io/crates/ndk-sys) [![crates.io](https://docs.rs/ndk-sys/badge.svg)](https://docs.rs/ndk-sys) [![MSRV](https://img.shields.io/badge/rustc-1.60.0+-ab6000.svg)](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html) -[`ndk`](./ndk) | Safe abstraction of the bindings | [![crates.io](https://img.shields.io/crates/v/ndk.svg)](https://crates.io/crates/ndk) [![crates.io](https://docs.rs/ndk/badge.svg)](https://docs.rs/ndk) [![MSRV](https://img.shields.io/badge/rustc-1.64.0+-ab6000.svg)](https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html) - +[`ndk-sys`](./ndk-sys) | Raw FFI bindings to the NDK | [![crates.io](https://img.shields.io/crates/v/ndk-sys.svg)](https://crates.io/crates/ndk-sys) [![Docs](https://docs.rs/ndk-sys/badge.svg)](https://docs.rs/ndk-sys) [![MSRV](https://img.shields.io/badge/rustc-1.60.0+-ab6000.svg)](https://blog.rust-lang.org/2022/04/07/Rust-1.60.0.html) +[`ndk`](./ndk) | Safe abstraction of the bindings | [![crates.io](https://img.shields.io/crates/v/ndk.svg)](https://crates.io/crates/ndk) [![Docs](https://docs.rs/ndk/badge.svg)](https://docs.rs/ndk) [![MSRV](https://img.shields.io/badge/rustc-1.64.0+-ab6000.svg)](https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html) See these [`ndk-examples`](https://github.com/rust-mobile/cargo-apk/tree/main/examples/examples) and these [`rust-android-examples`](https://github.com/rust-mobile/rust-android-examples) for examples using the NDK. diff --git a/ndk/CHANGELOG.md b/ndk/CHANGELOG.md index 14b8202c..484c0598 100644 --- a/ndk/CHANGELOG.md +++ b/ndk/CHANGELOG.md @@ -8,6 +8,7 @@ - **Breaking:** Upgrade to [`ndk-sys 0.5.0`](../ndk-sys/CHANGELOG.md#050-TODO). (#370) - **Breaking:** Upgrade `bitflags` crate from `1` to `2`. (#394) - **Breaking:** Upgrade `num_enum` crate from `0.5.1` to `0.6`. (#398) +- native_window: Add `lock()` to blit raw pixel data. (#404) # 0.7.0 (2022-07-24) diff --git a/ndk/src/hardware_buffer_format.rs b/ndk/src/hardware_buffer_format.rs index e5a21fb4..891c0fe7 100644 --- a/ndk/src/hardware_buffer_format.rs +++ b/ndk/src/hardware_buffer_format.rs @@ -16,6 +16,7 @@ pub enum HardwareBufferFormat { R8G8B8_UNORM = ffi::AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM.0, /// Matches deprecated [`ffi::ANativeWindow_LegacyFormat::WINDOW_FORMAT_RGB_565`]. R5G6B5_UNORM = ffi::AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM.0, + #[cfg(feature = "api-level-26")] R16G16B16A16_FLOAT = ffi::AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT.0, #[cfg(feature = "api-level-26")] R10G10B10A2_UNORM = ffi::AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM.0, @@ -36,3 +37,34 @@ pub enum HardwareBufferFormat { #[cfg(feature = "api-level-26")] Y8Cb8Cr8_420 = ffi::AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420.0, } + +impl HardwareBufferFormat { + pub fn bytes_per_pixel(self) -> usize { + match self { + Self::R8G8B8A8_UNORM | Self::R8G8B8X8_UNORM => 4, + #[cfg(feature = "api-level-26")] + Self::R8G8B8_UNORM => 3, + Self::R5G6B5_UNORM => 2, + #[cfg(feature = "api-level-26")] + Self::R16G16B16A16_FLOAT => 8, + #[cfg(feature = "api-level-26")] + Self::R10G10B10A2_UNORM => 4, + #[cfg(feature = "api-level-26")] + Self::BLOB => todo!(), + #[cfg(feature = "api-level-26")] + Self::D16_UNORM => 2, + #[cfg(feature = "api-level-26")] + Self::D24_UNORM => 3, + #[cfg(feature = "api-level-26")] + Self::D24_UNORM_S8_UINT => 4, + #[cfg(feature = "api-level-26")] + Self::D32_FLOAT => 4, + #[cfg(feature = "api-level-26")] + Self::D32_FLOAT_S8_UINT => 5, + #[cfg(feature = "api-level-26")] + Self::S8_UINT => 1, + #[cfg(feature = "api-level-26")] + Self::Y8Cb8Cr8_420 => 3, + } + } +} diff --git a/ndk/src/native_activity.rs b/ndk/src/native_activity.rs index bc041e84..3f5fef3a 100644 --- a/ndk/src/native_activity.rs +++ b/ndk/src/native_activity.rs @@ -67,11 +67,11 @@ unsafe impl Send for NativeActivity {} unsafe impl Sync for NativeActivity {} impl NativeActivity { - /// Create a `NativeActivity` from a pointer + /// Create a [`NativeActivity`] from a pointer /// /// # Safety /// By calling this function, you assert that it is a valid pointer to a native - /// `ANativeActivity`. + /// [`ffi::ANativeActivity`]. pub unsafe fn from_ptr(ptr: NonNull) -> Self { Self { ptr } } diff --git a/ndk/src/native_window.rs b/ndk/src/native_window.rs index 84af1ac5..77c47f0c 100644 --- a/ndk/src/native_window.rs +++ b/ndk/src/native_window.rs @@ -126,4 +126,61 @@ impl NativeWindow { pub unsafe fn to_surface(&self, env: *mut JNIEnv) -> jobject { ffi::ANativeWindow_toSurface(env, self.ptr().as_ptr()) } + + /// Lock the window's next drawing surface for writing. + /// + /// Optionally pass the region you intend to draw into `dirty_bounds`. When this function + /// returns it is updated (commonly enlarged) with the actual area the caller needs to redraw. + pub fn lock( + &self, + dirty_bounds: Option<&mut ffi::ARect>, + ) -> Result { + let dirty_bounds = match dirty_bounds { + Some(dirty_bounds) => dirty_bounds, + None => std::ptr::null_mut(), + }; + let mut out = unsafe { std::mem::zeroed() }; + let ret = unsafe { ffi::ANativeWindow_lock(self.ptr.as_ptr(), &mut out, dirty_bounds) }; + status_to_io_result(ret, NativeWindowBufferLockGuard(out, self)) + } +} + +/// Lock holding the next drawing surface for writing. It is unlocked and posted on [`drop()`]. +#[derive(Debug)] +pub struct NativeWindowBufferLockGuard<'a>(ffi::ANativeWindow_Buffer, &'a NativeWindow); + +impl<'a> NativeWindowBufferLockGuard<'a> { + /// The number of pixels that are shown horizontally. + pub fn width(&self) -> i32 { + self.0.width + } + + // The number of pixels that are shown vertically. + pub fn height(&self) -> i32 { + self.0.height + } + + /// The number of _pixels_ that a line in the buffer takes in memory. + /// + /// This may be `>= width`. + pub fn stride(&self) -> i32 { + self.0.stride + } + + /// The format of the buffer. One of [`HardwareBufferFormat`]. + pub fn format(&self) -> HardwareBufferFormat { + unsafe { std::mem::transmute(self.0.format) } + } + + /// The actual bits. + pub fn bits(&mut self) -> *mut std::ffi::c_void { + self.0.bits + } +} + +impl<'a> Drop for NativeWindowBufferLockGuard<'a> { + fn drop(&mut self) { + let ret = unsafe { ffi::ANativeWindow_unlockAndPost(self.1.ptr.as_ptr()) }; + assert_eq!(ret, 0); + } }