1#![doc = include_str!("../README.md")]
2#![deny(unsafe_op_in_unsafe_fn)]
3#![warn(missing_docs)]
4#![cfg_attr(docsrs, feature(doc_auto_cfg))]
5
6#[cfg(target_os = "macos")]
7#[macro_use]
8extern crate objc;
9extern crate core;
10
11#[cfg(target_os = "macos")]
12mod cg;
13#[cfg(kms_platform)]
14mod kms;
15#[cfg(target_os = "redox")]
16mod orbital;
17#[cfg(wayland_platform)]
18mod wayland;
19#[cfg(target_arch = "wasm32")]
20mod web;
21#[cfg(target_os = "windows")]
22mod win32;
23#[cfg(x11_platform)]
24mod x11;
25
26mod error;
27mod util;
28
29use std::marker::PhantomData;
30use std::num::NonZeroU32;
31use std::ops;
32#[cfg(any(wayland_platform, x11_platform, kms_platform))]
33use std::rc::Rc;
34
35use error::InitError;
36pub use error::SoftBufferError;
37
38use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
39
40#[cfg(target_arch = "wasm32")]
41pub use self::web::SurfaceExtWeb;
42
43pub struct Context<D> {
46 _marker: PhantomData<*mut ()>,
47
48 context_impl: ContextDispatch<D>,
50}
51
52macro_rules! make_dispatch {
54 (
55 <$dgen: ident, $wgen: ident> =>
56 $(
57 $(#[$attr:meta])*
58 $name: ident
59 ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
60 )*
61 ) => {
62 enum ContextDispatch<$dgen> {
63 $(
64 $(#[$attr])*
65 $name($context_inner),
66 )*
67 }
68
69 impl<D: HasDisplayHandle> ContextDispatch<D> {
70 fn variant_name(&self) -> &'static str {
71 match self {
72 $(
73 $(#[$attr])*
74 Self::$name(_) => stringify!($name),
75 )*
76 }
77 }
78 }
79
80 #[allow(clippy::large_enum_variant)] enum SurfaceDispatch<$dgen, $wgen> {
82 $(
83 $(#[$attr])*
84 $name($surface_inner),
85 )*
86 }
87
88 impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceDispatch<D, W> {
89 fn window(&self) -> &W {
90 match self {
91 $(
92 $(#[$attr])*
93 Self::$name(inner) => inner.window(),
94 )*
95 }
96 }
97
98 pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
99 match self {
100 $(
101 $(#[$attr])*
102 Self::$name(inner) => inner.resize(width, height),
103 )*
104 }
105 }
106
107 pub fn buffer_mut(&mut self) -> Result<BufferDispatch<'_, D, W>, SoftBufferError> {
108 match self {
109 $(
110 $(#[$attr])*
111 Self::$name(inner) => Ok(BufferDispatch::$name(inner.buffer_mut()?)),
112 )*
113 }
114 }
115
116 pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
117 match self {
118 $(
119 $(#[$attr])*
120 Self::$name(inner) => inner.fetch(),
121 )*
122 }
123 }
124 }
125
126 enum BufferDispatch<'a, $dgen, $wgen> {
127 $(
128 $(#[$attr])*
129 $name($buffer_inner),
130 )*
131 }
132
133 impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferDispatch<'a, D, W> {
134 #[inline]
135 pub fn pixels(&self) -> &[u32] {
136 match self {
137 $(
138 $(#[$attr])*
139 Self::$name(inner) => inner.pixels(),
140 )*
141 }
142 }
143
144 #[inline]
145 pub fn pixels_mut(&mut self) -> &mut [u32] {
146 match self {
147 $(
148 $(#[$attr])*
149 Self::$name(inner) => inner.pixels_mut(),
150 )*
151 }
152 }
153
154 pub fn age(&self) -> u8 {
155 match self {
156 $(
157 $(#[$attr])*
158 Self::$name(inner) => inner.age(),
159 )*
160 }
161 }
162
163 pub fn present(self) -> Result<(), SoftBufferError> {
164 match self {
165 $(
166 $(#[$attr])*
167 Self::$name(inner) => inner.present(),
168 )*
169 }
170 }
171
172 pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
173 match self {
174 $(
175 $(#[$attr])*
176 Self::$name(inner) => inner.present_with_damage(damage),
177 )*
178 }
179 }
180 }
181 };
182}
183
184make_dispatch! {
187 <D, W> =>
188 #[cfg(x11_platform)]
189 X11(Rc<x11::X11DisplayImpl<D>>, x11::X11Impl<D, W>, x11::BufferImpl<'a, D, W>),
190 #[cfg(wayland_platform)]
191 Wayland(Rc<wayland::WaylandDisplayImpl<D>>, wayland::WaylandImpl<D, W>, wayland::BufferImpl<'a, D, W>),
192 #[cfg(kms_platform)]
193 Kms(Rc<kms::KmsDisplayImpl<D>>, kms::KmsImpl<D, W>, kms::BufferImpl<'a, D, W>),
194 #[cfg(target_os = "windows")]
195 Win32(D, win32::Win32Impl<D, W>, win32::BufferImpl<'a, D, W>),
196 #[cfg(target_os = "macos")]
197 CG(D, cg::CGImpl<D, W>, cg::BufferImpl<'a, D, W>),
198 #[cfg(target_arch = "wasm32")]
199 Web(web::WebDisplayImpl<D>, web::WebImpl<D, W>, web::BufferImpl<'a, D, W>),
200 #[cfg(target_os = "redox")]
201 Orbital(D, orbital::OrbitalImpl<D, W>, orbital::BufferImpl<'a, D, W>),
202}
203
204impl<D: HasDisplayHandle> Context<D> {
205 pub fn new(mut dpy: D) -> Result<Self, SoftBufferError> {
207 macro_rules! try_init {
208 ($imp:ident, $x:ident => $make_it:expr) => {{
209 let $x = dpy;
210 match { $make_it } {
211 Ok(x) => {
212 return Ok(Self {
213 context_impl: ContextDispatch::$imp(x),
214 _marker: PhantomData,
215 })
216 }
217 Err(InitError::Unsupported(d)) => dpy = d,
218 Err(InitError::Failure(f)) => return Err(f),
219 }
220 }};
221 }
222
223 #[cfg(x11_platform)]
224 try_init!(X11, display => x11::X11DisplayImpl::new(display).map(Rc::new));
225 #[cfg(wayland_platform)]
226 try_init!(Wayland, display => wayland::WaylandDisplayImpl::new(display).map(Rc::new));
227 #[cfg(kms_platform)]
228 try_init!(Kms, display => kms::KmsDisplayImpl::new(display).map(Rc::new));
229 #[cfg(target_os = "windows")]
230 try_init!(Win32, display => Ok(display));
231 #[cfg(target_os = "macos")]
232 try_init!(CG, display => Ok(display));
233 #[cfg(target_arch = "wasm32")]
234 try_init!(Web, display => web::WebDisplayImpl::new(display));
235 #[cfg(target_os = "redox")]
236 try_init!(Orbital, display => Ok(display));
237
238 let raw = dpy.display_handle()?.as_raw();
239 Err(SoftBufferError::UnsupportedDisplayPlatform {
240 human_readable_display_platform_name: display_handle_type_name(&raw),
241 display_handle: raw,
242 })
243 }
244}
245
246#[derive(Clone, Copy, Debug)]
248pub struct Rect {
249 pub x: u32,
251 pub y: u32,
253 pub width: NonZeroU32,
255 pub height: NonZeroU32,
257}
258
259pub struct Surface<D, W> {
261 surface_impl: Box<SurfaceDispatch<D, W>>,
263 _marker: PhantomData<*mut ()>,
264}
265
266impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
267 pub fn new(context: &Context<D>, window: W) -> Result<Self, SoftBufferError> {
269 macro_rules! leap {
270 ($e:expr) => {{
271 match ($e) {
272 Ok(x) => x,
273 Err(InitError::Unsupported(window)) => {
274 let raw = window.window_handle()?.as_raw();
275 return Err(SoftBufferError::UnsupportedWindowPlatform {
276 human_readable_window_platform_name: window_handle_type_name(&raw),
277 human_readable_display_platform_name: context
278 .context_impl
279 .variant_name(),
280 window_handle: raw,
281 });
282 }
283 Err(InitError::Failure(f)) => return Err(f),
284 }
285 }};
286 }
287
288 let imple = match &context.context_impl {
289 #[cfg(x11_platform)]
290 ContextDispatch::X11(xcb_display_handle) => {
291 SurfaceDispatch::X11(leap!(x11::X11Impl::new(window, xcb_display_handle.clone())))
292 }
293 #[cfg(wayland_platform)]
294 ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!(
295 wayland::WaylandImpl::new(window, wayland_display_impl.clone())
296 )),
297 #[cfg(kms_platform)]
298 ContextDispatch::Kms(kms_display_impl) => {
299 SurfaceDispatch::Kms(leap!(kms::KmsImpl::new(window, kms_display_impl.clone())))
300 }
301 #[cfg(target_os = "windows")]
302 ContextDispatch::Win32(_) => {
303 SurfaceDispatch::Win32(leap!(win32::Win32Impl::new(window)))
304 }
305 #[cfg(target_os = "macos")]
306 ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(cg::CGImpl::new(window))),
307 #[cfg(target_arch = "wasm32")]
308 ContextDispatch::Web(web_display_impl) => {
309 SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window)))
310 }
311 #[cfg(target_os = "redox")]
312 ContextDispatch::Orbital(_) => {
313 SurfaceDispatch::Orbital(leap!(orbital::OrbitalImpl::new(window)))
314 }
315 };
316
317 Ok(Self {
318 surface_impl: Box::new(imple),
319 _marker: PhantomData,
320 })
321 }
322
323 pub fn window(&self) -> &W {
325 self.surface_impl.window()
326 }
327
328 pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
335 self.surface_impl.resize(width, height)
336 }
337
338 pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
347 self.surface_impl.fetch()
348 }
349
350 pub fn buffer_mut(&mut self) -> Result<Buffer<'_, D, W>, SoftBufferError> {
360 Ok(Buffer {
361 buffer_impl: self.surface_impl.buffer_mut()?,
362 _marker: PhantomData,
363 })
364 }
365}
366
367impl<D: HasDisplayHandle, W: HasWindowHandle> AsRef<W> for Surface<D, W> {
368 #[inline]
369 fn as_ref(&self) -> &W {
370 self.window()
371 }
372}
373
374impl<D: HasDisplayHandle, W: HasWindowHandle> HasWindowHandle for Surface<D, W> {
375 #[inline]
376 fn window_handle(
377 &self,
378 ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
379 self.window().window_handle()
380 }
381}
382
383pub struct Buffer<'a, D, W> {
421 buffer_impl: BufferDispatch<'a, D, W>,
422 _marker: PhantomData<*mut ()>,
423}
424
425impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> {
426 pub fn age(&self) -> u8 {
433 self.buffer_impl.age()
434 }
435
436 pub fn present(self) -> Result<(), SoftBufferError> {
449 self.buffer_impl.present()
450 }
451
452 pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
464 self.buffer_impl.present_with_damage(damage)
465 }
466}
467
468impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::Deref for Buffer<'a, D, W> {
469 type Target = [u32];
470
471 #[inline]
472 fn deref(&self) -> &[u32] {
473 self.buffer_impl.pixels()
474 }
475}
476
477impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::DerefMut for Buffer<'a, D, W> {
478 #[inline]
479 fn deref_mut(&mut self) -> &mut [u32] {
480 self.buffer_impl.pixels_mut()
481 }
482}
483
484#[derive(Debug)]
486pub struct NoDisplayHandle(core::convert::Infallible);
487
488impl HasDisplayHandle for NoDisplayHandle {
489 fn display_handle(
490 &self,
491 ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
492 match self.0 {}
493 }
494}
495
496#[derive(Debug)]
498pub struct NoWindowHandle(());
499
500impl HasWindowHandle for NoWindowHandle {
501 fn window_handle(
502 &self,
503 ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
504 Err(raw_window_handle::HandleError::NotSupported)
505 }
506}
507
508fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
509 match handle {
510 RawWindowHandle::Xlib(_) => "Xlib",
511 RawWindowHandle::Win32(_) => "Win32",
512 RawWindowHandle::WinRt(_) => "WinRt",
513 RawWindowHandle::Web(_) => "Web",
514 RawWindowHandle::Wayland(_) => "Wayland",
515 RawWindowHandle::AndroidNdk(_) => "AndroidNdk",
516 RawWindowHandle::AppKit(_) => "AppKit",
517 RawWindowHandle::Orbital(_) => "Orbital",
518 RawWindowHandle::UiKit(_) => "UiKit",
519 RawWindowHandle::Xcb(_) => "XCB",
520 RawWindowHandle::Drm(_) => "DRM",
521 RawWindowHandle::Gbm(_) => "GBM",
522 RawWindowHandle::Haiku(_) => "Haiku",
523 _ => "Unknown Name", }
525}
526
527fn display_handle_type_name(handle: &RawDisplayHandle) -> &'static str {
528 match handle {
529 RawDisplayHandle::Xlib(_) => "Xlib",
530 RawDisplayHandle::Web(_) => "Web",
531 RawDisplayHandle::Wayland(_) => "Wayland",
532 RawDisplayHandle::AppKit(_) => "AppKit",
533 RawDisplayHandle::Orbital(_) => "Orbital",
534 RawDisplayHandle::UiKit(_) => "UiKit",
535 RawDisplayHandle::Xcb(_) => "XCB",
536 RawDisplayHandle::Drm(_) => "DRM",
537 RawDisplayHandle::Gbm(_) => "GBM",
538 RawDisplayHandle::Haiku(_) => "Haiku",
539 RawDisplayHandle::Windows(_) => "Windows",
540 RawDisplayHandle::Android(_) => "Android",
541 _ => "Unknown Name", }
543}