Skip to content

Commit 5c57eba

Browse files
committed
Use traits to define common backend interface
This still uses enums to dispatch to the backends, but has the `*Dispatch` types implement the same traits. Nothing about the behavior or performance should change. If we require backends to implement the same methods, it seems good to use traits for that. Any documentation on the interface implemented by backends can be in one place. The traits can provide default implementations where appropriate. Hopefully this will help with more refactoring and features.
1 parent e435fc9 commit 5c57eba

File tree

10 files changed

+426
-382
lines changed

10 files changed

+426
-382
lines changed

src/backend_dispatch.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//! Implements `buffer_interface::*` traits for enums dispatching to backends
2+
3+
use crate::{backend_interface::*, Rect, SoftBufferError};
4+
5+
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
6+
use std::num::NonZeroU32;
7+
#[cfg(any(wayland_platform, x11_platform, kms_platform))]
8+
use std::rc::Rc;
9+
10+
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
11+
macro_rules! make_dispatch {
12+
(
13+
<$dgen: ident, $wgen: ident> =>
14+
$(
15+
$(#[$attr:meta])*
16+
$name: ident
17+
($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
18+
)*
19+
) => {
20+
pub(crate) enum ContextDispatch<$dgen> {
21+
$(
22+
$(#[$attr])*
23+
$name($context_inner),
24+
)*
25+
}
26+
27+
impl<D: HasDisplayHandle> ContextDispatch<D> {
28+
pub fn variant_name(&self) -> &'static str {
29+
match self {
30+
$(
31+
$(#[$attr])*
32+
Self::$name(_) => stringify!($name),
33+
)*
34+
}
35+
}
36+
}
37+
38+
#[allow(clippy::large_enum_variant)] // it's boxed anyways
39+
pub(crate) enum SurfaceDispatch<$dgen, $wgen> {
40+
$(
41+
$(#[$attr])*
42+
$name($surface_inner),
43+
)*
44+
}
45+
46+
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<W> for SurfaceDispatch<D, W> {
47+
type Buffer<'a> = BufferDispatch<'a, D, W> where Self: 'a;
48+
49+
fn window(&self) -> &W {
50+
match self {
51+
$(
52+
$(#[$attr])*
53+
Self::$name(inner) => inner.window(),
54+
)*
55+
}
56+
}
57+
58+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
59+
match self {
60+
$(
61+
$(#[$attr])*
62+
Self::$name(inner) => inner.resize(width, height),
63+
)*
64+
}
65+
}
66+
67+
fn buffer_mut(&mut self) -> Result<BufferDispatch<'_, D, W>, SoftBufferError> {
68+
match self {
69+
$(
70+
$(#[$attr])*
71+
Self::$name(inner) => Ok(BufferDispatch::$name(inner.buffer_mut()?)),
72+
)*
73+
}
74+
}
75+
76+
fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
77+
match self {
78+
$(
79+
$(#[$attr])*
80+
Self::$name(inner) => inner.fetch(),
81+
)*
82+
}
83+
}
84+
}
85+
86+
pub(crate) enum BufferDispatch<'a, $dgen, $wgen> {
87+
$(
88+
$(#[$attr])*
89+
$name($buffer_inner),
90+
)*
91+
}
92+
93+
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferDispatch<'a, D, W> {
94+
#[inline]
95+
fn pixels(&self) -> &[u32] {
96+
match self {
97+
$(
98+
$(#[$attr])*
99+
Self::$name(inner) => inner.pixels(),
100+
)*
101+
}
102+
}
103+
104+
#[inline]
105+
fn pixels_mut(&mut self) -> &mut [u32] {
106+
match self {
107+
$(
108+
$(#[$attr])*
109+
Self::$name(inner) => inner.pixels_mut(),
110+
)*
111+
}
112+
}
113+
114+
fn age(&self) -> u8 {
115+
match self {
116+
$(
117+
$(#[$attr])*
118+
Self::$name(inner) => inner.age(),
119+
)*
120+
}
121+
}
122+
123+
fn present(self) -> Result<(), SoftBufferError> {
124+
match self {
125+
$(
126+
$(#[$attr])*
127+
Self::$name(inner) => inner.present(),
128+
)*
129+
}
130+
}
131+
132+
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
133+
match self {
134+
$(
135+
$(#[$attr])*
136+
Self::$name(inner) => inner.present_with_damage(damage),
137+
)*
138+
}
139+
}
140+
}
141+
};
142+
}
143+
144+
// XXX empty enum with generic bound is invalid?
145+
146+
make_dispatch! {
147+
<D, W> =>
148+
#[cfg(x11_platform)]
149+
X11(Rc<crate::x11::X11DisplayImpl<D>>, crate::x11::X11Impl<D, W>, crate::x11::BufferImpl<'a, D, W>),
150+
#[cfg(wayland_platform)]
151+
Wayland(Rc<crate::wayland::WaylandDisplayImpl<D>>, crate::wayland::WaylandImpl<D, W>, crate::wayland::BufferImpl<'a, D, W>),
152+
#[cfg(kms_platform)]
153+
Kms(Rc<crate::kms::KmsDisplayImpl<D>>, crate::kms::KmsImpl<D, W>, crate::kms::BufferImpl<'a, D, W>),
154+
#[cfg(target_os = "windows")]
155+
Win32(D, crate::win32::Win32Impl<D, W>, crate::win32::BufferImpl<'a, D, W>),
156+
#[cfg(target_os = "macos")]
157+
CG(D, crate::cg::CGImpl<D, W>, crate::cg::BufferImpl<'a, D, W>),
158+
#[cfg(target_arch = "wasm32")]
159+
Web(crate::web::WebDisplayImpl<D>, crate::web::WebImpl<D, W>, crate::web::BufferImpl<'a, D, W>),
160+
#[cfg(target_os = "redox")]
161+
Orbital(D, crate::orbital::OrbitalImpl<D, W>, crate::orbital::BufferImpl<'a, D, W>),
162+
}

src/backend_interface.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! Interface implemented by backends
2+
3+
use crate::{Rect, SoftBufferError};
4+
5+
use raw_window_handle::HasWindowHandle;
6+
use std::num::NonZeroU32;
7+
8+
pub(crate) trait SurfaceInterface<W: HasWindowHandle + ?Sized> {
9+
type Buffer<'a>: BufferInterface
10+
where
11+
Self: 'a;
12+
13+
/// Get the inner window handle.
14+
fn window(&self) -> &W;
15+
/// Resize the internal buffer to the given width and height.
16+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError>;
17+
/// Get a mutable reference to the buffer.
18+
fn buffer_mut(&mut self) -> Result<Self::Buffer<'_>, SoftBufferError>;
19+
/// Fetch the buffer from the window.
20+
fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
21+
Err(SoftBufferError::Unimplemented)
22+
}
23+
}
24+
25+
pub(crate) trait BufferInterface {
26+
fn pixels(&self) -> &[u32];
27+
fn pixels_mut(&mut self) -> &mut [u32];
28+
fn age(&self) -> u8;
29+
fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError>;
30+
fn present(self) -> Result<(), SoftBufferError>;
31+
}

src/cg.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::backend_interface::*;
12
use crate::error::InitError;
23
use crate::{Rect, SoftBufferError};
34
use core_graphics::base::{
@@ -65,19 +66,22 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
6566
window_handle: window_src,
6667
})
6768
}
69+
}
70+
71+
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<W> for CGImpl<D, W> {
72+
type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a;
6873

69-
/// Get the inner window handle.
7074
#[inline]
71-
pub fn window(&self) -> &W {
75+
fn window(&self) -> &W {
7276
&self.window_handle
7377
}
7478

75-
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
79+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
7680
self.size = Some((width, height));
7781
Ok(())
7882
}
7983

80-
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
84+
fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
8185
let (width, height) = self
8286
.size
8387
.expect("Must set size of surface before calling `buffer_mut()`");
@@ -87,34 +91,29 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
8791
imp: self,
8892
})
8993
}
90-
91-
/// Fetch the buffer from the window.
92-
pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
93-
Err(SoftBufferError::Unimplemented)
94-
}
9594
}
9695

9796
pub struct BufferImpl<'a, D, W> {
9897
imp: &'a mut CGImpl<D, W>,
9998
buffer: Vec<u32>,
10099
}
101100

102-
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
101+
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'a, D, W> {
103102
#[inline]
104-
pub fn pixels(&self) -> &[u32] {
103+
fn pixels(&self) -> &[u32] {
105104
&self.buffer
106105
}
107106

108107
#[inline]
109-
pub fn pixels_mut(&mut self) -> &mut [u32] {
108+
fn pixels_mut(&mut self) -> &mut [u32] {
110109
&mut self.buffer
111110
}
112111

113-
pub fn age(&self) -> u8 {
112+
fn age(&self) -> u8 {
114113
0
115114
}
116115

117-
pub fn present(self) -> Result<(), SoftBufferError> {
116+
fn present(self) -> Result<(), SoftBufferError> {
118117
let data_provider = CGDataProvider::from_buffer(Arc::new(Buffer(self.buffer)));
119118
let (width, height) = self.imp.size.unwrap();
120119
let image = CGImage::new(
@@ -148,7 +147,7 @@ impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
148147
Ok(())
149148
}
150149

151-
pub fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
150+
fn present_with_damage(self, _damage: &[Rect]) -> Result<(), SoftBufferError> {
152151
self.present()
153152
}
154153
}

src/kms.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::num::NonZeroU32;
1717
use std::os::unix::io::{AsFd, BorrowedFd};
1818
use std::rc::Rc;
1919

20+
use crate::backend_interface::*;
2021
use crate::error::{InitError, SoftBufferError, SwResultExt};
2122

2223
#[derive(Debug)]
@@ -203,19 +204,17 @@ impl<D: ?Sized, W: HasWindowHandle> KmsImpl<D, W> {
203204
window_handle: window,
204205
})
205206
}
207+
}
208+
209+
impl<D: ?Sized, W: HasWindowHandle> SurfaceInterface<W> for KmsImpl<D, W> {
210+
type Buffer<'a> = BufferImpl<'a, D, W> where Self: 'a;
206211

207-
/// Get the inner window handle.
208212
#[inline]
209-
pub fn window(&self) -> &W {
213+
fn window(&self) -> &W {
210214
&self.window_handle
211215
}
212216

213-
/// Resize the internal buffer to the given size.
214-
pub(crate) fn resize(
215-
&mut self,
216-
width: NonZeroU32,
217-
height: NonZeroU32,
218-
) -> Result<(), SoftBufferError> {
217+
fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
219218
// Don't resize if we don't have to.
220219
if let Some(buffer) = &self.buffer {
221220
let (buffer_width, buffer_height) = buffer.size();
@@ -237,14 +236,13 @@ impl<D: ?Sized, W: HasWindowHandle> KmsImpl<D, W> {
237236
Ok(())
238237
}
239238

240-
/// Fetch the buffer from the window.
241-
pub(crate) fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
239+
/*
240+
fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
242241
// TODO: Implement this!
243-
Err(SoftBufferError::Unimplemented)
244242
}
243+
*/
245244

246-
/// Get a mutable reference to the buffer.
247-
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
245+
fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
248246
// Map the dumb buffer.
249247
let set = self
250248
.buffer
@@ -299,26 +297,26 @@ impl<D: ?Sized, W: ?Sized> Drop for KmsImpl<D, W> {
299297
}
300298
}
301299

302-
impl<D: ?Sized, W: ?Sized> BufferImpl<'_, D, W> {
300+
impl<D: ?Sized, W: ?Sized> BufferInterface for BufferImpl<'_, D, W> {
303301
#[inline]
304-
pub fn pixels(&self) -> &[u32] {
302+
fn pixels(&self) -> &[u32] {
305303
// drm-rs doesn't let us have the immutable reference... so just use a bunch of zeroes.
306304
// TODO: There has to be a better way of doing this!
307305
self.zeroes
308306
}
309307

310308
#[inline]
311-
pub fn pixels_mut(&mut self) -> &mut [u32] {
309+
fn pixels_mut(&mut self) -> &mut [u32] {
312310
bytemuck::cast_slice_mut(self.mapping.as_mut())
313311
}
314312

315313
#[inline]
316-
pub fn age(&self) -> u8 {
314+
fn age(&self) -> u8 {
317315
*self.front_age
318316
}
319317

320318
#[inline]
321-
pub fn present_with_damage(self, damage: &[crate::Rect]) -> Result<(), SoftBufferError> {
319+
fn present_with_damage(self, damage: &[crate::Rect]) -> Result<(), SoftBufferError> {
322320
let rectangles = damage
323321
.iter()
324322
.map(|&rect| {
@@ -374,7 +372,7 @@ impl<D: ?Sized, W: ?Sized> BufferImpl<'_, D, W> {
374372
}
375373

376374
#[inline]
377-
pub fn present(self) -> Result<(), SoftBufferError> {
375+
fn present(self) -> Result<(), SoftBufferError> {
378376
let (width, height) = self.size;
379377
self.present_with_damage(&[crate::Rect {
380378
x: 0,

0 commit comments

Comments
 (0)