Skip to content

Commit 7911980

Browse files
committed
android: Make the backend zero-copy
1 parent b34029c commit 7911980

1 file changed

Lines changed: 32 additions & 22 deletions

File tree

src/backends/android.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Implementation of software buffering for Android.
22
33
use std::marker::PhantomData;
4+
use std::mem::MaybeUninit;
45
use std::num::{NonZeroI32, NonZeroU32};
56

67
use ndk::{
@@ -12,7 +13,9 @@ use raw_window_handle::AndroidNdkWindowHandle;
1213
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
1314

1415
use crate::error::InitError;
15-
use crate::{util, BufferInterface, Pixel, Rect, SoftBufferError, SurfaceInterface};
16+
use crate::{BufferInterface, Pixel, Rect, SoftBufferError, SurfaceInterface};
17+
18+
const PIXEL_SIZE: usize = size_of::<Pixel>();
1619

1720
/// The handle to a window for software buffering.
1821
#[derive(Debug)]
@@ -52,7 +55,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
5255
&self.window
5356
}
5457

55-
/// Also changes the pixel format to [`HardwareBufferFormat::R8G8B8A8_UNORM`].
58+
/// Also changes the pixel format to [`HardwareBufferFormat::R8G8B8X8_UNORM`].
5659
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
5760
let (width, height) = (|| {
5861
let width = NonZeroI32::try_from(width).ok()?;
@@ -77,7 +80,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
7780
}
7881

7982
fn next_buffer(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
80-
let native_window_buffer = self.native_window.lock(None).map_err(|err| {
83+
let mut native_window_buffer = self.native_window.lock(None).map_err(|err| {
8184
SoftBufferError::PlatformError(
8285
Some("Failed to lock ANativeWindow".to_owned()),
8386
Some(Box::new(err)),
@@ -99,12 +102,22 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
99102
));
100103
}
101104

102-
let buffer =
103-
vec![Pixel::default(); native_window_buffer.stride() * native_window_buffer.height()];
105+
assert_eq!(
106+
native_window_buffer.format().bytes_per_pixel(),
107+
Some(PIXEL_SIZE)
108+
);
109+
let native_buffer = native_window_buffer.bytes().unwrap();
110+
111+
// Zero-initialize the buffer, allowing it to be cast away from MaybeUninit and mapped as a Pixel slice
112+
native_buffer.fill(MaybeUninit::new(0));
113+
114+
assert_eq!(
115+
native_buffer.len(),
116+
native_window_buffer.stride() * native_window_buffer.height() * PIXEL_SIZE
117+
);
104118

105119
Ok(BufferImpl {
106120
native_window_buffer,
107-
buffer: util::PixelBuffer(buffer),
108121
})
109122
}
110123

@@ -117,15 +130,14 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
117130
#[derive(Debug)]
118131
pub struct BufferImpl<'surface> {
119132
native_window_buffer: NativeWindowBufferLockGuard<'surface>,
120-
buffer: util::PixelBuffer,
121133
}
122134

123135
// TODO: Move to NativeWindowBufferLockGuard?
124136
unsafe impl Send for BufferImpl<'_> {}
125137

126138
impl BufferInterface for BufferImpl<'_> {
127139
fn byte_stride(&self) -> NonZeroU32 {
128-
NonZeroU32::new(self.native_window_buffer.stride() as u32 * 4).unwrap()
140+
NonZeroU32::new((self.native_window_buffer.stride() * PIXEL_SIZE) as u32).unwrap()
129141
}
130142

131143
fn width(&self) -> NonZeroU32 {
@@ -138,7 +150,15 @@ impl BufferInterface for BufferImpl<'_> {
138150

139151
#[inline]
140152
fn pixels_mut(&mut self) -> &mut [Pixel] {
141-
&mut self.buffer
153+
let native_buffer = self.native_window_buffer.bytes().unwrap();
154+
// SAFETY: The buffer was zero-initialized and its length is always a multiple of the pixel
155+
// size (4 bytes), even when stride is applied
156+
unsafe {
157+
std::slice::from_raw_parts_mut(
158+
native_buffer.as_mut_ptr().cast(),
159+
native_buffer.len() / PIXEL_SIZE,
160+
)
161+
}
142162
}
143163

144164
#[inline]
@@ -147,7 +167,7 @@ impl BufferInterface for BufferImpl<'_> {
147167
}
148168

149169
// TODO: This function is pretty slow this way
150-
fn present_with_damage(mut self, damage: &[Rect]) -> Result<(), SoftBufferError> {
170+
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
151171
// TODO: Android requires the damage rect _at lock time_
152172
// Since we're faking the backing buffer _anyway_, we could even fake the surface lock
153173
// and lock it here (if it doesn't influence timings).
@@ -158,18 +178,8 @@ impl BufferInterface for BufferImpl<'_> {
158178
// when the enlarged damage region is not re-rendered?
159179
let _ = damage;
160180

161-
// Unreachable as we checked before that this is a valid, mappable format
162-
let native_buffer = self.native_window_buffer.bytes().unwrap();
163-
164-
// Write RGB(A) to the output.
165-
// TODO: Use `slice::write_copy_of_slice` once stable and in MSRV.
166-
// TODO(madsmtm): Verify that this compiles down to an efficient copy.
167-
for (pixel, output) in self.buffer.iter().zip(native_buffer.chunks_mut(4)) {
168-
output[0].write(pixel.r);
169-
output[1].write(pixel.g);
170-
output[2].write(pixel.b);
171-
output[3].write(pixel.a);
172-
}
181+
// The surface will be presented when it is unlocked, which happens when the owned guard
182+
// is dropped.
173183

174184
Ok(())
175185
}

0 commit comments

Comments
 (0)