#![doc = include_str!("../README.md")]
#![allow(clippy::needless_doctest_main)]
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
extern crate core;
mod backend_dispatch;
use backend_dispatch::*;
mod backend_interface;
use backend_interface::*;
mod backends;
mod error;
mod util;
use std::cell::Cell;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::ops;
use std::sync::Arc;
use error::InitError;
pub use error::SoftBufferError;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
#[cfg(target_family = "wasm")]
pub use backends::web::SurfaceExtWeb;
#[derive(Clone, Debug)]
pub struct Context<D> {
context_impl: ContextDispatch<D>,
_marker: PhantomData<Arc<D>>,
}
impl<D: HasDisplayHandle> Context<D> {
pub fn new(display: D) -> Result<Self, SoftBufferError> {
match ContextDispatch::new(display) {
Ok(context_impl) => Ok(Self {
context_impl,
_marker: PhantomData,
}),
Err(InitError::Unsupported(display)) => {
let raw = display.display_handle()?.as_raw();
Err(SoftBufferError::UnsupportedDisplayPlatform {
human_readable_display_platform_name: display_handle_type_name(&raw),
display_handle: raw,
})
}
Err(InitError::Failure(f)) => Err(f),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct Rect {
pub x: u32,
pub y: u32,
pub width: NonZeroU32,
pub height: NonZeroU32,
}
#[derive(Debug)]
pub struct Surface<D, W> {
surface_impl: Box<SurfaceDispatch<D, W>>,
_marker: PhantomData<Cell<()>>,
}
impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
pub fn new(context: &Context<D>, window: W) -> Result<Self, SoftBufferError> {
match SurfaceDispatch::new(window, &context.context_impl) {
Ok(surface_dispatch) => Ok(Self {
surface_impl: Box::new(surface_dispatch),
_marker: PhantomData,
}),
Err(InitError::Unsupported(window)) => {
let raw = window.window_handle()?.as_raw();
Err(SoftBufferError::UnsupportedWindowPlatform {
human_readable_window_platform_name: window_handle_type_name(&raw),
human_readable_display_platform_name: context.context_impl.variant_name(),
window_handle: raw,
})
}
Err(InitError::Failure(f)) => Err(f),
}
}
pub fn window(&self) -> &W {
self.surface_impl.window()
}
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
self.surface_impl.resize(width, height)
}
pub fn fetch(&mut self) -> Result<Vec<u32>, SoftBufferError> {
self.surface_impl.fetch()
}
pub fn buffer_mut(&mut self) -> Result<Buffer<'_, D, W>, SoftBufferError> {
Ok(Buffer {
buffer_impl: self.surface_impl.buffer_mut()?,
_marker: PhantomData,
})
}
}
impl<D: HasDisplayHandle, W: HasWindowHandle> AsRef<W> for Surface<D, W> {
#[inline]
fn as_ref(&self) -> &W {
self.window()
}
}
impl<D: HasDisplayHandle, W: HasWindowHandle> HasWindowHandle for Surface<D, W> {
#[inline]
fn window_handle(
&self,
) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
self.window().window_handle()
}
}
#[derive(Debug)]
pub struct Buffer<'a, D, W> {
buffer_impl: BufferDispatch<'a, D, W>,
_marker: PhantomData<(Arc<D>, Cell<()>)>,
}
impl<D: HasDisplayHandle, W: HasWindowHandle> Buffer<'_, D, W> {
pub fn width(&self) -> NonZeroU32 {
let width = self.buffer_impl.width();
debug_assert_eq!(
width.get() as usize * self.buffer_impl.height().get() as usize,
self.len(),
"buffer must be sized correctly"
);
width
}
pub fn height(&self) -> NonZeroU32 {
let height = self.buffer_impl.height();
debug_assert_eq!(
height.get() as usize * self.buffer_impl.width().get() as usize,
self.len(),
"buffer must be sized correctly"
);
height
}
pub fn age(&self) -> u8 {
self.buffer_impl.age()
}
pub fn present(self) -> Result<(), SoftBufferError> {
self.buffer_impl.present()
}
pub fn present_with_damage(self, damage: &[Rect]) -> Result<(), SoftBufferError> {
self.buffer_impl.present_with_damage(damage)
}
}
impl<D: HasDisplayHandle, W: HasWindowHandle> ops::Deref for Buffer<'_, D, W> {
type Target = [u32];
#[inline]
fn deref(&self) -> &[u32] {
self.buffer_impl.pixels()
}
}
impl<D: HasDisplayHandle, W: HasWindowHandle> ops::DerefMut for Buffer<'_, D, W> {
#[inline]
fn deref_mut(&mut self) -> &mut [u32] {
self.buffer_impl.pixels_mut()
}
}
#[derive(Debug)]
#[allow(dead_code)]
pub struct NoDisplayHandle(core::convert::Infallible);
impl HasDisplayHandle for NoDisplayHandle {
fn display_handle(
&self,
) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
match self.0 {}
}
}
#[derive(Debug)]
pub struct NoWindowHandle(());
impl HasWindowHandle for NoWindowHandle {
fn window_handle(
&self,
) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
Err(raw_window_handle::HandleError::NotSupported)
}
}
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
match handle {
RawWindowHandle::Xlib(_) => "Xlib",
RawWindowHandle::Win32(_) => "Win32",
RawWindowHandle::WinRt(_) => "WinRt",
RawWindowHandle::Web(_) => "Web",
RawWindowHandle::Wayland(_) => "Wayland",
RawWindowHandle::AndroidNdk(_) => "AndroidNdk",
RawWindowHandle::AppKit(_) => "AppKit",
RawWindowHandle::Orbital(_) => "Orbital",
RawWindowHandle::UiKit(_) => "UiKit",
RawWindowHandle::Xcb(_) => "XCB",
RawWindowHandle::Drm(_) => "DRM",
RawWindowHandle::Gbm(_) => "GBM",
RawWindowHandle::Haiku(_) => "Haiku",
_ => "Unknown Name", }
}
fn display_handle_type_name(handle: &RawDisplayHandle) -> &'static str {
match handle {
RawDisplayHandle::Xlib(_) => "Xlib",
RawDisplayHandle::Web(_) => "Web",
RawDisplayHandle::Wayland(_) => "Wayland",
RawDisplayHandle::AppKit(_) => "AppKit",
RawDisplayHandle::Orbital(_) => "Orbital",
RawDisplayHandle::UiKit(_) => "UiKit",
RawDisplayHandle::Xcb(_) => "XCB",
RawDisplayHandle::Drm(_) => "DRM",
RawDisplayHandle::Gbm(_) => "GBM",
RawDisplayHandle::Haiku(_) => "Haiku",
RawDisplayHandle::Windows(_) => "Windows",
RawDisplayHandle::Android(_) => "Android",
_ => "Unknown Name", }
}
#[cfg(not(target_family = "wasm"))]
fn __assert_send() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<Context<()>>();
is_sync::<Context<()>>();
is_send::<Surface<(), ()>>();
is_send::<Buffer<'static, (), ()>>();
fn __surface_not_sync() {}
fn __buffer_not_sync() {}
}