Skip to content

Commit 1ed5a10

Browse files
committed
Buffer copies
1 parent 3a77cae commit 1ed5a10

File tree

3 files changed

+57
-42
lines changed

3 files changed

+57
-42
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ log = "0.4.17"
2929
raw_window_handle = { package = "raw-window-handle", version = "0.6", features = ["std"] }
3030

3131
[target.'cfg(target_os = "android")'.dependencies]
32+
bytemuck.version = "1.12.3"
3233
ndk = "0.9.0"
3334

3435
[target.'cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))'.dependencies]

src/backends/android.rs

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,14 @@ use crate::error::InitError;
1313
use crate::{Rect, SoftBufferError};
1414

1515
/// The handle to a window for software buffering.
16-
pub struct AndroidImpl<D: ?Sized, W: ?Sized> {
16+
pub struct AndroidImpl<D, W> {
1717
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`]
2518
window: W,
19+
_display: PhantomData<D>,
2620
}
2721

2822
// TODO: Current system doesn't require a trait to be implemented here, even though it exists.
23+
// impl SurfaceInterface<D, W> for ...
2924
impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> {
3025
/// Create a new [`AndroidImpl`] from an [`AndroidNdkWindowHandle`].
3126
///
@@ -45,9 +40,6 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> {
4540

4641
Ok(Self {
4742
native_window,
48-
// _display: DisplayHandle::borrow_raw(raw_window_handle::RawDisplayHandle::Android(
49-
// AndroidDisplayHandle,
50-
// )),
5143
_display: PhantomData,
5244
window,
5345
})
@@ -73,7 +65,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> {
7365
width.into(),
7466
height.into(),
7567
// Default is typically R5G6B5 16bpp, switch to 32bpp
76-
Some(HardwareBufferFormat::R8G8B8A8_UNORM),
68+
Some(HardwareBufferFormat::R8G8B8X8_UNORM),
7769
)
7870
.map_err(|err| {
7971
SoftBufferError::PlatformError(
@@ -84,21 +76,30 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> {
8476
}
8577

8678
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
87-
let lock_guard = self.native_window.lock(None).map_err(|err| {
79+
let native_window_buffer = self.native_window.lock(None).map_err(|err| {
8880
SoftBufferError::PlatformError(
8981
Some("Failed to lock ANativeWindow".to_owned()),
9082
Some(Box::new(err)),
9183
)
9284
})?;
9385

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()
86+
assert!(
87+
matches!(
88+
native_window_buffer.format(),
89+
// These are the only formats we support
90+
HardwareBufferFormat::R8G8B8A8_UNORM | HardwareBufferFormat::R8G8B8X8_UNORM
91+
),
92+
"Unexpected buffer format {:?}, please call .resize() first to change it to RGBx8888",
93+
native_window_buffer.format()
9994
);
10095

101-
Ok(BufferImpl(lock_guard, PhantomData, PhantomData))
96+
let buffer = vec![0; native_window_buffer.width() * native_window_buffer.height()];
97+
98+
Ok(BufferImpl {
99+
native_window_buffer,
100+
buffer,
101+
marker: PhantomData,
102+
})
102103
}
103104

104105
/// Fetch the buffer from the window.
@@ -107,48 +108,58 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> AndroidImpl<D, W> {
107108
}
108109
}
109110

110-
pub struct BufferImpl<'a, D: ?Sized, W>(
111-
NativeWindowBufferLockGuard<'a>,
112-
PhantomData<&'a D>,
113-
PhantomData<&'a W>,
114-
);
111+
pub struct BufferImpl<'a, D: ?Sized, W> {
112+
native_window_buffer: NativeWindowBufferLockGuard<'a>,
113+
buffer: Vec<u32>,
114+
marker: PhantomData<(&'a D, &'a W)>,
115+
}
115116

116117
// TODO: Move to NativeWindowBufferLockGuard?
117118
unsafe impl<'a, D, W> Send for BufferImpl<'a, D, W> {}
118119

119120
impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> {
120121
#[inline]
121122
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-
// }
123+
&self.buffer
129124
}
130125

131126
#[inline]
132127
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-
}
128+
&mut self.buffer
140129
}
141130

142131
pub fn age(&self) -> u8 {
143132
0
144133
}
145134

146-
pub fn present(self) -> Result<(), SoftBufferError> {
147-
// Dropping the guard automatically unlocks and posts it
135+
// TODO: This function is pretty slow this way
136+
pub fn present(mut self) -> Result<(), SoftBufferError> {
137+
let input_lines = self.buffer.chunks(self.native_window_buffer.width());
138+
for (output, input) in self
139+
.native_window_buffer
140+
.lines()
141+
.expect("Nonplanar format")
142+
.zip(input_lines)
143+
{
144+
// .lines() removed the stride
145+
assert_eq!(output.len(), input.len() * 4);
146+
147+
for (i, pixel) in input.iter().enumerate() {
148+
// Swizzle colors from RGBX to BGR
149+
let [b, g, r, _] = pixel.to_le_bytes();
150+
output[i * 4].write(b);
151+
output[i * 4 + 1].write(g);
152+
output[i * 4 + 2].write(r);
153+
// TODO alpha?
154+
}
155+
}
148156
Ok(())
149157
}
150158

151159
pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
152-
Err(SoftBufferError::Unimplemented)
160+
// TODO: Android requires the damage rect _at lock time_
161+
// Since we're faking the backing buffer _anyway_, we could even fake the surface lock
162+
// and lock it here (if it doesn't influence timings).
163+
self.present()
153164
}
154165
}

src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,16 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> HasWindowHandle for Surface<D, W>
195195
/// Currently [`Buffer::present`] must block copying image data on:
196196
/// - Web
197197
/// - macOS
198+
///
199+
/// Buffer copies an channel swizzling happen on:
200+
/// - Android
198201
pub struct Buffer<'a, D, W> {
199202
buffer_impl: BufferDispatch<'a, D, W>,
200203
_marker: PhantomData<(Arc<D>, Cell<()>)>,
201204
}
202205

203206
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> {
204-
/// Is age is the number of frames ago this buffer was last presented. So if the value is
207+
/// `age` is the number of frames ago this buffer was last presented. So if the value is
205208
/// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame
206209
/// before that (for backends using double buffering). If the value is `0`, it is a new
207210
/// buffer that has unspecified contents.

0 commit comments

Comments
 (0)