Skip to content

Commit 90341fb

Browse files
committed
Allow configuring and querying pixel format
1 parent aee9c4d commit 90341fb

14 files changed

Lines changed: 232 additions & 87 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Unreleased
22

33
- Added `AlphaMode` to allow configuring transparency and zero-copy on Web. Set it with `Surface::configure`.
4-
- Added `Surface::supports_alpha_mode` for querying supported alpha modes.
5-
- Added `PixelFormat` enum.
4+
- Added `PixelFormat` enum. Set it with `Surface::configure`.
5+
- Added `Surface::supported_pixel_formats` for querying supported alpha modes and pixel formats.
66
- Added `Buffer::pixels()` for accessing the buffer's pixel data.
77
- Added `Buffer::pixel_rows()` for iterating over rows of the buffer data.
88
- Added `Buffer::pixels_iter()` for iterating over each pixel with its associated `x`/`y` coordinate.

examples/transparency.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn main() {
141141
_ => return,
142142
};
143143

144-
if !surface.supports_alpha_mode(alpha_mode) {
144+
if surface.supported_pixel_formats(alpha_mode).is_empty() {
145145
tracing::warn!(?alpha_mode, "not supported by the backend");
146146
return;
147147
}
@@ -150,7 +150,9 @@ fn main() {
150150
let size = window.inner_size();
151151
let width = NonZeroU32::new(size.width).unwrap();
152152
let height = NonZeroU32::new(size.height).unwrap();
153-
surface.configure(width, height, alpha_mode).unwrap();
153+
surface
154+
.configure(width, height, alpha_mode, surface.pixel_format())
155+
.unwrap();
154156
assert_eq!(surface.alpha_mode(), alpha_mode);
155157

156158
window.set_transparent(matches!(

src/backend_dispatch.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Implements `buffer_interface::*` traits for enums dispatching to backends
22
3-
use crate::{backend_interface::*, backends, AlphaMode, InitError, Pixel, Rect, SoftBufferError};
3+
use crate::{
4+
backend_interface::*, backends, AlphaMode, InitError, Pixel, PixelFormat, Rect, SoftBufferError,
5+
};
46

57
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
68
use std::fmt;
@@ -100,29 +102,35 @@ macro_rules! make_dispatch {
100102
}
101103

102104
#[inline]
103-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
105+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
104106
match self {
105107
$(
106108
$(#[$attr])*
107-
Self::$name(inner) => inner.supports_alpha_mode(alpha_mode),
109+
Self::$name(inner) => inner.supported_pixel_formats(alpha_mode),
108110
)*
109111
}
110112
}
111113

112-
fn configure(&mut self, width: NonZeroU32, height: NonZeroU32, alpha_mode: AlphaMode) -> Result<(), SoftBufferError> {
114+
fn configure(
115+
&mut self,
116+
width: NonZeroU32,
117+
height: NonZeroU32,
118+
alpha_mode: AlphaMode,
119+
pixel_format: PixelFormat,
120+
) -> Result<(), SoftBufferError> {
113121
match self {
114122
$(
115123
$(#[$attr])*
116-
Self::$name(inner) => inner.configure(width, height, alpha_mode),
124+
Self::$name(inner) => inner.configure(width, height, alpha_mode, pixel_format),
117125
)*
118126
}
119127
}
120128

121-
fn next_buffer(&mut self, alpha_mode: AlphaMode) -> Result<BufferDispatch<'_>, SoftBufferError> {
129+
fn next_buffer(&mut self, alpha_mode: AlphaMode, pixel_format: PixelFormat) -> Result<BufferDispatch<'_>, SoftBufferError> {
122130
match self {
123131
$(
124132
$(#[$attr])*
125-
Self::$name(inner) => Ok(BufferDispatch::$name(inner.next_buffer(alpha_mode)?)),
133+
Self::$name(inner) => Ok(BufferDispatch::$name(inner.next_buffer(alpha_mode, pixel_format)?)),
126134
)*
127135
}
128136
}

src/backend_interface.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Interface implemented by backends
22
3-
use crate::{AlphaMode, InitError, Pixel, Rect, SoftBufferError};
3+
use crate::{AlphaMode, InitError, Pixel, PixelFormat, Rect, SoftBufferError};
44

55
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
66
use std::num::NonZeroU32;
@@ -26,18 +26,24 @@ pub(crate) trait SurfaceInterface<D: HasDisplayHandle + ?Sized, W: HasWindowHand
2626
/// Get the inner window handle.
2727
fn window(&self) -> &W;
2828

29-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool;
29+
/// The supported pixel formats for the given alpha mode.
30+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat];
3031

3132
/// Reconfigure the internal buffer(s).
3233
fn configure(
3334
&mut self,
3435
width: NonZeroU32,
3536
height: NonZeroU32,
3637
alpha_mode: AlphaMode,
38+
pixel_format: PixelFormat,
3739
) -> Result<(), SoftBufferError>;
3840

3941
/// Get the next buffer to render into.
40-
fn next_buffer(&mut self, alpha_mode: AlphaMode) -> Result<Self::Buffer<'_>, SoftBufferError>;
42+
fn next_buffer(
43+
&mut self,
44+
alpha_mode: AlphaMode,
45+
pixel_format: PixelFormat,
46+
) -> Result<Self::Buffer<'_>, SoftBufferError>;
4147

4248
/// Fetch the buffer from the window.
4349
fn fetch(&mut self) -> Result<Vec<Pixel>, SoftBufferError> {

src/backends/android.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use raw_window_handle::AndroidNdkWindowHandle;
1212
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
1313

1414
use crate::error::InitError;
15-
use crate::{util, AlphaMode, BufferInterface, Pixel, Rect, SoftBufferError, SurfaceInterface};
15+
use crate::{
16+
util, AlphaMode, BufferInterface, Pixel, PixelFormat, Rect, SoftBufferError, SurfaceInterface,
17+
};
1618

1719
/// The handle to a window for software buffering.
1820
#[derive(Debug)]
@@ -53,8 +55,12 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
5355
}
5456

5557
#[inline]
56-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
57-
matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Ignored)
58+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
59+
if matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Ignored) {
60+
&[PixelFormat::Rgba8]
61+
} else {
62+
&[]
63+
}
5864
}
5965

6066
/// Also changes the pixel format.
@@ -63,6 +69,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
6369
width: NonZeroU32,
6470
height: NonZeroU32,
6571
alpha_mode: AlphaMode,
72+
_pixel_format: PixelFormat,
6673
) -> Result<(), SoftBufferError> {
6774
let (width, height) = (|| {
6875
let width = NonZeroI32::try_from(width).ok()?;
@@ -90,7 +97,11 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Android
9097
Ok(())
9198
}
9299

93-
fn next_buffer(&mut self, _alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
100+
fn next_buffer(
101+
&mut self,
102+
_alpha_mode: AlphaMode,
103+
_pixel_format: PixelFormat,
104+
) -> Result<BufferImpl<'_>, SoftBufferError> {
94105
let native_window_buffer = self.native_window.lock(None).map_err(|err| {
95106
SoftBufferError::PlatformError(
96107
Some("Failed to lock ANativeWindow".to_owned()),

src/backends/cg.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Softbuffer implementation using CoreGraphics.
22
use crate::error::InitError;
3-
use crate::{backend_interface::*, AlphaMode};
3+
use crate::{backend_interface::*, AlphaMode, PixelFormat};
44
use crate::{util, Pixel, Rect, SoftBufferError};
55
use objc2::rc::Retained;
66
use objc2::runtime::{AnyObject, Bool};
@@ -256,15 +256,17 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
256256
}
257257

258258
#[inline]
259-
fn supports_alpha_mode(&self, _alpha_mode: AlphaMode) -> bool {
260-
true
259+
fn supported_pixel_formats(&self, _alpha_mode: AlphaMode) -> &[PixelFormat] {
260+
// All alpha modes supported (ish).
261+
&[PixelFormat::Bgra8]
261262
}
262263

263264
fn configure(
264265
&mut self,
265266
width: NonZeroU32,
266267
height: NonZeroU32,
267268
alpha_mode: AlphaMode,
269+
_pixel_format: PixelFormat,
268270
) -> Result<(), SoftBufferError> {
269271
let opaque = matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Ignored);
270272
self.layer.setOpaque(opaque);
@@ -276,7 +278,11 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
276278
Ok(())
277279
}
278280

279-
fn next_buffer(&mut self, alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
281+
fn next_buffer(
282+
&mut self,
283+
alpha_mode: AlphaMode,
284+
_pixel_format: PixelFormat,
285+
) -> Result<BufferImpl<'_>, SoftBufferError> {
280286
let buffer_size = util::byte_stride(self.width as u32) as usize * self.height / 4;
281287
Ok(BufferImpl {
282288
buffer: util::PixelBuffer(vec![Pixel::default(); buffer_size]),

src/backends/kms.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use std::sync::Arc;
2121

2222
use crate::backend_interface::*;
2323
use crate::error::{InitError, SoftBufferError, SwResultExt};
24-
use crate::{util, AlphaMode, Pixel};
24+
use crate::{util, AlphaMode, Pixel, PixelFormat};
2525

2626
#[derive(Debug, Clone)]
2727
struct DrmDevice<'surface> {
@@ -226,18 +226,23 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
226226
}
227227

228228
#[inline]
229-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
230-
matches!(
229+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
230+
if matches!(
231231
alpha_mode,
232232
AlphaMode::Opaque | AlphaMode::Ignored | AlphaMode::Premultiplied
233-
)
233+
) {
234+
&[PixelFormat::Bgra8]
235+
} else {
236+
&[]
237+
}
234238
}
235239

236240
fn configure(
237241
&mut self,
238242
width: NonZeroU32,
239243
height: NonZeroU32,
240244
alpha_mode: AlphaMode,
245+
_pixel_format: PixelFormat,
241246
) -> Result<(), SoftBufferError> {
242247
// Don't resize if we don't have to.
243248
if let Some(buffer) = &self.buffer {
@@ -271,7 +276,11 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W> fo
271276
}
272277
*/
273278

274-
fn next_buffer(&mut self, _alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
279+
fn next_buffer(
280+
&mut self,
281+
_alpha_mode: AlphaMode,
282+
_pixel_format: PixelFormat,
283+
) -> Result<BufferImpl<'_>, SoftBufferError> {
275284
// Map the dumb buffer.
276285
let set = self
277286
.buffer

src/backends/orbital.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle,
33
use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str};
44

55
use crate::backend_interface::*;
6-
use crate::{util, AlphaMode, Pixel, Rect, SoftBufferError};
6+
use crate::{util, AlphaMode, Pixel, PixelFormat, Rect, SoftBufferError};
77

88
#[derive(Debug)]
99
struct OrbitalMap {
@@ -102,15 +102,20 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Orbital
102102
}
103103

104104
#[inline]
105-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
106-
matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Ignored)
105+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
106+
if matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Ignored) {
107+
&[PixelFormat::Bgra8]
108+
} else {
109+
&[]
110+
}
107111
}
108112

109113
fn configure(
110114
&mut self,
111115
width: NonZeroU32,
112116
height: NonZeroU32,
113117
_alpha_mode: AlphaMode,
118+
_pixel_format: PixelFormat,
114119
) -> Result<(), SoftBufferError> {
115120
let width = width.get();
116121
let height = height.get();
@@ -122,7 +127,11 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for Orbital
122127
Ok(())
123128
}
124129

125-
fn next_buffer(&mut self, _alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
130+
fn next_buffer(
131+
&mut self,
132+
_alpha_mode: AlphaMode,
133+
_pixel_format: PixelFormat,
134+
) -> Result<BufferImpl<'_>, SoftBufferError> {
126135
let (window_width, window_height) = window_size(self.window_fd());
127136
let pixels = if self.width as usize == window_width && self.height as usize == window_height
128137
{

src/backends/wayland/mod.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
backend_interface::*,
33
error::{InitError, SwResultExt},
4-
util, AlphaMode, Pixel, Rect, SoftBufferError,
4+
util, AlphaMode, Pixel, PixelFormat, Rect, SoftBufferError,
55
};
66
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
77
use std::{
@@ -143,18 +143,23 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W>
143143
}
144144

145145
#[inline]
146-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
147-
matches!(
146+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
147+
if matches!(
148148
alpha_mode,
149149
AlphaMode::Opaque | AlphaMode::Ignored | AlphaMode::Premultiplied
150-
)
150+
) {
151+
&[PixelFormat::Bgra8]
152+
} else {
153+
&[]
154+
}
151155
}
152156

153157
fn configure(
154158
&mut self,
155159
width: NonZeroU32,
156160
height: NonZeroU32,
157161
_alpha_mode: AlphaMode,
162+
_pixel_format: PixelFormat,
158163
) -> Result<(), SoftBufferError> {
159164
self.size = Some(
160165
(|| {
@@ -167,7 +172,11 @@ impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> SurfaceInterface<D, W>
167172
Ok(())
168173
}
169174

170-
fn next_buffer(&mut self, alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
175+
fn next_buffer(
176+
&mut self,
177+
alpha_mode: AlphaMode,
178+
_pixel_format: PixelFormat,
179+
) -> Result<BufferImpl<'_>, SoftBufferError> {
171180
// This is documented as `0xXXRRGGBB` on a little-endian machine, which means a byte
172181
// order of `[B, G, R, X]`.
173182
let format = match alpha_mode {

src/backends/web.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
1111

1212
use crate::backend_interface::*;
1313
use crate::error::{InitError, SwResultExt};
14-
use crate::{util, AlphaMode, Pixel, Rect, SoftBufferError};
14+
use crate::{util, AlphaMode, Pixel, PixelFormat, Rect, SoftBufferError};
1515
use std::marker::PhantomData;
1616
use std::num::NonZeroU32;
1717

@@ -167,8 +167,12 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for WebImpl
167167
}
168168

169169
#[inline]
170-
fn supports_alpha_mode(&self, alpha_mode: AlphaMode) -> bool {
171-
matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Postmultiplied)
170+
fn supported_pixel_formats(&self, alpha_mode: AlphaMode) -> &[PixelFormat] {
171+
if matches!(alpha_mode, AlphaMode::Opaque | AlphaMode::Postmultiplied) {
172+
&[PixelFormat::Rgba8]
173+
} else {
174+
&[]
175+
}
172176
}
173177

174178
/// De-duplicates the error handling between `HtmlCanvasElement` and `OffscreenCanvas`.
@@ -178,6 +182,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for WebImpl
178182
width: NonZeroU32,
179183
height: NonZeroU32,
180184
_alpha_mode: AlphaMode,
185+
_pixel_format: PixelFormat,
181186
) -> Result<(), SoftBufferError> {
182187
if self.size != Some((width, height)) {
183188
self.buffer_presented = false;
@@ -193,7 +198,11 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for WebImpl
193198
Ok(())
194199
}
195200

196-
fn next_buffer(&mut self, _alpha_mode: AlphaMode) -> Result<BufferImpl<'_>, SoftBufferError> {
201+
fn next_buffer(
202+
&mut self,
203+
_alpha_mode: AlphaMode,
204+
_pixel_format: PixelFormat,
205+
) -> Result<BufferImpl<'_>, SoftBufferError> {
197206
Ok(BufferImpl {
198207
canvas: &self.canvas,
199208
buffer: &mut self.buffer,

0 commit comments

Comments
 (0)