@@ -31,11 +31,13 @@ use binder::{
3131} ;
3232use ffi:: {
3333 AHardwareBuffer , AHardwareBuffer_Desc , AHardwareBuffer_readFromParcel ,
34- AHardwareBuffer_writeToParcel ,
34+ AHardwareBuffer_writeToParcel , ARect ,
3535} ;
36+ use std:: ffi:: c_void;
3637use std:: fmt:: { self , Debug , Formatter } ;
37- use std:: mem:: ManuallyDrop ;
38- use std:: ptr:: { self , null_mut, NonNull } ;
38+ use std:: mem:: { forget, ManuallyDrop } ;
39+ use std:: os:: fd:: { AsRawFd , BorrowedFd , FromRawFd , OwnedFd } ;
40+ use std:: ptr:: { self , null, null_mut, NonNull } ;
3941
4042/// Wrapper around a C `AHardwareBuffer_Desc`.
4143#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -267,10 +269,141 @@ impl HardwareBuffer {
267269 rfu0 : 0 ,
268270 rfu1 : 0 ,
269271 } ;
270- // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
272+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the
273+ // AHardwareBuffer_Desc pointer is valid because it comes from a reference.
271274 unsafe { ffi:: AHardwareBuffer_describe ( self . 0 . as_ref ( ) , & mut buffer_desc) } ;
272275 HardwareBufferDescription ( buffer_desc)
273276 }
277+
278+ /// Locks the hardware buffer for direct CPU access.
279+ ///
280+ /// # Safety
281+ ///
282+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
283+ /// before calling this function.
284+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
285+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
286+ /// and break Rust's aliasing rules, like any other shared memory.
287+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
288+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
289+ /// processes lock the buffer simultaneously for any usage.
290+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
291+ /// simultaneously.
292+ /// - If `rect` is not `None`, the caller must not modify the buffer outside of that rectangle.
293+ pub unsafe fn lock < ' a > (
294+ & ' a self ,
295+ usage : AHardwareBuffer_UsageFlags ,
296+ fence : Option < BorrowedFd > ,
297+ rect : Option < & ARect > ,
298+ ) -> Result < HardwareBufferGuard < ' a > , StatusCode > {
299+ let fence = if let Some ( fence) = fence { fence. as_raw_fd ( ) } else { -1 } ;
300+ let rect = rect. map ( ptr:: from_ref) . unwrap_or ( null ( ) ) ;
301+ let mut address = null_mut ( ) ;
302+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the buffer address out
303+ // pointer is valid because it comes from a reference. Our caller promises that writes have
304+ // completed and there will be no simultaneous read/write locks.
305+ let status = unsafe {
306+ ffi:: AHardwareBuffer_lock ( self . 0 . as_ptr ( ) , usage. 0 , fence, rect, & mut address)
307+ } ;
308+ status_result ( status) ?;
309+ Ok ( HardwareBufferGuard {
310+ buffer : self ,
311+ address : NonNull :: new ( address)
312+ . expect ( "AHardwareBuffer_lock set a null outVirtualAddress" ) ,
313+ } )
314+ }
315+
316+ /// Locks the hardware buffer for direct CPU access, returning information about the bytes per
317+ /// pixel and stride as well.
318+ ///
319+ /// # Safety
320+ ///
321+ /// - If `fence` is `None`, the caller must ensure that all writes to the buffer have completed
322+ /// before calling this function.
323+ /// - If the buffer has `AHARDWAREBUFFER_FORMAT_BLOB`, multiple threads or process may lock the
324+ /// buffer simultaneously, but the caller must ensure that they don't access it simultaneously
325+ /// and break Rust's aliasing rules, like any other shared memory.
326+ /// - Otherwise if `usage` includes `AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY` or
327+ /// `AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN`, the caller must ensure that no other threads or
328+ /// processes lock the buffer simultaneously for any usage.
329+ /// - Otherwise, the caller must ensure that no other threads lock the buffer for writing
330+ /// simultaneously.
331+ pub unsafe fn lock_and_get_info < ' a > (
332+ & ' a self ,
333+ usage : AHardwareBuffer_UsageFlags ,
334+ fence : Option < BorrowedFd > ,
335+ rect : Option < & ARect > ,
336+ ) -> Result < LockedBufferInfo < ' 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 address = null_mut ( ) ;
340+ let mut bytes_per_pixel = 0 ;
341+ let mut stride = 0 ;
342+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid, and the various out
343+ // pointers are valid because they come from references. Our caller promises that writes have
344+ // completed and there will be no simultaneous read/write locks.
345+ let status = unsafe {
346+ ffi:: AHardwareBuffer_lockAndGetInfo (
347+ self . 0 . as_ptr ( ) ,
348+ usage. 0 ,
349+ fence,
350+ rect,
351+ & mut address,
352+ & mut bytes_per_pixel,
353+ & mut stride,
354+ )
355+ } ;
356+ status_result ( status) ?;
357+ Ok ( LockedBufferInfo {
358+ guard : HardwareBufferGuard {
359+ buffer : self ,
360+ address : NonNull :: new ( address)
361+ . expect ( "AHardwareBuffer_lockAndGetInfo set a null outVirtualAddress" ) ,
362+ } ,
363+ bytes_per_pixel : bytes_per_pixel as u32 ,
364+ stride : stride as u32 ,
365+ } )
366+ }
367+
368+ /// Unlocks the hardware buffer from direct CPU access.
369+ ///
370+ /// Must be called after all changes to the buffer are completed by the caller. This will block
371+ /// until the unlocking is complete and the buffer contents are updated.
372+ fn unlock ( & self ) -> Result < ( ) , StatusCode > {
373+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid.
374+ let status = unsafe { ffi:: AHardwareBuffer_unlock ( self . 0 . as_ptr ( ) , null_mut ( ) ) } ;
375+ status_result ( status) ?;
376+ Ok ( ( ) )
377+ }
378+
379+ /// Unlocks the hardware buffer from direct CPU access.
380+ ///
381+ /// Must be called after all changes to the buffer are completed by the caller.
382+ ///
383+ /// This may not block until all work is completed, but rather will return a file descriptor
384+ /// which will be signalled once the unlocking is complete and the buffer contents is updated.
385+ /// If `Ok(None)` is returned then unlocking has already completed and no further waiting is
386+ /// necessary. The file descriptor may be passed to a subsequent call to [`Self::lock`].
387+ pub fn unlock_with_fence (
388+ & self ,
389+ guard : HardwareBufferGuard ,
390+ ) -> Result < Option < OwnedFd > , StatusCode > {
391+ // Forget the guard so that its `Drop` implementation doesn't try to unlock the
392+ // HardwareBuffer again.
393+ forget ( guard) ;
394+
395+ let mut fence = -2 ;
396+ // SAFETY: The `AHardwareBuffer` pointer we wrap is always valid.
397+ let status = unsafe { ffi:: AHardwareBuffer_unlock ( self . 0 . as_ptr ( ) , & mut fence) } ;
398+ let fence = if fence < 0 {
399+ None
400+ } else {
401+ // SAFETY: `AHardwareBuffer_unlock` gives us ownership of the fence file descriptor.
402+ Some ( unsafe { OwnedFd :: from_raw_fd ( fence) } )
403+ } ;
404+ status_result ( status) ?;
405+ Ok ( fence)
406+ }
274407}
275408
276409impl Drop for HardwareBuffer {
@@ -346,6 +479,37 @@ unsafe impl Send for HardwareBuffer {}
346479// according to the docs on the underlying gralloc calls)
347480unsafe impl Sync for HardwareBuffer { }
348481
482+ /// A guard for when a `HardwareBuffer` is locked.
483+ ///
484+ /// The `HardwareBuffer` will be unlocked when this is dropped, or may be unlocked via
485+ /// [`HardwareBuffer::unlock_with_fence`].
486+ #[ derive( Debug ) ]
487+ pub struct HardwareBufferGuard < ' a > {
488+ buffer : & ' a HardwareBuffer ,
489+ /// The address of the buffer in memory.
490+ pub address : NonNull < c_void > ,
491+ }
492+
493+ impl < ' a > Drop for HardwareBufferGuard < ' a > {
494+ fn drop ( & mut self ) {
495+ self . buffer
496+ . unlock ( )
497+ . expect ( "Failed to unlock HardwareBuffer when dropping HardwareBufferGuard" ) ;
498+ }
499+ }
500+
501+ /// A guard for when a `HardwareBuffer` is locked, with additional information about the number of
502+ /// bytes per pixel and stride.
503+ #[ derive( Debug ) ]
504+ pub struct LockedBufferInfo < ' a > {
505+ /// The locked buffer guard.
506+ pub guard : HardwareBufferGuard < ' a > ,
507+ /// The number of bytes used for each pixel in the buffer.
508+ pub bytes_per_pixel : u32 ,
509+ /// The stride in bytes between rows in the buffer.
510+ pub stride : u32 ,
511+ }
512+
349513#[ cfg( test) ]
350514mod test {
351515 use super :: * ;
@@ -499,4 +663,108 @@ mod test {
499663 assert_eq ! ( buffer. description( ) , buffer_description) ;
500664 assert_eq ! ( buffer2. description( ) , buffer_description) ;
501665 }
666+
667+ #[ test]
668+ fn lock ( ) {
669+ let buffer = HardwareBuffer :: new ( & HardwareBufferDescription :: new (
670+ 1024 ,
671+ 512 ,
672+ 1 ,
673+ AHardwareBuffer_Format :: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM ,
674+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
675+ 0 ,
676+ ) )
677+ . expect ( "Failed to create buffer" ) ;
678+
679+ // SAFETY: No other threads or processes have access to the buffer.
680+ let guard = unsafe {
681+ buffer. lock (
682+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
683+ None ,
684+ None ,
685+ )
686+ }
687+ . unwrap ( ) ;
688+
689+ drop ( guard) ;
690+ }
691+
692+ #[ test]
693+ fn lock_with_rect ( ) {
694+ let buffer = HardwareBuffer :: new ( & HardwareBufferDescription :: new (
695+ 1024 ,
696+ 512 ,
697+ 1 ,
698+ AHardwareBuffer_Format :: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM ,
699+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
700+ 0 ,
701+ ) )
702+ . expect ( "Failed to create buffer" ) ;
703+ let rect = ARect { left : 10 , right : 20 , top : 35 , bottom : 45 } ;
704+
705+ // SAFETY: No other threads or processes have access to the buffer.
706+ let guard = unsafe {
707+ buffer. lock (
708+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
709+ None ,
710+ Some ( & rect) ,
711+ )
712+ }
713+ . unwrap ( ) ;
714+
715+ drop ( guard) ;
716+ }
717+
718+ #[ test]
719+ fn unlock_with_fence ( ) {
720+ let buffer = HardwareBuffer :: new ( & HardwareBufferDescription :: new (
721+ 1024 ,
722+ 512 ,
723+ 1 ,
724+ AHardwareBuffer_Format :: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM ,
725+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
726+ 0 ,
727+ ) )
728+ . expect ( "Failed to create buffer" ) ;
729+
730+ // SAFETY: No other threads or processes have access to the buffer.
731+ let guard = unsafe {
732+ buffer. lock (
733+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
734+ None ,
735+ None ,
736+ )
737+ }
738+ . unwrap ( ) ;
739+
740+ buffer. unlock_with_fence ( guard) . unwrap ( ) ;
741+ }
742+
743+ #[ test]
744+ fn lock_with_info ( ) {
745+ const WIDTH : u32 = 1024 ;
746+ let buffer = HardwareBuffer :: new ( & HardwareBufferDescription :: new (
747+ WIDTH ,
748+ 512 ,
749+ 1 ,
750+ AHardwareBuffer_Format :: AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM ,
751+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
752+ 0 ,
753+ ) )
754+ . expect ( "Failed to create buffer" ) ;
755+
756+ // SAFETY: No other threads or processes have access to the buffer.
757+ let info = unsafe {
758+ buffer. lock_and_get_info (
759+ AHardwareBuffer_UsageFlags :: AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN ,
760+ None ,
761+ None ,
762+ )
763+ }
764+ . unwrap ( ) ;
765+
766+ assert_eq ! ( info. bytes_per_pixel, 4 ) ;
767+ assert_eq ! ( info. stride, WIDTH * 4 ) ;
768+ drop ( info) ;
769+ }
502770}
0 commit comments