Skip to content

Commit e036162

Browse files
committed
Add methods to lock and unlock HardwareBuffer.
Bug: 371874777 Test: atest libnativewindow_rs-internal_test Change-Id: I1494f17720761db6dbc7ba63ba51c5ec91536f74
1 parent 84c4614 commit e036162

1 file changed

Lines changed: 272 additions & 4 deletions

File tree

  • libs/nativewindow/rust/src

libs/nativewindow/rust/src/lib.rs

Lines changed: 272 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ use binder::{
3131
};
3232
use ffi::{
3333
AHardwareBuffer, AHardwareBuffer_Desc, AHardwareBuffer_readFromParcel,
34-
AHardwareBuffer_writeToParcel,
34+
AHardwareBuffer_writeToParcel, ARect,
3535
};
36+
use std::ffi::c_void;
3637
use 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

276409
impl Drop for HardwareBuffer {
@@ -346,6 +479,37 @@ unsafe impl Send for HardwareBuffer {}
346479
// according to the docs on the underlying gralloc calls)
347480
unsafe 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)]
350514
mod 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

Comments
 (0)