From 384f2dc9a3f6d0dbfb3e35cbfada5305d5d999bb Mon Sep 17 00:00:00 2001 From: David Johnson Date: Sat, 15 Jan 2022 08:17:17 -0600 Subject: [PATCH] Added X11 support --- .gitignore | 3 ++ Cargo.toml | 11 +++++++ examples/winit.rs | 37 +++++++++++++++++++++++ src/lib.rs | 62 +++++++++++++++++++++++++++++++++++++++ src/x11.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 examples/winit.rs create mode 100644 src/lib.rs create mode 100644 src/x11.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6a59f55 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +/.idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..83fa30c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "softbuffer" +version = "0.1.0" +edition = "2021" + +[dependencies] +raw-window-handle = "0.4.2" +x11-dl = "2.19.1" + +[dev-dependencies] +winit = "0.26.1" \ No newline at end of file diff --git a/examples/winit.rs b/examples/winit.rs new file mode 100644 index 0000000..52c18a9 --- /dev/null +++ b/examples/winit.rs @@ -0,0 +1,37 @@ +use std::time::Instant; +use winit::event::{Event, WindowEvent}; +use winit::event_loop::{ControlFlow, EventLoop}; +use winit::window::WindowBuilder; +use softbuffer::GraphicsContext; + +fn main() { + let event_loop = EventLoop::new(); + let window = WindowBuilder::new().build(&event_loop).unwrap(); + let mut graphics_context = unsafe { GraphicsContext::new(window) }; + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::RedrawRequested(window_id) if window_id == graphics_context.window().id() => { + let (width, height) = { + let size = graphics_context.window().inner_size(); + (size.width, size.height) + }; + let buffer = vec![0x00FF00FF; (width * height) as usize]; + + let start = Instant::now(); + graphics_context.set_buffer(&buffer, width as u16, height as u16); + let elapsed = Instant::now()-start; + println!("Set in: {}ms", elapsed.as_millis()); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + window_id + } if window_id == graphics_context.window().id() => { + *control_flow = ControlFlow::Exit; + }, + _ => {} + } + }); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9f35689 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,62 @@ +mod x11; + +use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; +use crate::x11::X11Impl; + +pub struct GraphicsContext{ + window: W, + graphics_context_impl: Box +} + +impl GraphicsContext { + + pub unsafe fn new(window: W) -> Self{ + let raw_handle = window.raw_window_handle(); + let imple = match raw_handle{ + RawWindowHandle::Xlib(xlib_handle) => Box::new(X11Impl::new(xlib_handle)), + unimplemented_handle_type => unimplemented!("Unsupported window handle type: {}.", window_handle_type_name(&unimplemented_handle_type)) + }; + + Self{ + window, + graphics_context_impl: imple + } + } + + #[inline] + pub fn window(&self) -> &W{ + &self.window + } + + #[inline] + pub fn window_mut(&mut self) -> &mut W{ + &mut self.window + } + + #[inline] + pub fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16){ + unsafe { + self.graphics_context_impl.set_buffer(buffer, width, height); + } + } + +} + +trait GraphicsContextImpl{ + unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16); +} + +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", + _ => "Unknown Name" //don't completely fail to compile if there is a new raw window handle type that's added at some point + } +} \ No newline at end of file diff --git a/src/x11.rs b/src/x11.rs new file mode 100644 index 0000000..3fd3786 --- /dev/null +++ b/src/x11.rs @@ -0,0 +1,75 @@ +use std::os::raw::{c_char, c_uint}; +use raw_window_handle::XlibHandle; +use x11_dl::xlib::{Display, GC, Visual, Xlib, ZPixmap}; +use crate::GraphicsContextImpl; + +pub struct X11Impl{ + handle: XlibHandle, + lib: Xlib, + gc: GC, + visual: *mut Visual, + depth: i32 +} + +impl X11Impl { + + pub unsafe fn new(handle: XlibHandle) -> Self{ + let lib = Xlib::open().unwrap(); + let screen = (lib.XDefaultScreen)(handle.display as *mut Display); + let gc = (lib.XDefaultGC)(handle.display as *mut Display, screen); + let visual = (lib.XDefaultVisual)(handle.display as *mut Display, screen); + let depth = (lib.XDefaultDepth)(handle.display as *mut Display, screen); + + Self{ + handle, + lib, + gc, + visual, + depth + } + } + +} + +impl GraphicsContextImpl for X11Impl { + + unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) { + let mut owned_buffer = vec![0; (width as usize)*(height as usize)]; + owned_buffer.copy_from_slice(buffer); + + //create image + let image = (self.lib.XCreateImage)( + self.handle.display as *mut Display, + self.visual, + self.depth as u32, + ZPixmap, + 0, + Box::leak(owned_buffer.into_boxed_slice()).as_mut_ptr() as *mut c_char, + width as u32, + height as u32, + 32, + (width*4) as i32 + ); + + if image.is_null(){ + panic!("Image is null!"); + } + + //push image to window + (self.lib.XPutImage)( + self.handle.display as *mut Display, + self.handle.window, + self.gc, + image, + 0, + 0, + 0, + 0, + width as c_uint, + height as c_uint + ); + + (self.lib.XDestroyImage)(image); + } + +} \ No newline at end of file