#![cfg(feature = "api-level-26")]
use std::{
io::Result,
mem::MaybeUninit,
ops::Deref,
os::{
fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
raw::c_void,
},
ptr::NonNull,
};
use jni_sys::{jobject, JNIEnv};
use super::{hardware_buffer_format::HardwareBufferFormat, utils::status_to_io_result};
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
#[doc(alias = "AHardwareBuffer_UsageFlags")]
pub struct HardwareBufferUsage : u64 {
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_NEVER")]
const CPU_READ_NEVER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_NEVER.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_RARELY")]
const CPU_READ_RARELY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_RARELY.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN")]
const CPU_READ_OFTEN = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_MASK")]
const CPU_READ_MASK = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_MASK.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER")]
const CPU_WRITE_NEVER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY")]
const CPU_WRITE_RARELY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN")]
const CPU_WRITE_OFTEN = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK")]
const CPU_WRITE_MASK = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE")]
const GPU_SAMPLED_IMAGE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER")]
const GPU_FRAMEBUFFER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT")]
const GPU_COLOR_OUTPUT = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY")]
const COMPOSER_OVERLAY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT")]
const PROTECTED_CONTENT = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VIDEO_ENCODE")]
const VIDEO_ENCODE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VIDEO_ENCODE.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA")]
const SENSOR_DIRECT_DATA = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER")]
const GPU_DATA_BUFFER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP")]
const GPU_CUBE_MAP = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE")]
const GPU_MIPMAP_COMPLETE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_0")]
const VENDOR_0 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_0.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_1")]
const VENDOR_1 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_1.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_2")]
const VENDOR_2 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_2.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_3")]
const VENDOR_3 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_3.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_4")]
const VENDOR_4 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_4.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_5")]
const VENDOR_5 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_5.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_6")]
const VENDOR_6 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_6.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_7")]
const VENDOR_7 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_7.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_8")]
const VENDOR_8 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_8.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_9")]
const VENDOR_9 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_9.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_10")]
const VENDOR_10 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_10.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_11")]
const VENDOR_11 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_11.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_12")]
const VENDOR_12 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_12.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_13")]
const VENDOR_13 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_13.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_14")]
const VENDOR_14 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_14.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_15")]
const VENDOR_15 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_15.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_16")]
const VENDOR_16 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_16.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_17")]
const VENDOR_17 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_17.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_18")]
const VENDOR_18 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_18.0;
#[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_19")]
const VENDOR_19 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_19.0;
}
}
impl HardwareBufferUsage {
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_MASK")]
pub fn cpu_read(self) -> HardwareBufferUsage {
self.intersection(Self::CPU_READ_MASK)
}
#[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK")]
pub fn cpu_write(self) -> HardwareBufferUsage {
self.intersection(Self::CPU_WRITE_MASK)
}
}
pub type Rect = ffi::ARect;
fn construct<T>(with_ptr: impl FnOnce(*mut T) -> i32) -> Result<T> {
let mut result = MaybeUninit::uninit();
let status = with_ptr(result.as_mut_ptr());
status_to_io_result(status).map(|()| unsafe { result.assume_init() })
}
#[derive(Debug)]
pub struct HardwareBuffer {
inner: NonNull<ffi::AHardwareBuffer>,
}
impl HardwareBuffer {
pub unsafe fn from_ptr(ptr: NonNull<ffi::AHardwareBuffer>) -> Self {
Self { inner: ptr }
}
pub fn as_ptr(&self) -> *mut ffi::AHardwareBuffer {
self.inner.as_ptr()
}
pub fn allocate(desc: HardwareBufferDesc) -> Result<HardwareBufferRef> {
unsafe {
let ptr = construct(|res| ffi::AHardwareBuffer_allocate(&desc.into_native(), res))?;
Ok(HardwareBufferRef::from_ptr(NonNull::new_unchecked(ptr)))
}
}
pub unsafe fn from_jni(env: *mut JNIEnv, hardware_buffer: jobject) -> Self {
let ptr = ffi::AHardwareBuffer_fromHardwareBuffer(env, hardware_buffer);
Self::from_ptr(NonNull::new_unchecked(ptr))
}
pub unsafe fn to_jni(&self, env: *mut JNIEnv) -> jobject {
ffi::AHardwareBuffer_toHardwareBuffer(env, self.as_ptr())
}
pub fn describe(&self) -> HardwareBufferDesc {
let desc = unsafe {
let mut result = MaybeUninit::uninit();
ffi::AHardwareBuffer_describe(self.as_ptr(), result.as_mut_ptr());
result.assume_init()
};
HardwareBufferDesc {
width: desc.width,
height: desc.height,
layers: desc.layers,
format: i32::try_from(desc.format)
.expect("i32->u32 overflow in HardwareBuffer::describe()")
.into(),
usage: HardwareBufferUsage::from_bits_retain(desc.usage),
stride: desc.stride,
}
}
#[cfg(feature = "api-level-29")]
pub fn is_supported(desc: HardwareBufferDesc) -> bool {
let res = unsafe { ffi::AHardwareBuffer_isSupported(&desc.into_native()) };
res == 1
}
#[cfg(feature = "api-level-31")]
#[doc(alias = "AHardwareBuffer_getId")]
pub fn id(&self) -> Result<u64> {
construct(|res| unsafe { ffi::AHardwareBuffer_getId(self.as_ptr(), res) })
}
pub fn lock(
&self,
usage: HardwareBufferUsage,
fence: Option<OwnedFd>,
rect: Option<Rect>,
) -> Result<*mut c_void> {
let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
let rect = match rect {
Some(rect) => &rect,
None => std::ptr::null(),
};
construct(|res| unsafe {
ffi::AHardwareBuffer_lock(self.as_ptr(), usage.bits(), fence, rect, res)
})
}
#[cfg(feature = "api-level-29")]
pub fn lock_and_get_info(
&self,
usage: HardwareBufferUsage,
fence: Option<OwnedFd>,
rect: Option<Rect>,
) -> Result<LockedPlaneInfo> {
let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
let rect = match rect {
Some(rect) => &rect,
None => std::ptr::null(),
};
let mut virtual_address = MaybeUninit::uninit();
let mut bytes_per_pixel = MaybeUninit::uninit();
let mut bytes_per_stride = MaybeUninit::uninit();
let status = unsafe {
ffi::AHardwareBuffer_lockAndGetInfo(
self.as_ptr(),
usage.bits(),
fence,
rect,
virtual_address.as_mut_ptr(),
bytes_per_pixel.as_mut_ptr(),
bytes_per_stride.as_mut_ptr(),
)
};
status_to_io_result(status).map(|()| unsafe {
LockedPlaneInfo {
virtual_address: virtual_address.assume_init(),
bytes_per_pixel: bytes_per_pixel.assume_init() as u32,
bytes_per_stride: bytes_per_stride.assume_init() as u32,
}
})
}
#[cfg(feature = "api-level-29")]
pub fn lock_planes(
&self,
usage: HardwareBufferUsage,
fence: Option<OwnedFd>,
rect: Option<Rect>,
) -> Result<HardwareBufferPlanes> {
let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
let rect = match rect {
Some(rect) => &rect,
None => std::ptr::null(),
};
let planes = construct(|res| unsafe {
ffi::AHardwareBuffer_lockPlanes(self.as_ptr(), usage.bits(), fence, rect, res)
})?;
Ok(HardwareBufferPlanes {
inner: planes,
index: 0,
})
}
pub fn unlock(&self) -> Result<()> {
let status = unsafe { ffi::AHardwareBuffer_unlock(self.as_ptr(), std::ptr::null_mut()) };
status_to_io_result(status)
}
pub fn unlock_async(&self) -> Result<Option<OwnedFd>> {
let fence = construct(|res| unsafe { ffi::AHardwareBuffer_unlock(self.as_ptr(), res) })?;
Ok(match fence {
-1 => None,
fence => Some(unsafe { OwnedFd::from_raw_fd(fence) }),
})
}
pub fn recv_handle_from_unix_socket(socket_fd: BorrowedFd<'_>) -> Result<Self> {
unsafe {
let ptr = construct(|res| {
ffi::AHardwareBuffer_recvHandleFromUnixSocket(socket_fd.as_raw_fd(), res)
})?;
Ok(Self::from_ptr(NonNull::new_unchecked(ptr)))
}
}
pub fn send_handle_to_unix_socket(&self, socket_fd: BorrowedFd<'_>) -> Result<()> {
let status = unsafe {
ffi::AHardwareBuffer_sendHandleToUnixSocket(self.as_ptr(), socket_fd.as_raw_fd())
};
status_to_io_result(status)
}
pub fn acquire(&self) -> HardwareBufferRef {
unsafe {
ffi::AHardwareBuffer_acquire(self.as_ptr());
HardwareBufferRef::from_ptr(self.inner)
}
}
}
#[derive(Debug)]
pub struct HardwareBufferRef {
inner: HardwareBuffer,
}
impl HardwareBufferRef {
pub unsafe fn from_ptr(ptr: NonNull<ffi::AHardwareBuffer>) -> Self {
Self {
inner: HardwareBuffer { inner: ptr },
}
}
}
impl Deref for HardwareBufferRef {
type Target = HardwareBuffer;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl Drop for HardwareBufferRef {
fn drop(&mut self) {
unsafe { ffi::AHardwareBuffer_release(self.inner.as_ptr()) }
}
}
impl Clone for HardwareBufferRef {
fn clone(&self) -> Self {
self.acquire()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct HardwareBufferDesc {
pub width: u32,
pub height: u32,
pub layers: u32,
pub format: HardwareBufferFormat,
pub usage: HardwareBufferUsage,
pub stride: u32,
}
impl HardwareBufferDesc {
fn into_native(self) -> ffi::AHardwareBuffer_Desc {
ffi::AHardwareBuffer_Desc {
width: self.width,
height: self.height,
layers: self.layers,
format: i32::from(self.format)
.try_into()
.expect("i32->u32 overflow in HardwareBufferDesc::into_native()"),
usage: self.usage.bits(),
stride: self.stride,
rfu0: 0,
rfu1: 0,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct LockedPlaneInfo {
pub virtual_address: *mut c_void,
pub bytes_per_pixel: u32,
pub bytes_per_stride: u32,
}
#[derive(Debug)]
pub struct HardwareBufferPlanes {
inner: ffi::AHardwareBuffer_Planes,
index: u32,
}
impl Iterator for HardwareBufferPlanes {
type Item = LockedPlaneInfo;
fn next(&mut self) -> Option<LockedPlaneInfo> {
if self.index == self.inner.planeCount {
None
} else {
let plane = self.inner.planes[self.index as usize];
self.index += 1;
Some(LockedPlaneInfo {
virtual_address: plane.data,
bytes_per_pixel: plane.pixelStride,
bytes_per_stride: plane.rowStride,
})
}
}
}