@@ -30,8 +30,8 @@ use binder::{
3030 StatusCode ,
3131} ;
3232use ffi:: {
33- AHardwareBuffer , AHardwareBuffer_Desc , AHardwareBuffer_readFromParcel ,
34- AHardwareBuffer_writeToParcel , ARect ,
33+ AHardwareBuffer , AHardwareBuffer_Desc , AHardwareBuffer_Plane , AHardwareBuffer_Planes ,
34+ AHardwareBuffer_readFromParcel , AHardwareBuffer_writeToParcel , ARect ,
3535} ;
3636use std:: ffi:: c_void;
3737use std:: fmt:: { self , Debug , Formatter } ;
@@ -313,6 +313,57 @@ impl HardwareBuffer {
313313 } )
314314 }
315315
316+ /// Lock a potentially multi-planar hardware buffer for direct CPU access.
317+ ///
318+ /// # Safety
319+ ///
320+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
321+ /// before calling this function.
322+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
323+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
324+ /// and break Rust's aliasing rules, like any other shared memory.
325+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
326+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
327+ /// processes lock the buffer simultaneously for any usage.
328+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
329+ /// simultaneously.
330+ /// - If `rect` is not `None`, the caller must not modify the buffer outside of that rectangle.
331+ pub unsafe fn lock_planes < ' a > (
332+ & ' a self ,
333+ usage : AHardwareBuffer_UsageFlags ,
334+ fence : Option < BorrowedFd > ,
335+ rect : Option < & ARect > ,
336+ ) -> Result < Vec < PlaneGuard < ' a > > , StatusCode > {
337+ let fence = if let Some ( fence) = fence { fence. as_raw_fd ( ) } else { -1 } ;
338+ let rect = rect. map ( ptr:: from_ref) . unwrap_or ( null ( ) ) ;
339+ let mut planes = AHardwareBuffer_Planes {
340+ planeCount : 0 ,
341+ planes : [ const { AHardwareBuffer_Plane { data : null_mut ( ) , pixelStride : 0 , rowStride : 0 } } ;
342+ 4 ] ,
343+ } ;
344+
345+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the various out
346+ // pointers are valid because they come from references. Our caller promises that writes have
347+ // completed and there will be no simultaneous read/write locks.
348+ let status = unsafe {
349+ ffi:: AHardwareBuffer_lockPlanes ( self . 0 . as_ptr ( ) , usage. 0 , fence, rect, & mut planes)
350+ } ;
351+ status_result ( status) ?;
352+ let plane_count = planes. planeCount . try_into ( ) . unwrap ( ) ;
353+ Ok ( planes. planes [ ..plane_count]
354+ . iter ( )
355+ . map ( |plane| PlaneGuard {
356+ guard : HardwareBufferGuard {
357+ buffer : self ,
358+ address : NonNull :: new ( plane. data )
359+ . expect ( "AHardwareBuffer_lockAndGetInfo set a null outVirtualAddress" ) ,
360+ } ,
361+ pixel_stride : plane. pixelStride ,
362+ row_stride : plane. rowStride ,
363+ } )
364+ . collect ( ) )
365+ }
366+
316367 /// Locks the hardware buffer for direct CPU access, returning information about the bytes per
317368 /// pixel and stride as well.
318369 ///
@@ -510,6 +561,18 @@ pub struct LockedBufferInfo<'a> {
510561 pub stride : u32 ,
511562}
512563
564+ /// A guard for a single plane of a locked `HardwareBuffer`, with additional information about the
565+ /// stride.
566+ #[ derive( Debug ) ]
567+ pub struct PlaneGuard < ' a > {
568+ /// The locked buffer guard.
569+ pub guard : HardwareBufferGuard < ' a > ,
570+ /// The stride in bytes between the color channel for one pixel to the next pixel.
571+ pub pixel_stride : u32 ,
572+ /// The stride in bytes between rows in the buffer.
573+ pub row_stride : u32 ,
574+ }
575+
513576#[ cfg( test) ]
514577mod test {
515578 use super :: * ;
0 commit comments