diff options
| -rw-r--r-- | libs/nativewindow/TEST_MAPPING | 6 | ||||
| -rw-r--r-- | libs/nativewindow/rust/Android.bp | 87 | ||||
| -rw-r--r-- | libs/nativewindow/rust/src/lib.rs | 260 | ||||
| -rw-r--r-- | libs/nativewindow/rust/sys/nativewindow_bindings.h | 20 |
4 files changed, 373 insertions, 0 deletions
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..9d6425bfe0 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ { + "name": "libnativewindow_bindgen_test" + }, + { "name": "libnativewindow_test" + }, + { + "name": "libnativewindow_rs-internal_test" } ] } diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..dc1575ca33 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libnativewindow", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen"], + crate_name: "nativewindow_bindgen_test", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..a5bcc6293a --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,260 @@ +// Copyright (C) 2023 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use std::os::raw::c_void; +use std::ptr; + +/// Wrapper around an opaque C AHardwareBuffer. +pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); + +impl AHardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option<Self> { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut buffer = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + + if status == 0 { + Some(Self(buffer)) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { + assert!(!buffer_ptr.is_null()); + Self(buffer_ptr as *mut ffi::AHardwareBuffer) + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: Neither pointers can be null. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for AHardwareBuffer { + fn drop(&mut self) { + // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have + // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw + // pointer requiring callers to ensure the refcount is managed appropriately. + unsafe { ffi::AHardwareBuffer_release(self.0) } + } +} + +#[cfg(test)] +mod ahardwarebuffer_tests { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = AHardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + #[should_panic] + fn take_from_raw_panics_on_null() { + unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; + } + + #[test] + fn take_from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..e652aee711 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/data_space.h> +#include <android/hardware_buffer.h> +#include <android/hdr_metadata.h> +#include <android/native_window.h> |