ndk/
hardware_buffer.rs

1//! Bindings for [`AHardwareBuffer`]
2//!
3//! [`AHardwareBuffer`]: https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer
4
5#![cfg(feature = "api-level-26")]
6
7use std::{
8    io::Result,
9    mem::MaybeUninit,
10    ops::Deref,
11    os::{
12        fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
13        raw::c_void,
14    },
15    ptr::NonNull,
16};
17
18use jni_sys::{jobject, JNIEnv};
19
20use super::{hardware_buffer_format::HardwareBufferFormat, utils::status_to_io_result};
21
22bitflags::bitflags! {
23    /// Buffer usage flags, specifying how the buffer will be accessed.
24    #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
25    #[doc(alias = "AHardwareBuffer_UsageFlags")]
26    pub struct HardwareBufferUsage : u64 {
27        /// The buffer will never be locked for direct CPU reads using the
28        /// [`HardwareBuffer::lock()`] function. Note that reading the buffer using OpenGL or Vulkan
29        /// functions or memory mappings is still allowed.
30        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_NEVER")]
31        const CPU_READ_NEVER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_NEVER.0;
32        /// The buffer will sometimes be locked for direct CPU reads using the
33        /// [`HardwareBuffer::lock()`] function. Note that reading the buffer using OpenGL or Vulkan
34        /// functions or memory mappings does not require the presence of this flag.
35        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_RARELY")]
36        const CPU_READ_RARELY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_RARELY.0;
37        /// The buffer will often be locked for direct CPU reads using the
38        /// [`HardwareBuffer::lock()`] function. Note that reading the buffer using OpenGL or Vulkan
39        /// functions or memory mappings does not require the presence of this flag.
40        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN")]
41        const CPU_READ_OFTEN = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0;
42        /// CPU read value mask.
43        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_MASK")]
44        const CPU_READ_MASK = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_MASK.0;
45
46        /// The buffer will never be locked for direct CPU writes using the
47        /// [`HardwareBuffer::lock()`] function. Note that writing the buffer using OpenGL or Vulkan
48        /// functions or memory mappings is still allowed.
49        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER")]
50        const CPU_WRITE_NEVER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER.0;
51        /// The buffer will sometimes be locked for direct CPU writes using the
52        /// [`HardwareBuffer::lock()`] function. Note that writing the buffer using OpenGL or Vulkan
53        /// functions or memory mappings does not require the presence of this flag.
54        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY")]
55        const CPU_WRITE_RARELY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY.0;
56        /// The buffer will often be locked for direct CPU writes using the
57        /// [`HardwareBuffer::lock()`] function. Note that writing the buffer using OpenGL or Vulkan
58        /// functions or memory mappings does not require the presence of this flag.
59        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN")]
60        const CPU_WRITE_OFTEN = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.0;
61        /// CPU write value mask.
62        #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK")]
63        const CPU_WRITE_MASK = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK.0;
64
65        /// The buffer will be read from by the GPU as a texture.
66        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE")]
67        const GPU_SAMPLED_IMAGE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.0;
68        /// The buffer will be written to by the GPU as a framebuffer attachment.
69        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER")]
70        const GPU_FRAMEBUFFER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER.0;
71        /// The buffer will be written to by the GPU as a framebuffer attachment.
72        ///
73        /// Note that the name of this flag is somewhat misleading: it does not imply that the
74        /// buffer contains a color format. A buffer with depth or stencil format that will be
75        /// used as a framebuffer attachment should also have this flag. Use the equivalent flag
76        /// [`HardwareBufferusage::GPU_FRAMEBUFFER`] to avoid this confusion.
77        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT")]
78        const GPU_COLOR_OUTPUT = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT.0;
79        /// The buffer will be used as a composer HAL overlay layer.
80        ///
81        /// This flag is currently only needed when using [`SurfaceTransaction::set_buffer()`] to
82        /// set a buffer. In all other cases, the framework adds this flag internally to buffers
83        /// that could be presented in a composer overlay. [`SurfaceTransaction::set_buffer()`]
84        /// is special because it uses buffers allocated directly through
85        /// [`HardwareBuffer::allocate()`] instead of buffers allocated by the framework.
86        #[doc(alias = "AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY")]
87        const COMPOSER_OVERLAY = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_COMPOSER_OVERLAY.0;
88        /// The buffer is protected from direct CPU access or being read by non-secure hardware,
89        /// such as video encoders.
90        ///
91        /// This flag is incompatible with CPU read and write flags. It is mainly used when handling
92        /// DRM video. Refer to the EGL extension [`EGL_EXT_protected_content`] and GL extension
93        /// [`GL_EXT_protected_textures`] for more information on how these buffers are expected
94        /// to behave.
95        ///
96        /// [`EGL_EXT_protected_content`]: https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_protected_content.txt
97        /// [`GL_EXT_protected_textures`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_protected_textures.txt
98        #[doc(alias = "AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT")]
99        const PROTECTED_CONTENT = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT.0;
100        /// The buffer will be read by a hardware video encoder.
101        #[doc(alias = "AHARDWAREBUFFER_USAGE_VIDEO_ENCODE")]
102        const VIDEO_ENCODE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VIDEO_ENCODE.0;
103        /// The buffer will be used for direct writes from sensors. When this flag is present, the
104        /// format must be [`HardwareBufferFormat::Blob`].
105        #[doc(alias = "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA")]
106        const SENSOR_DIRECT_DATA = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA.0;
107        /// The buffer will be used as a shader storage or uniform buffer object. When this flag is
108        /// present, the format must be [`HardwareBufferFormat::Blob`].
109        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER")]
110        const GPU_DATA_BUFFER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER.0;
111        /// The buffer will be used as a cube map texture. When this flag is present, the buffer
112        /// must have a layer count that is a multiple of 6. Note that buffers with this flag must
113        /// be bound to OpenGL textures using the extension [`GL_EXT_EGL_image_storage`] instead
114        /// of [`GL_KHR_EGL_image`].
115        ///
116        /// [`GL_EXT_EGL_image_storage`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
117        // TODO: This extension only exists for VG. Reported at https://issuetracker.google.com/issues/300602767#comment16
118        /// [`GL_KHR_EGL_image`]: https://registry.khronos.org/OpenVG/extensions/KHR/VG_KHR_EGL_image.txt
119        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP")]
120        const GPU_CUBE_MAP = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP.0;
121        /// The buffer contains a complete mipmap hierarchy. Note that buffers with this flag must
122        /// be bound to OpenGL textures using the extension [`GL_EXT_EGL_image_storage`] instead
123        /// of [`GL_KHR_EGL_image`].
124        ///
125        /// [`GL_EXT_EGL_image_storage`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
126        // TODO: This extension only exists for VG. Reported at https://issuetracker.google.com/issues/300602767#comment16
127        /// [`GL_KHR_EGL_image`]: https://registry.khronos.org/OpenVG/extensions/KHR/VG_KHR_EGL_image.txt
128        #[doc(alias = "AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE")]
129        const GPU_MIPMAP_COMPLETE = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE.0;
130
131        // TODO: Only available in a newer NDK
132        // /// Usage: The buffer is used for front-buffer rendering. When front-buffering rendering
133        // /// is specified, different usages may adjust their behavior as a result. For example, when
134        // /// used as [`HardwareBufferFormat::GPU_COLOR_OUTPUT`] the buffer will behave similar to a
135        // /// single-buffered window. When used with [`HardwareBufferFormat::COMPOSER_OVERLAY`], the
136        // /// system will try to prioritize the buffer receiving an overlay plane & avoid caching it
137        // /// in intermediate composition buffers.
138        // #[doc(alias = "AHARDWAREBUFFER_USAGE_FRONT_BUFFER")]
139        // const USAGE_FRONT_BUFFER = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_FRONT_BUFFER.0;
140
141        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_0")]
142        const VENDOR_0 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_0.0;
143        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_1")]
144        const VENDOR_1 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_1.0;
145        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_2")]
146        const VENDOR_2 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_2.0;
147        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_3")]
148        const VENDOR_3 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_3.0;
149        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_4")]
150        const VENDOR_4 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_4.0;
151        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_5")]
152        const VENDOR_5 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_5.0;
153        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_6")]
154        const VENDOR_6 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_6.0;
155        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_7")]
156        const VENDOR_7 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_7.0;
157        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_8")]
158        const VENDOR_8 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_8.0;
159        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_9")]
160        const VENDOR_9 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_9.0;
161        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_10")]
162        const VENDOR_10 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_10.0;
163        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_11")]
164        const VENDOR_11 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_11.0;
165        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_12")]
166        const VENDOR_12 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_12.0;
167        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_13")]
168        const VENDOR_13 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_13.0;
169        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_14")]
170        const VENDOR_14 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_14.0;
171        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_15")]
172        const VENDOR_15 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_15.0;
173        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_16")]
174        const VENDOR_16 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_16.0;
175        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_17")]
176        const VENDOR_17 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_17.0;
177        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_18")]
178        const VENDOR_18 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_18.0;
179        #[doc(alias = "AHARDWAREBUFFER_USAGE_VENDOR_19")]
180        const VENDOR_19 = ffi::AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_VENDOR_19.0;
181    }
182}
183
184impl HardwareBufferUsage {
185    /// Helper to read [`HardwareBufferUsage::CPU_READ_MASK`] values.
186    #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_READ_MASK")]
187    pub fn cpu_read(self) -> HardwareBufferUsage {
188        self.intersection(Self::CPU_READ_MASK)
189    }
190
191    /// Helper to read [`HardwareBufferUsage::CPU_WRITE_MASK`] values.
192    #[doc(alias = "AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK")]
193    pub fn cpu_write(self) -> HardwareBufferUsage {
194        self.intersection(Self::CPU_WRITE_MASK)
195    }
196}
197
198pub type Rect = ffi::ARect;
199
200fn construct<T>(with_ptr: impl FnOnce(*mut T) -> i32) -> Result<T> {
201    let mut result = MaybeUninit::uninit();
202    let status = with_ptr(result.as_mut_ptr());
203    status_to_io_result(status).map(|()| unsafe { result.assume_init() })
204}
205
206/// A native [`AHardwareBuffer *`]
207///
208/// [`HardwareBuffer`] objects represent chunks of memory that can be accessed by various hardware
209/// components in the system.
210///
211/// It can be easily converted to the Java counterpart [`android.hardware.HardwareBuffer`] and
212/// passed between processes using Binder. All operations involving [`HardwareBuffer`] and
213/// [`android.hardware.HardwareBuffer`] are zero-copy, i.e., passing [`HardwareBuffer`] to another
214/// process creates a shared view of the same region of memory.
215///
216/// [`HardwareBuffer`] can be bound to EGL/OpenGL and Vulkan primitives. For EGL, use the extension
217/// function [`eglGetNativeClientBufferANDROID`] to obtain an `EGLClientBuffer` and pass it
218/// directly to [`eglCreateImageKHR`]. Refer to the EGL extensions
219/// [`EGL_ANDROID_get_native_client_buffer`] and [`EGL_ANDROID_image_native_buffer`] for more
220/// information. In Vulkan, the contents of the [`HardwareBuffer`] can be accessed as [external
221/// memory]. See the [`VK_ANDROID_external_memory_android_hardware_buffer`] extension for details.
222///
223/// [`AHardwareBuffer *`]: https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer
224/// [`android.hardware.HardwareBuffer`]: https://developer.android.com/reference/android/hardware/HardwareBuffer
225/// [`eglGetNativeClientBufferANDROID`]: https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
226/// [`eglCreateImageKHR`]: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt
227/// [`EGL_ANDROID_get_native_client_buffer`]: https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_get_native_client_buffer.txt
228/// [`EGL_ANDROID_image_native_buffer`]: https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_image_native_buffer.txt
229/// [external memory]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_memory.html
230/// [`VK_ANDROID_external_memory_android_hardware_buffer`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VK_ANDROID_external_memory_android_hardware_buffer.html
231#[derive(Debug)]
232pub struct HardwareBuffer {
233    inner: NonNull<ffi::AHardwareBuffer>,
234}
235
236impl HardwareBuffer {
237    /// Create an _unowned_ [`HardwareBuffer`] from a native pointer
238    ///
239    /// To wrap a strong reference (that is `release`d on [`Drop`]), call
240    /// [`HardwareBufferRef::from_ptr()`] instead.
241    ///
242    /// # Safety
243    /// By calling this function, you assert that it is a valid pointer to an NDK
244    /// [`ffi::AHardwareBuffer`] that is kept alive externally, or retrieve a strong reference
245    /// using [`HardwareBuffer::acquire()`].
246    pub unsafe fn from_ptr(ptr: NonNull<ffi::AHardwareBuffer>) -> Self {
247        Self { inner: ptr }
248    }
249
250    /// Returns the underlying [`ffi::AHardwareBuffer`] pointer
251    ///
252    /// See the top-level [`HardwareBuffer`] struct documentation for (graphics) APIs that accept
253    /// this pointer.
254    pub fn as_ptr(&self) -> *mut ffi::AHardwareBuffer {
255        self.inner.as_ptr()
256    }
257
258    /// Allocates a buffer that matches the passed [`HardwareBufferDesc`].
259    ///
260    /// If allocation succeeds, the buffer can be used according to the usage flags specified in
261    /// its description. If a buffer is used in ways not compatible with its usage flags, the
262    /// results are undefined and may include program termination.
263    pub fn allocate(desc: HardwareBufferDesc) -> Result<HardwareBufferRef> {
264        unsafe {
265            let ptr = construct(|res| ffi::AHardwareBuffer_allocate(&desc.into_native(), res))?;
266
267            Ok(HardwareBufferRef::from_ptr(NonNull::new_unchecked(ptr)))
268        }
269    }
270
271    /// Create a [`HardwareBuffer`] from JNI pointers
272    ///
273    /// # Safety
274    /// By calling this function, you assert that these are valid pointers to JNI objects.
275    ///
276    /// This method does not acquire any additional reference to the AHardwareBuffer that is
277    /// returned. To keep the [`HardwareBuffer`] alive after the [Java `HardwareBuffer`] object
278    /// is closed, explicitly or by the garbage collector, be sure to retrieve a strong reference
279    /// using [`HardwareBuffer::acquire()`].
280    ///
281    /// [Java `HardwareBuffer`]: https://developer.android.com/reference/android/hardware/HardwareBuffer
282    pub unsafe fn from_jni(env: *mut JNIEnv, hardware_buffer: jobject) -> Self {
283        let ptr = ffi::AHardwareBuffer_fromHardwareBuffer(env, hardware_buffer);
284
285        Self::from_ptr(NonNull::new_unchecked(ptr))
286    }
287
288    /// # Safety
289    /// By calling this function, you assert that `env` is a valid pointer to a [`JNIEnv`].
290    pub unsafe fn to_jni(&self, env: *mut JNIEnv) -> jobject {
291        ffi::AHardwareBuffer_toHardwareBuffer(env, self.as_ptr())
292    }
293
294    /// Return a description of the [`HardwareBuffer`] in the passed [`HardwareBufferDesc`] struct.
295    pub fn describe(&self) -> HardwareBufferDesc {
296        let desc = unsafe {
297            let mut result = MaybeUninit::uninit();
298            ffi::AHardwareBuffer_describe(self.as_ptr(), result.as_mut_ptr());
299            result.assume_init()
300        };
301
302        HardwareBufferDesc {
303            width: desc.width,
304            height: desc.height,
305            layers: desc.layers,
306            format: i32::try_from(desc.format)
307                .expect("i32->u32 overflow in HardwareBuffer::describe()")
308                .into(),
309            usage: HardwareBufferUsage::from_bits_retain(desc.usage),
310            stride: desc.stride,
311        }
312    }
313
314    /// Test whether the given format and usage flag combination is allocatable.
315    ///
316    /// If this function returns [`true`], it means that a buffer with the given description can
317    /// be allocated on this implementation, unless resource exhaustion occurs. If this function
318    /// returns [`false`], it means that the allocation of the given description will never
319    /// succeed.
320    ///
321    /// The return value of this function may depend on all fields in the description, except
322    /// [`HardwareBufferDesc::stride`], which is always ignored. For example, some implementations
323    /// have implementation-defined limits on texture size and layer count.
324    #[cfg(feature = "api-level-29")]
325    pub fn is_supported(desc: HardwareBufferDesc) -> bool {
326        let res = unsafe { ffi::AHardwareBuffer_isSupported(&desc.into_native()) };
327        res == 1
328    }
329
330    /// Get the system-wide unique id for this [`HardwareBuffer`].
331    #[cfg(feature = "api-level-31")]
332    #[doc(alias = "AHardwareBuffer_getId")]
333    pub fn id(&self) -> Result<u64> {
334        construct(|res| unsafe { ffi::AHardwareBuffer_getId(self.as_ptr(), res) })
335    }
336
337    /// Lock the [`HardwareBuffer`] for direct CPU access.
338    ///
339    /// This function can lock the buffer for either reading or writing. It may block if the
340    /// hardware needs to finish rendering, if CPU caches need to be synchronized, or possibly for
341    /// other implementation-specific reasons.
342    ///
343    /// The [`HardwareBuffer`] must have one layer, otherwise the call will fail.
344    ///
345    /// If `fence` is not [`None`], it specifies a fence file descriptor on which to wait before
346    /// locking the buffer. If it's [`None`], the caller is responsible for ensuring that writes
347    /// to the buffer have completed before calling this function. Using this parameter is more
348    /// efficient than waiting on the fence and then calling this function.
349    ///
350    /// The `usage` parameter may only specify `HardwareBufferUsage::CPU_*`. If set, then the
351    /// address of the buffer in virtual memory is returned. The flags must also be compatible with
352    /// usage flags specified at buffer creation: if a read flag is passed, the buffer must have
353    /// been created with [`HardwareBufferUsage::CPU_READ_RARELY`] or
354    /// [`HardwareBufferUsage::CPU_READ_OFTEN`]. If a write flag is passed, it must have been
355    /// created with [`HardwareBufferUsage::CPU_WRITE_RARELY`] or
356    /// [`HardwareBufferUsage::CPU_WRITE_OFTEN`].
357    ///
358    /// If `rect` is not [`None`], the caller promises to modify only data in the area specified by
359    /// `rect`. If rect is [`None`], the caller may modify the contents of the entire buffer. The
360    /// content of the buffer outside of the specified rect is NOT modified by this call.
361    ///
362    /// It is legal for several different threads to lock a buffer for read access; none of the
363    /// threads are blocked.
364    ///
365    /// Locking a buffer simultaneously for write or read/write is undefined, but will neither
366    /// terminate the process nor block the caller. This function may return an error or leave the
367    /// buffer's content in an indeterminate state.
368    ///
369    /// If the buffer has [`HardwareBufferFormat::BLOB`], it is legal lock it for reading and
370    /// writing in multiple threads and/or processes simultaneously, and the contents of the buffer
371    /// behave like shared memory.
372    pub fn lock(
373        &self,
374        usage: HardwareBufferUsage,
375        fence: Option<OwnedFd>,
376        rect: Option<Rect>,
377    ) -> Result<*mut c_void> {
378        let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
379        let rect = match rect {
380            Some(rect) => &rect,
381            None => std::ptr::null(),
382        };
383        construct(|res| unsafe {
384            ffi::AHardwareBuffer_lock(self.as_ptr(), usage.bits(), fence, rect, res)
385        })
386    }
387
388    /// Lock a [`HardwareBuffer`] for direct CPU access.
389    ///
390    /// This function is the same as the above [`lock()`][Self::lock()] function, but passes back
391    /// additional information about the bytes per pixel and the bytes per stride of the locked
392    /// buffer. If the bytes per pixel or bytes per stride are unknown or variable, or if the
393    /// underlying mapper implementation does not support returning additional information, then
394    /// this call will fail with [`std::io::Error::kind()`] = [`std::io::ErrorKind::Unsupported`].
395    #[cfg(feature = "api-level-29")]
396    pub fn lock_and_get_info(
397        &self,
398        usage: HardwareBufferUsage,
399        fence: Option<OwnedFd>,
400        rect: Option<Rect>,
401    ) -> Result<LockedPlaneInfo> {
402        let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
403        let rect = match rect {
404            Some(rect) => &rect,
405            None => std::ptr::null(),
406        };
407        let mut virtual_address = MaybeUninit::uninit();
408        let mut bytes_per_pixel = MaybeUninit::uninit();
409        let mut bytes_per_stride = MaybeUninit::uninit();
410        let status = unsafe {
411            ffi::AHardwareBuffer_lockAndGetInfo(
412                self.as_ptr(),
413                usage.bits(),
414                fence,
415                rect,
416                virtual_address.as_mut_ptr(),
417                bytes_per_pixel.as_mut_ptr(),
418                bytes_per_stride.as_mut_ptr(),
419            )
420        };
421        status_to_io_result(status).map(|()| unsafe {
422            LockedPlaneInfo {
423                virtual_address: virtual_address.assume_init(),
424                bytes_per_pixel: bytes_per_pixel.assume_init() as u32,
425                bytes_per_stride: bytes_per_stride.assume_init() as u32,
426            }
427        })
428    }
429
430    /// Lock a potentially multi-planar [`HardwareBuffer`] for direct CPU access.
431    ///
432    /// This function is similar to [`lock()`][Self::lock()], but can lock multi-planar formats.
433    /// Note, that multi-planar should not be confused with multi-layer images, which this locking
434    /// function does not support.
435    ///
436    /// YUV formats are always represented by three separate planes of data, one for each color
437    /// plane. The order of planes in the array is guaranteed such that plane #0 is always `Y`,
438    /// plane #1 is always `U` (`Cb`), and plane #2 is always `V` (`Cr`). All other formats are
439    /// represented by a single plane.
440    ///
441    /// Additional information always accompanies the buffers, describing the row stride and the
442    /// pixel stride for each plane.
443    ///
444    /// In case the buffer cannot be locked, this will return zero planes.
445    ///
446    /// See the [`lock()`][Self::lock()] documentation for all other locking semantics.
447    #[cfg(feature = "api-level-29")]
448    pub fn lock_planes(
449        &self,
450        usage: HardwareBufferUsage,
451        fence: Option<OwnedFd>,
452        rect: Option<Rect>,
453    ) -> Result<HardwareBufferPlanes> {
454        let fence = fence.map_or(-1, IntoRawFd::into_raw_fd);
455        let rect = match rect {
456            Some(rect) => &rect,
457            None => std::ptr::null(),
458        };
459        let planes = construct(|res| unsafe {
460            ffi::AHardwareBuffer_lockPlanes(self.as_ptr(), usage.bits(), fence, rect, res)
461        })?;
462
463        Ok(HardwareBufferPlanes {
464            inner: planes,
465            index: 0,
466        })
467    }
468
469    /// Unlock the [`HardwareBuffer`] from direct CPU access.
470    ///
471    /// Must be called after all changes to the buffer are completed by the caller. The function
472    /// will block until all work is completed. See [`unlock_async()`][Self::unlock_async()] for
473    /// a non-blocking variant that returns a file descriptor to be signaled on unlocking instead.
474    pub fn unlock(&self) -> Result<()> {
475        let status = unsafe { ffi::AHardwareBuffer_unlock(self.as_ptr(), std::ptr::null_mut()) };
476        status_to_io_result(status)
477    }
478
479    /// Unlock the [`HardwareBuffer`] from direct CPU access.
480    ///
481    /// Returns a fence file descriptor that will become signaled when unlocking is completed, or
482    /// [`None`] if unlocking is already finished. The caller is responsible for closing the file
483    /// descriptor once it's no longer needed. See [`unlock()`][Self::unlock()] for a variant that
484    /// blocks instead.
485    pub fn unlock_async(&self) -> Result<Option<OwnedFd>> {
486        let fence = construct(|res| unsafe { ffi::AHardwareBuffer_unlock(self.as_ptr(), res) })?;
487        Ok(match fence {
488            -1 => None,
489            fence => Some(unsafe { OwnedFd::from_raw_fd(fence) }),
490        })
491    }
492
493    /// Receive a [`HardwareBuffer`] from an `AF_UNIX` socket.
494    ///
495    /// `AF_UNIX` sockets are wrapped by [`std::os::unix::net::UnixListener`] and
496    /// [`std::os::unix::net::UnixStream`] in Rust and have a corresponding
497    /// [`std::os::unix::io::AsFd::as_fd()`] implementation.
498    pub fn recv_handle_from_unix_socket(socket_fd: BorrowedFd<'_>) -> Result<Self> {
499        unsafe {
500            let ptr = construct(|res| {
501                ffi::AHardwareBuffer_recvHandleFromUnixSocket(socket_fd.as_raw_fd(), res)
502            })?;
503
504            Ok(Self::from_ptr(NonNull::new_unchecked(ptr)))
505        }
506    }
507
508    /// Send the [`HardwareBuffer`] to an `AF_UNIX` socket.
509    ///
510    /// `AF_UNIX` sockets are wrapped by [`std::os::unix::net::UnixListener`] and
511    /// [`std::os::unix::net::UnixStream`] in Rust and have a corresponding
512    /// [`std::os::unix::io::AsFd::as_fd()`] implementation.
513    pub fn send_handle_to_unix_socket(&self, socket_fd: BorrowedFd<'_>) -> Result<()> {
514        let status = unsafe {
515            ffi::AHardwareBuffer_sendHandleToUnixSocket(self.as_ptr(), socket_fd.as_raw_fd())
516        };
517        status_to_io_result(status)
518    }
519
520    /// Acquire a reference on the given [`HardwareBuffer`] object.
521    ///
522    /// This prevents the object from being deleted until the last strong reference, represented
523    /// by [`HardwareBufferRef`], is [`drop()`]ped.
524    pub fn acquire(&self) -> HardwareBufferRef {
525        unsafe {
526            ffi::AHardwareBuffer_acquire(self.as_ptr());
527            HardwareBufferRef::from_ptr(self.inner)
528        }
529    }
530}
531
532/// A [`HardwareBuffer`] with an owned reference, that is released when dropped.
533/// It behaves much like a strong [`std::rc::Rc`] reference.
534#[derive(Debug)]
535pub struct HardwareBufferRef {
536    inner: HardwareBuffer,
537}
538
539impl HardwareBufferRef {
540    /// Create an _owned_ [`HardwareBuffer`] from a native pointer
541    ///
542    /// To wrap a weak reference (that is **not** `release`d on [`Drop`]), call
543    /// [`HardwareBuffer::from_ptr()`] instead.
544    ///
545    /// # Safety
546    /// By calling this function, you assert that it is a valid pointer to an NDK
547    /// [`ffi::AHardwareBuffer`].
548    pub unsafe fn from_ptr(ptr: NonNull<ffi::AHardwareBuffer>) -> Self {
549        Self {
550            inner: HardwareBuffer { inner: ptr },
551        }
552    }
553}
554
555impl Deref for HardwareBufferRef {
556    type Target = HardwareBuffer;
557
558    fn deref(&self) -> &Self::Target {
559        &self.inner
560    }
561}
562
563impl Drop for HardwareBufferRef {
564    fn drop(&mut self) {
565        unsafe { ffi::AHardwareBuffer_release(self.inner.as_ptr()) }
566    }
567}
568
569impl Clone for HardwareBufferRef {
570    fn clone(&self) -> Self {
571        self.acquire()
572    }
573}
574
575/// Buffer description.
576///
577/// Used for allocating new buffers and querying parameters of existing ones.
578#[derive(Copy, Clone, Debug, PartialEq, Eq)]
579pub struct HardwareBufferDesc {
580    pub width: u32,
581    pub height: u32,
582    pub layers: u32,
583    pub format: HardwareBufferFormat,
584    pub usage: HardwareBufferUsage,
585    pub stride: u32,
586}
587
588impl HardwareBufferDesc {
589    fn into_native(self) -> ffi::AHardwareBuffer_Desc {
590        ffi::AHardwareBuffer_Desc {
591            width: self.width,
592            height: self.height,
593            layers: self.layers,
594            format: i32::from(self.format)
595                .try_into()
596                .expect("i32->u32 overflow in HardwareBufferDesc::into_native()"),
597            usage: self.usage.bits(),
598            stride: self.stride,
599            rfu0: 0,
600            rfu1: 0,
601        }
602    }
603}
604
605/// A native [`AHardwareBuffer_Plane`]
606///
607/// Contains the same fields as [`ffi::AHardwareBuffer_Plane`].
608///
609/// [`AHardwareBuffer_Plane`]: https://developer.android.com/ndk/reference/group/a-hardware-buffer#ahardwarebuffer_plane
610#[derive(Copy, Clone, Debug, PartialEq, Eq)]
611pub struct LockedPlaneInfo {
612    pub virtual_address: *mut c_void,
613    pub bytes_per_pixel: u32,
614    pub bytes_per_stride: u32,
615}
616
617/// Iterator over [`ffi::AHardwareBuffer_Planes`], containing a list of [`LockedPlaneInfo`].
618#[derive(Debug)]
619pub struct HardwareBufferPlanes {
620    inner: ffi::AHardwareBuffer_Planes,
621    index: u32,
622}
623
624impl Iterator for HardwareBufferPlanes {
625    type Item = LockedPlaneInfo;
626
627    fn next(&mut self) -> Option<LockedPlaneInfo> {
628        if self.index == self.inner.planeCount {
629            None
630        } else {
631            let plane = self.inner.planes[self.index as usize];
632            self.index += 1;
633            Some(LockedPlaneInfo {
634                virtual_address: plane.data,
635                bytes_per_pixel: plane.pixelStride,
636                bytes_per_stride: plane.rowStride,
637            })
638        }
639    }
640}