|
| 1 | +//! Implementation of software buffering for Android. |
| 2 | +
|
| 3 | +use std::marker::PhantomData; |
| 4 | +use std::num::{NonZeroI32, NonZeroU32}; |
| 5 | + |
| 6 | +use ndk::{ |
| 7 | + hardware_buffer_format::HardwareBufferFormat, |
| 8 | + native_window::{NativeWindow, NativeWindowBufferLockGuard}, |
| 9 | +}; |
| 10 | +use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle}; |
| 11 | + |
| 12 | +use crate::error::InitError; |
| 13 | +use crate::{Rect, SoftBufferError}; |
| 14 | + |
| 15 | +/// The handle to a window for software buffering. |
| 16 | +pub struct AndroidImpl<D: ?Sized, W: ?Sized> { |
| 17 | + native_window: NativeWindow, |
| 18 | + |
| 19 | + _display: PhantomData<D>, |
| 20 | + |
| 21 | + /// The pointer to the window object. |
| 22 | + /// |
| 23 | + /// This is pretty useless because it gives us a pointer to [`NativeWindow`] that we have to increase the refcount on. |
| 24 | + /// Alternatively we can use [`NativeWindow::from_ptr()`] wrapped in [`std::mem::ManuallyDrop`] |
| 25 | + window: W, |
| 26 | +} |
| 27 | + |
| 28 | +// TODO: Current system doesn't require a trait to be implemented here, even though it exists. |
| 29 | +impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> { |
| 30 | + /// Create a new [`AndroidImpl`] from an [`AndroidNdkWindowHandle`]. |
| 31 | + /// |
| 32 | + /// # Safety |
| 33 | + /// |
| 34 | + /// The [`AndroidNdkWindowHandle`] must be a valid window handle. |
| 35 | + // TODO: That's lame, why can't we get an AndroidNdkWindowHandle directly here |
| 36 | + pub(crate) fn new(window: W, _display: &D) -> Result<Self, InitError<W>> { |
| 37 | + // Get the raw Android window (surface). |
| 38 | + let raw = window.window_handle()?.as_raw(); |
| 39 | + let RawWindowHandle::AndroidNdk(a) = raw else { |
| 40 | + return Err(InitError::Unsupported(window)); |
| 41 | + }; |
| 42 | + |
| 43 | + // Acquire a new owned reference to the window, that will be freed on drop. |
| 44 | + let native_window = unsafe { NativeWindow::clone_from_ptr(a.a_native_window.cast()) }; |
| 45 | + |
| 46 | + Ok(Self { |
| 47 | + native_window, |
| 48 | + // _display: DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::Android( |
| 49 | + // AndroidDisplayHandle, |
| 50 | + // )), |
| 51 | + _display: PhantomData, |
| 52 | + window, |
| 53 | + }) |
| 54 | + } |
| 55 | + |
| 56 | + #[inline] |
| 57 | + pub fn window(&self) -> &W { |
| 58 | + &self.window |
| 59 | + } |
| 60 | + |
| 61 | + /// Also changes the pixel format to [`HardwareBufferFormat::R8G8B8A8_UNORM`]. |
| 62 | + pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> { |
| 63 | + let (width, height) = (|| { |
| 64 | + let width = NonZeroI32::try_from(width).ok()?; |
| 65 | + let height = NonZeroI32::try_from(height).ok()?; |
| 66 | + Some((width, height)) |
| 67 | + })() |
| 68 | + .ok_or(SoftBufferError::SizeOutOfRange { width, height })?; |
| 69 | + |
| 70 | + // Do not change the format. |
| 71 | + self.native_window |
| 72 | + .set_buffers_geometry( |
| 73 | + width.into(), |
| 74 | + height.into(), |
| 75 | + // Default is typically R5G6B5 16bpp, switch to 32bpp |
| 76 | + Some(HardwareBufferFormat::R8G8B8A8_UNORM), |
| 77 | + ) |
| 78 | + .map_err(|err| { |
| 79 | + SoftBufferError::PlatformError( |
| 80 | + Some("Failed to set buffer geometry on ANativeWindow".to_owned()), |
| 81 | + Some(Box::new(err)), |
| 82 | + ) |
| 83 | + }) |
| 84 | + } |
| 85 | + |
| 86 | + pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> { |
| 87 | + let lock_guard = self.native_window.lock(None).map_err(|err| { |
| 88 | + SoftBufferError::PlatformError( |
| 89 | + Some("Failed to lock ANativeWindow".to_owned()), |
| 90 | + Some(Box::new(err)), |
| 91 | + ) |
| 92 | + })?; |
| 93 | + |
| 94 | + assert_eq!( |
| 95 | + lock_guard.format().bytes_per_pixel(), |
| 96 | + Some(4), |
| 97 | + "Unexpected buffer format {:?}, please call .resize() first to change it to RGBA8888", |
| 98 | + lock_guard.format() |
| 99 | + ); |
| 100 | + |
| 101 | + Ok(BufferImpl(lock_guard, PhantomData, PhantomData)) |
| 102 | + } |
| 103 | + |
| 104 | + /// Fetch the buffer from the window. |
| 105 | + pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> { |
| 106 | + Err(SoftBufferError::Unimplemented) |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +pub struct BufferImpl<'a, D: ?Sized, W>( |
| 111 | + NativeWindowBufferLockGuard<'a>, |
| 112 | + PhantomData<&'a D>, |
| 113 | + PhantomData<&'a W>, |
| 114 | +); |
| 115 | + |
| 116 | +// TODO: Move to NativeWindowBufferLockGuard? |
| 117 | +unsafe impl<'a, D, W> Send for BufferImpl<'a, D, W> {} |
| 118 | + |
| 119 | +impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> { |
| 120 | + #[inline] |
| 121 | + pub fn pixels(&self) -> &[u32] { |
| 122 | + todo!() |
| 123 | + // unsafe { |
| 124 | + // std::slice::from_raw_parts( |
| 125 | + // self.0.bits().cast_const().cast(), |
| 126 | + // (self.0.stride() * self.0.height()) as usize, |
| 127 | + // ) |
| 128 | + // } |
| 129 | + } |
| 130 | + |
| 131 | + #[inline] |
| 132 | + pub fn pixels_mut(&mut self) -> &mut [u32] { |
| 133 | + let bytes = self.0.bytes().expect("Nonplanar format"); |
| 134 | + unsafe { |
| 135 | + std::slice::from_raw_parts_mut( |
| 136 | + bytes.as_mut_ptr().cast(), |
| 137 | + bytes.len() / std::mem::size_of::<u32>(), |
| 138 | + ) |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + pub fn age(&self) -> u8 { |
| 143 | + 0 |
| 144 | + } |
| 145 | + |
| 146 | + pub fn present(self) -> Result<(), SoftBufferError> { |
| 147 | + // Dropping the guard automatically unlocks and posts it |
| 148 | + Ok(()) |
| 149 | + } |
| 150 | + |
| 151 | + pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> { |
| 152 | + Err(SoftBufferError::Unimplemented) |
| 153 | + } |
| 154 | +} |
0 commit comments