Skip to content

Commit b9f5218

Browse files
committed
android: Hold the locked buffer in AndroidImpl until it is presented via BufferImpl
1 parent 7911980 commit b9f5218

1 file changed

Lines changed: 32 additions & 6 deletions

File tree

src/backends/android.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@ const PIXEL_SIZE: usize = size_of::<Pixel>();
2020
/// The handle to a window for software buffering.
2121
#[derive(Debug)]
2222
pub struct AndroidImpl<D, W> {
23+
// Must be first in the struct to guarantee being dropped and unlocked before the `NativeWindow` reference
24+
in_progress_buffer: Option<NativeWindowBufferLockGuard<'static>>,
2325
native_window: NativeWindow,
2426
window: W,
2527
_display: PhantomData<D>,
2628
}
2729

30+
// TODO: Move to NativeWindowBufferLockGuard?
31+
unsafe impl<D, W> Send for AndroidImpl<D, W> {}
32+
2833
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for AndroidImpl<D, W> {
2934
type Context = D;
3035
type Buffer<'surface>
@@ -44,6 +49,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
4449
let native_window = unsafe { NativeWindow::clone_from_ptr(a.a_native_window.cast()) };
4550

4651
Ok(Self {
52+
in_progress_buffer: None,
4753
native_window,
4854
_display: PhantomData,
4955
window,
@@ -80,6 +86,12 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
8086
}
8187

8288
fn next_buffer(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
89+
if self.in_progress_buffer.is_some() {
90+
return Ok(BufferImpl {
91+
native_window_buffer: &mut self.in_progress_buffer,
92+
});
93+
}
94+
8395
let mut native_window_buffer = self.native_window.lock(None).map_err(|err| {
8496
SoftBufferError::PlatformError(
8597
Some("Failed to lock ANativeWindow".to_owned()),
@@ -116,8 +128,19 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
116128
native_window_buffer.stride() * native_window_buffer.height() * PIXEL_SIZE
117129
);
118130

131+
// SAFETY: We guarantee that the guard isn't actually held longer than this owned handle of
132+
// the `NativeWindow` (which is trivially cloneable), by means of having BufferImpl take a
133+
// mutable borrow on AndroidImpl which owns the NativeWindow and LockGuard.
134+
let native_window_buffer = unsafe {
135+
std::mem::transmute::<
136+
NativeWindowBufferLockGuard<'_>,
137+
NativeWindowBufferLockGuard<'static>,
138+
>(native_window_buffer)
139+
};
140+
self.in_progress_buffer = Some(native_window_buffer);
141+
119142
Ok(BufferImpl {
120-
native_window_buffer,
143+
native_window_buffer: &mut self.in_progress_buffer,
121144
})
122145
}
123146

@@ -129,28 +152,30 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
129152

130153
#[derive(Debug)]
131154
pub struct BufferImpl<'surface> {
132-
native_window_buffer: NativeWindowBufferLockGuard<'surface>,
155+
// This Option will always be Some until present_with_damage() is called
156+
native_window_buffer: &'surface mut Option<NativeWindowBufferLockGuard<'static>>,
133157
}
134158

135159
// TODO: Move to NativeWindowBufferLockGuard?
136160
unsafe impl Send for BufferImpl<'_> {}
137161

138162
impl BufferInterface for BufferImpl<'_> {
139163
fn byte_stride(&self) -> NonZeroU32 {
140-
NonZeroU32::new((self.native_window_buffer.stride() * PIXEL_SIZE) as u32).unwrap()
164+
NonZeroU32::new((self.native_window_buffer.as_ref().unwrap().stride() * PIXEL_SIZE) as u32)
165+
.unwrap()
141166
}
142167

143168
fn width(&self) -> NonZeroU32 {
144-
NonZeroU32::new(self.native_window_buffer.width() as u32).unwrap()
169+
NonZeroU32::new(self.native_window_buffer.as_ref().unwrap().width() as u32).unwrap()
145170
}
146171

147172
fn height(&self) -> NonZeroU32 {
148-
NonZeroU32::new(self.native_window_buffer.height() as u32).unwrap()
173+
NonZeroU32::new(self.native_window_buffer.as_ref().unwrap().height() as u32).unwrap()
149174
}
150175

151176
#[inline]
152177
fn pixels_mut(&mut self) -> &mut [Pixel] {
153-
let native_buffer = self.native_window_buffer.bytes().unwrap();
178+
let native_buffer = self.native_window_buffer.as_mut().unwrap().bytes().unwrap();
154179
// SAFETY: The buffer was zero-initialized and its length is always a multiple of the pixel
155180
// size (4 bytes), even when stride is applied
156181
unsafe {
@@ -180,6 +205,7 @@ impl BufferInterface for BufferImpl<'_> {
180205

181206
// The surface will be presented when it is unlocked, which happens when the owned guard
182207
// is dropped.
208+
self.native_window_buffer.take();
183209

184210
Ok(())
185211
}

0 commit comments

Comments
 (0)