Use static dispatch

This commit is contained in:
jtnunley 2022-12-22 10:09:47 -08:00
parent 58d4fd41b7
commit 319ff565a5
7 changed files with 75 additions and 49 deletions

View file

@ -1,4 +1,4 @@
use crate::{GraphicsContextImpl, SwBufError}; use crate::SwBufError;
use raw_window_handle::AppKitWindowHandle; use raw_window_handle::AppKitWindowHandle;
use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault}; use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault};
use core_graphics::color_space::CGColorSpace; use core_graphics::color_space::CGColorSpace;
@ -32,10 +32,8 @@ impl CGImpl {
let _: () = msg_send![subview, release]; // releases subview (-1) = 1 let _: () = msg_send![subview, release]; // releases subview (-1) = 1
Ok(Self{layer}) Ok(Self{layer})
} }
}
impl GraphicsContextImpl for CGImpl { pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
let color_space = CGColorSpace::create_device_rgb(); let color_space = CGColorSpace::create_device_rgb();
let data = std::slice::from_raw_parts( let data = std::slice::from_raw_parts(
buffer.as_ptr() as *const u8, buffer.as_ptr() as *const u8,

View file

@ -27,7 +27,54 @@ use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandl
/// An instance of this struct contains the platform-specific data that must be managed in order to /// An instance of this struct contains the platform-specific data that must be managed in order to
/// write to a window on that platform. /// write to a window on that platform.
pub struct GraphicsContext { pub struct GraphicsContext {
graphics_context_impl: Box<dyn GraphicsContextImpl>, /// The inner static dispatch object.
///
/// This is boxed so that `GraphicsContext` is the same size on every platform, which should
/// hopefully prevent surprises.
graphics_context_impl: Box<Dispatch>
}
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
macro_rules! make_dispatch {
(
$(
$(#[$attr:meta])*
$name: ident ($inner_ty: ty),
)*
) => {
enum Dispatch {
$(
$(#[$attr])*
$name($inner_ty),
)*
}
impl Dispatch {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
match self {
$(
$(#[$attr])*
Self::$name(inner) => inner.set_buffer(buffer, width, height),
)*
}
}
}
};
}
make_dispatch! {
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
X11(x11::X11Impl),
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
Wayland(wayland::WaylandImpl),
#[cfg(target_os = "windows")]
Win32(win32::Win32Impl),
#[cfg(target_os = "macos")]
CG(cg::CGImpl),
#[cfg(target_arch = "wasm32")]
Web(web::WebImpl),
#[cfg(target_os = "redox")]
Orbital(orbital::OrbitalImpl),
} }
impl GraphicsContext { impl GraphicsContext {
@ -48,19 +95,19 @@ impl GraphicsContext {
/// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the /// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the
/// lifetime of the GraphicsContext /// lifetime of the GraphicsContext
pub unsafe fn from_raw(raw_window_handle: RawWindowHandle, raw_display_handle: RawDisplayHandle) -> Result<Self, SwBufError> { pub unsafe fn from_raw(raw_window_handle: RawWindowHandle, raw_display_handle: RawDisplayHandle) -> Result<Self, SwBufError> {
let imple: Box<dyn GraphicsContextImpl> = match (raw_window_handle, raw_display_handle) { let imple: Dispatch = match (raw_window_handle, raw_display_handle) {
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))] #[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
(RawWindowHandle::Xlib(xlib_window_handle), RawDisplayHandle::Xlib(xlib_display_handle)) => Box::new(x11::X11Impl::new(xlib_window_handle, xlib_display_handle)?), (RawWindowHandle::Xlib(xlib_window_handle), RawDisplayHandle::Xlib(xlib_display_handle)) => Dispatch::X11(x11::X11Impl::new(xlib_window_handle, xlib_display_handle)?),
#[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))] #[cfg(all(feature = "wayland", any(target_os = "linux", target_os = "freebsd")))]
(RawWindowHandle::Wayland(wayland_window_handle), RawDisplayHandle::Wayland(wayland_display_handle)) => Box::new(wayland::WaylandImpl::new(wayland_window_handle, wayland_display_handle)?), (RawWindowHandle::Wayland(wayland_window_handle), RawDisplayHandle::Wayland(wayland_display_handle)) => Dispatch::Wayland(wayland::WaylandImpl::new(wayland_window_handle, wayland_display_handle)?),
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
(RawWindowHandle::Win32(win32_handle), _) => Box::new(win32::Win32Impl::new(&win32_handle)?), (RawWindowHandle::Win32(win32_handle), _) => Dispatch::Win32(win32::Win32Impl::new(&win32_handle)?),
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
(RawWindowHandle::AppKit(appkit_handle), _) => Box::new(cg::CGImpl::new(appkit_handle)?), (RawWindowHandle::AppKit(appkit_handle), _) => Dispatch::CG(cg::CGImpl::new(appkit_handle)?),
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
(RawWindowHandle::Web(web_handle), _) => Box::new(web::WebImpl::new(web_handle)?), (RawWindowHandle::Web(web_handle), _) => Dispatch::Web(web::WebImpl::new(web_handle)?),
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
(RawWindowHandle::Orbital(orbital_handle), _) => Box::new(orbital::OrbitalImpl::new(orbital_handle)?), (RawWindowHandle::Orbital(orbital_handle), _) => Dispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?),
(unimplemented_window_handle, unimplemented_display_handle) => return Err(SwBufError::UnsupportedPlatform { (unimplemented_window_handle, unimplemented_display_handle) => return Err(SwBufError::UnsupportedPlatform {
human_readable_window_platform_name: window_handle_type_name(&unimplemented_window_handle), human_readable_window_platform_name: window_handle_type_name(&unimplemented_window_handle),
human_readable_display_platform_name: display_handle_type_name(&unimplemented_display_handle), human_readable_display_platform_name: display_handle_type_name(&unimplemented_display_handle),
@ -70,7 +117,7 @@ impl GraphicsContext {
}; };
Ok(Self { Ok(Self {
graphics_context_impl: imple, graphics_context_impl: Box::new(imple)
}) })
} }
@ -109,10 +156,6 @@ impl GraphicsContext {
} }
} }
trait GraphicsContextImpl {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16);
}
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str { fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
match handle { match handle {
RawWindowHandle::Xlib(_) => "Xlib", RawWindowHandle::Xlib(_) => "Xlib",

View file

@ -5,7 +5,6 @@ use std::{
str, str,
}; };
use crate::GraphicsContextImpl;
use crate::SwBufError; use crate::SwBufError;
struct OrbitalMap { struct OrbitalMap {
@ -49,10 +48,8 @@ impl OrbitalImpl {
pub fn new(handle: OrbitalWindowHandle) -> Result<Self, SwBufError> { pub fn new(handle: OrbitalWindowHandle) -> Result<Self, SwBufError> {
Ok(Self { handle }) Ok(Self { handle })
} }
}
impl GraphicsContextImpl for OrbitalImpl { pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width_u16: u16, height_u16: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width_u16: u16, height_u16: u16) {
let window_fd = self.handle.window as usize; let window_fd = self.handle.window as usize;
// Read the current width and size // Read the current width and size

View file

@ -1,4 +1,4 @@
use crate::{error::unwrap, GraphicsContextImpl, SwBufError}; use crate::{error::unwrap, SwBufError};
use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle}; use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};
use std::collections::VecDeque; use std::collections::VecDeque;
use wayland_client::{ use wayland_client::{
@ -78,10 +78,8 @@ impl WaylandImpl {
self.buffers.push_back(buffer); self.buffers.push_back(buffer);
self.buffers.back().unwrap() self.buffers.back().unwrap()
} }
}
impl GraphicsContextImpl for WaylandImpl { pub(super) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
let _ = self.event_queue.dispatch_pending(&mut State); let _ = self.event_queue.dispatch_pending(&mut State);
let surface = self.surface.clone(); let surface = self.surface.clone();

View file

@ -5,7 +5,6 @@ use web_sys::CanvasRenderingContext2d;
use web_sys::HtmlCanvasElement; use web_sys::HtmlCanvasElement;
use web_sys::ImageData; use web_sys::ImageData;
use crate::GraphicsContextImpl;
use crate::SwBufError; use crate::SwBufError;
pub struct WebImpl { pub struct WebImpl {
@ -60,10 +59,8 @@ impl WebImpl {
Ok(Self { canvas, ctx }) Ok(Self { canvas, ctx })
} }
}
impl GraphicsContextImpl for WebImpl { pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
self.canvas.set_width(width.into()); self.canvas.set_width(width.into());
self.canvas.set_height(height.into()); self.canvas.set_height(height.into());

View file

@ -2,11 +2,11 @@
//! //!
//! This module converts the input buffer into a bitmap and then stretches it to the window. //! This module converts the input buffer into a bitmap and then stretches it to the window.
use crate::{GraphicsContextImpl, SwBufError}; use crate::SwBufError;
use raw_window_handle::Win32WindowHandle; use raw_window_handle::Win32WindowHandle;
use std::mem;
use std::io; use std::io;
use std::mem;
use std::os::raw::c_int; use std::os::raw::c_int;
use windows_sys::Win32::Foundation::HWND; use windows_sys::Win32::Foundation::HWND;
@ -56,17 +56,12 @@ impl Win32Impl {
)); ));
} }
Ok(Self { Ok(Self { dc, window: hwnd })
dc,
window: hwnd,
})
} }
}
impl GraphicsContextImpl for Win32Impl { pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
// Create a new bitmap info struct. // Create a new bitmap info struct.
let mut bitmap_info: BitmapInfo =mem::zeroed(); let mut bitmap_info: BitmapInfo = mem::zeroed();
bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32; bitmap_info.bmi_header.biSize = mem::size_of::<BITMAPINFOHEADER>() as u32;
bitmap_info.bmi_header.biPlanes = 1; bitmap_info.bmi_header.biPlanes = 1;

View file

@ -4,7 +4,7 @@
//! drawn. A more effective implementation would use shared memory instead of the wire. In //! drawn. A more effective implementation would use shared memory instead of the wire. In
//! addition, we may also want to blit to a pixmap instead of a window. //! addition, we may also want to blit to a pixmap instead of a window.
use crate::{GraphicsContextImpl, SwBufError}; use crate::SwBufError;
use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle}; use raw_window_handle::{XlibDisplayHandle, XlibWindowHandle};
use std::os::raw::{c_char, c_uint}; use std::os::raw::{c_char, c_uint};
use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC}; use x11_dl::xlib::{Display, Visual, Xlib, ZPixmap, GC};
@ -83,10 +83,8 @@ impl X11Impl {
depth, depth,
}) })
} }
}
impl GraphicsContextImpl for X11Impl { pub(crate) unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
// Create the image from the buffer. // Create the image from the buffer.
let image = (self.lib.XCreateImage)( let image = (self.lib.XCreateImage)(
self.display_handle.display as *mut Display, self.display_handle.display as *mut Display,