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}