Skip to content

Commit acc2bcf

Browse files
committed
Android: Hold the locked buffer in AndroidImpl until it is presented via BufferImpl
1 parent 81eff2e commit acc2bcf

File tree

1 file changed

+31
-6
lines changed

1 file changed

+31
-6
lines changed

src/backends/android.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ use crate::{BufferInterface, Pixel, Rect, SoftBufferError, SurfaceInterface};
1717
/// The handle to a window for software buffering.
1818
#[derive(Debug)]
1919
pub struct AndroidImpl<D, W> {
20+
// Must be first in the struct to guarantee being dropped and unlocked before the `NativeWindow` reference
21+
in_progress_buffer: Option<NativeWindowBufferLockGuard<'static>>,
2022
native_window: NativeWindow,
2123
window: W,
2224
_display: PhantomData<D>,
2325
}
2426

27+
// TODO: Move to NativeWindowBufferLockGuard?
28+
unsafe impl<D, W> Send for AndroidImpl<D, W> {}
29+
2530
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for AndroidImpl<D, W> {
2631
type Context = D;
2732
type Buffer<'surface>
@@ -41,6 +46,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
4146
let native_window = unsafe { NativeWindow::clone_from_ptr(a.a_native_window.cast()) };
4247

4348
Ok(Self {
49+
in_progress_buffer: None,
4450
native_window,
4551
_display: PhantomData,
4652
window,
@@ -77,6 +83,12 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
7783
}
7884

7985
fn buffer_mut(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
86+
if self.in_progress_buffer.is_some() {
87+
return Ok(BufferImpl {
88+
native_window_buffer: &mut self.in_progress_buffer,
89+
});
90+
}
91+
8092
let native_window_buffer = self.native_window.lock(None).map_err(|err| {
8193
SoftBufferError::PlatformError(
8294
Some("Failed to lock ANativeWindow".to_owned()),
@@ -99,8 +111,19 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
99111
));
100112
}
101113

114+
// SAFETY: We guarantee that the guard isn't actually held longer than this owned handle of
115+
// the `NativeWindow` (which is trivially cloneable), by means of having BufferImpl take a
116+
// mutable borrow on AndroidImpl which owns the NativeWindow and LockGuard.
117+
let native_window_buffer = unsafe {
118+
std::mem::transmute::<
119+
NativeWindowBufferLockGuard<'_>,
120+
NativeWindowBufferLockGuard<'static>,
121+
>(native_window_buffer)
122+
};
123+
self.in_progress_buffer = Some(native_window_buffer);
124+
102125
Ok(BufferImpl {
103-
native_window_buffer,
126+
native_window_buffer: &mut self.in_progress_buffer,
104127
})
105128
}
106129

@@ -112,28 +135,29 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
112135

113136
#[derive(Debug)]
114137
pub struct BufferImpl<'surface> {
115-
native_window_buffer: NativeWindowBufferLockGuard<'surface>,
138+
// This Option will always be Some until present_with_damage() is called
139+
native_window_buffer: &'surface mut Option<NativeWindowBufferLockGuard<'static>>,
116140
}
117141

118142
// TODO: Move to NativeWindowBufferLockGuard?
119143
unsafe impl Send for BufferImpl<'_> {}
120144

121145
impl BufferInterface for BufferImpl<'_> {
122146
fn byte_stride(&self) -> NonZeroU32 {
123-
NonZeroU32::new(self.native_window_buffer.stride() as u32 * 4).unwrap()
147+
NonZeroU32::new(self.native_window_buffer.as_ref().unwrap().stride() as u32 * 4).unwrap()
124148
}
125149

126150
fn width(&self) -> NonZeroU32 {
127-
NonZeroU32::new(self.native_window_buffer.width() as u32).unwrap()
151+
NonZeroU32::new(self.native_window_buffer.as_ref().unwrap().width() as u32).unwrap()
128152
}
129153

130154
fn height(&self) -> NonZeroU32 {
131-
NonZeroU32::new(self.native_window_buffer.height() as u32).unwrap()
155+
NonZeroU32::new(self.native_window_buffer.as_ref().unwrap().height() as u32).unwrap()
132156
}
133157

134158
#[inline]
135159
fn pixels_mut(&mut self) -> &mut [Pixel] {
136-
let native_buffer = self.native_window_buffer.bytes().unwrap();
160+
let native_buffer = self.native_window_buffer.as_mut().unwrap().bytes().unwrap();
137161
// assert_eq!(
138162
// native_buffer.len(),
139163
// self.native_window_buffer.stride() * self.native_window_buffer.height()
@@ -168,6 +192,7 @@ impl BufferInterface for BufferImpl<'_> {
168192

169193
// The surface will be presented when it is unlocked, which happens when the owned guard
170194
// is dropped.
195+
self.native_window_buffer.take();
171196

172197
Ok(())
173198
}

0 commit comments

Comments
 (0)