breaking: Use raw-window-handle version 0.6

Signed-off-by: John Nunley <dev@notgull.net>
Co-Authored-By: dAxpeDDa <daxpedda@gmail.com>
This commit is contained in:
John Nunley 2023-10-26 19:15:51 -07:00 committed by GitHub
parent 18c944736e
commit 0bcd2e22a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 830 additions and 628 deletions

View file

@ -1,3 +1,7 @@
# Unreleased
* **Breaking:** Port to use `raw-window-handle` v0.6.
# 0.3.2
* Document that `present_with_damage` is supported on web platforms. (#152)

View file

@ -26,7 +26,7 @@ x11-dlopen = ["tiny-xlib/dlopen", "x11rb/dl-libxcb"]
[dependencies]
log = "0.4.17"
raw-window-handle = "0.5.0"
raw_window_handle = { package = "raw-window-handle", version = "0.6", features = ["std"] }
[target.'cfg(all(unix, not(any(target_vendor = "apple", target_os = "android", target_os = "redox"))))'.dependencies]
as-raw-xcb-connection = { version = "1.0.0", optional = true }
@ -79,7 +79,7 @@ cfg_aliases = "0.1.1"
colorous = "1.0.12"
criterion = { version = "0.4.0", default-features = false, features = ["cargo_bench_support"] }
instant = "0.1.12"
winit = "0.28.1"
winit = "0.29.2"
winit-test = "0.1.0"
[dev-dependencies.image]
@ -119,3 +119,4 @@ targets = [
"x86_64-unknown-linux-gnu",
"wasm32-unknown-unknown",
]

View file

@ -59,21 +59,22 @@ Example
==
```rust,no_run
use std::num::NonZeroU32;
use std::rc::Rc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let event_loop = EventLoop::new().unwrap();
let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested } if window_id == window.id() => {
let (width, height) = {
let size = window.inner_size();
(size.width, size.height)
@ -96,17 +97,17 @@ fn main() {
buffer[index as usize] = blue | (green << 8) | (red << 16);
}
buffer.present().unwrap();
buffer.present().unwrap();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
elwt.exit();
}
_ => {}
}
});
}).unwrap();
}
```

View file

@ -12,21 +12,22 @@ fn buffer_mut(c: &mut Criterion) {
use criterion::black_box;
use softbuffer::{Context, Surface};
use std::num::NonZeroU32;
use winit::platform::run_return::EventLoopExtRunReturn;
use winit::event_loop::ControlFlow;
use winit::platform::run_on_demand::EventLoopExtRunOnDemand;
let mut evl = winit::event_loop::EventLoop::new();
let mut evl = winit::event_loop::EventLoop::new().unwrap();
let window = winit::window::WindowBuilder::new()
.with_visible(false)
.build(&evl)
.unwrap();
evl.run_return(move |ev, elwt, control_flow| {
control_flow.set_poll();
evl.run_on_demand(move |ev, elwt| {
elwt.set_control_flow(ControlFlow::Poll);
if let winit::event::Event::RedrawEventsCleared = ev {
control_flow.set_exit();
if let winit::event::Event::AboutToWait = ev {
elwt.exit();
let mut surface = unsafe {
let mut surface = {
let context = Context::new(elwt).unwrap();
Surface::new(&context, &window).unwrap()
};
@ -57,7 +58,8 @@ fn buffer_mut(c: &mut Criterion) {
});
});
}
});
})
.unwrap();
}
}

View file

@ -3,13 +3,14 @@ use instant::Instant;
use rayon::prelude::*;
use std::f64::consts::PI;
use std::num::NonZeroU32;
use std::rc::Rc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let event_loop = EventLoop::new().unwrap();
let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
#[cfg(target_arch = "wasm32")]
{
@ -21,57 +22,58 @@ fn main() {
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.append_child(&window.canvas().unwrap())
.unwrap();
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
let mut old_size = (0, 0);
let mut frames = pre_render_frames(0, 0);
let start = Instant::now();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Poll);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
let elapsed = start.elapsed().as_secs_f64() % 1.0;
let (width, height) = {
let size = window.inner_size();
(size.width, size.height)
};
match event {
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
} if window_id == window.id() => {
if let (Some(width), Some(height)) = {
let size = window.inner_size();
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
} {
let elapsed = start.elapsed().as_secs_f64() % 1.0;
if (width, height) != old_size {
old_size = (width, height);
frames = pre_render_frames(width as usize, height as usize);
};
if (width.get(), height.get()) != old_size {
old_size = (width.get(), height.get());
frames = pre_render_frames(width.get() as usize, height.get() as usize);
};
let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)];
let frame = &frames[((elapsed * 60.0).round() as usize).clamp(0, 59)];
surface
.resize(
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
)
.unwrap();
let mut buffer = surface.buffer_mut().unwrap();
buffer.copy_from_slice(frame);
buffer.present().unwrap();
surface.resize(width, height).unwrap();
let mut buffer = surface.buffer_mut().unwrap();
buffer.copy_from_slice(frame);
buffer.present().unwrap();
}
}
Event::AboutToWait => {
window.request_redraw();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
elwt.exit();
}
_ => {}
}
Event::MainEventsCleared => {
window.request_redraw();
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
})
.unwrap();
}
fn pre_render_frames(width: usize, height: usize) -> Vec<Vec<u32>> {

View file

@ -5,7 +5,7 @@ mod imple {
use drm::control::{connector, Device as CtrlDevice, Event, ModeTypeFlags, PlaneType};
use drm::Device;
use raw_window_handle::{DrmDisplayHandle, DrmWindowHandle};
use raw_window_handle::{DisplayHandle, DrmDisplayHandle, DrmWindowHandle, WindowHandle};
use softbuffer::{Context, Surface};
use std::num::NonZeroU32;
@ -19,11 +19,10 @@ mod imple {
// Create the softbuffer context.
let context = unsafe {
Context::from_raw({
let mut handle = DrmDisplayHandle::empty();
handle.fd = device.as_fd().as_raw_fd();
Context::new(DisplayHandle::borrow_raw({
let handle = DrmDisplayHandle::new(device.as_fd().as_raw_fd());
handle.into()
})
}))
}?;
// Get the DRM handles.
@ -93,11 +92,13 @@ mod imple {
// Create the surface on top of this plane.
// Note: This requires root on DRM/KMS.
let mut surface = unsafe {
Surface::from_raw(&context, {
let mut handle = DrmWindowHandle::empty();
handle.plane = (**plane).into();
handle.into()
})
Surface::new(
&context,
WindowHandle::borrow_raw({
let handle = DrmWindowHandle::new((**plane).into());
handle.into()
}),
)
}?;
// Resize the surface.

View file

@ -1,5 +1,6 @@
use image::GenericImageView;
use std::num::NonZeroU32;
use std::rc::Rc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
@ -8,11 +9,13 @@ fn main() {
//see fruit.jpg.license for the license of fruit.jpg
let fruit = image::load_from_memory(include_bytes!("fruit.jpg")).unwrap();
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.with_inner_size(winit::dpi::PhysicalSize::new(fruit.width(), fruit.height()))
.build(&event_loop)
.unwrap();
let event_loop = EventLoop::new().unwrap();
let window = Rc::new(
WindowBuilder::new()
.with_inner_size(winit::dpi::PhysicalSize::new(fruit.width(), fruit.height()))
.build(&event_loop)
.unwrap(),
);
#[cfg(target_arch = "wasm32")]
{
@ -24,45 +27,50 @@ fn main() {
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.append_child(&window.canvas().unwrap())
.unwrap();
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
surface
.resize(
NonZeroU32::new(fruit.width()).unwrap(),
NonZeroU32::new(fruit.height()).unwrap(),
)
.unwrap();
match event {
Event::WindowEvent {
window_id,
event: WindowEvent::CloseRequested,
} if window_id == window.id() => {
surface
.resize(
NonZeroU32::new(fruit.width()).unwrap(),
NonZeroU32::new(fruit.height()).unwrap(),
)
.unwrap();
let mut buffer = surface.buffer_mut().unwrap();
let width = fruit.width() as usize;
for (x, y, pixel) in fruit.pixels() {
let red = pixel.0[0] as u32;
let green = pixel.0[1] as u32;
let blue = pixel.0[2] as u32;
let mut buffer = surface.buffer_mut().unwrap();
let width = fruit.width() as usize;
for (x, y, pixel) in fruit.pixels() {
let red = pixel.0[0] as u32;
let green = pixel.0[1] as u32;
let blue = pixel.0[2] as u32;
let color = blue | (green << 8) | (red << 16);
buffer[y as usize * width + x as usize] = color;
let color = blue | (green << 8) | (red << 16);
buffer[y as usize * width + x as usize] = color;
}
buffer.present().unwrap();
}
buffer.present().unwrap();
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
elwt.exit();
}
_ => {}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
})
.unwrap();
}

View file

@ -2,8 +2,11 @@
#[cfg(all(feature = "x11", any(target_os = "linux", target_os = "freebsd")))]
mod example {
use raw_window_handle::{RawDisplayHandle, RawWindowHandle, XcbDisplayHandle, XcbWindowHandle};
use std::num::NonZeroU32;
use raw_window_handle::{
DisplayHandle, RawDisplayHandle, RawWindowHandle, WindowHandle, XcbDisplayHandle,
XcbWindowHandle,
};
use std::{num::NonZeroU32, ptr::NonNull};
use x11rb::{
connection::Connection,
protocol::{
@ -20,9 +23,10 @@ mod example {
let (conn, screen) = XCBConnection::connect(None).expect("Failed to connect to X server");
// x11rb doesn't use raw-window-handle yet, so just create our own.
let mut display_handle = XcbDisplayHandle::empty();
display_handle.connection = conn.get_raw_xcb_connection() as *mut _;
display_handle.screen = screen as _;
let display_handle = XcbDisplayHandle::new(
NonNull::new(conn.get_raw_xcb_connection() as *mut _),
screen as _,
);
// Create a new window.
let mut width = 640u16;
@ -50,18 +54,17 @@ mod example {
.check()
.unwrap();
let mut window_handle = XcbWindowHandle::empty();
window_handle.window = window as _;
window_handle.visual_id = root_visual as _;
let mut window_handle = XcbWindowHandle::new(NonZeroU32::new(window).unwrap());
window_handle.visual_id = NonZeroU32::new(root_visual);
// Create a new softbuffer context.
// SAFETY: The display and window handles outlive the context.
let context =
unsafe { softbuffer::Context::from_raw(RawDisplayHandle::Xcb(display_handle)) }
.unwrap();
let mut surface =
unsafe { softbuffer::Surface::from_raw(&context, RawWindowHandle::Xcb(window_handle)) }
.unwrap();
let display_handle =
unsafe { DisplayHandle::borrow_raw(RawDisplayHandle::Xcb(display_handle)) };
let window_handle =
unsafe { WindowHandle::borrow_raw(RawWindowHandle::Xcb(window_handle)) };
let context = softbuffer::Context::new(display_handle).unwrap();
let mut surface = softbuffer::Surface::new(&context, window_handle).unwrap();
// Register an atom for closing the window.
let wm_protocols_atom = conn

View file

@ -1,6 +1,8 @@
use std::num::NonZeroU32;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use std::rc::Rc;
use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::keyboard::{KeyCode, PhysicalKey};
use winit::window::WindowBuilder;
fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) {
@ -20,12 +22,14 @@ fn redraw(buffer: &mut [u32], width: usize, height: usize, flag: bool) {
}
fn main() {
let event_loop = EventLoop::new();
let event_loop = EventLoop::new().unwrap();
let window = WindowBuilder::new()
.with_title("Press space to show/hide a rectangle")
.build(&event_loop)
.unwrap();
let window = Rc::new(
WindowBuilder::new()
.with_title("Press space to show/hide a rectangle")
.build(&event_loop)
.unwrap(),
);
#[cfg(target_arch = "wasm32")]
{
@ -37,66 +41,71 @@ fn main() {
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.append_child(&window.canvas().unwrap())
.unwrap();
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
let mut flag = false;
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
// Grab the window's client area dimensions
let (width, height) = {
let size = window.inner_size();
(size.width, size.height)
};
match event {
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
} if window_id == window.id() => {
// Grab the window's client area dimensions
if let (Some(width), Some(height)) = {
let size = window.inner_size();
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
} {
// Resize surface if needed
surface.resize(width, height).unwrap();
// Resize surface if needed
surface
.resize(
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
)
.unwrap();
// Draw something in the window
let mut buffer = surface.buffer_mut().unwrap();
redraw(
&mut buffer,
width.get() as usize,
height.get() as usize,
flag,
);
buffer.present().unwrap();
}
}
// Draw something in the window
let mut buffer = surface.buffer_mut().unwrap();
redraw(&mut buffer, width as usize, height as usize, flag);
buffer.present().unwrap();
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
elwt.exit();
}
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
event:
KeyEvent {
state: ElementState::Pressed,
physical_key: PhysicalKey::Code(KeyCode::Space),
..
},
..
},
window_id,
} if window_id == window.id() => {
// Flip the rectangle flag and request a redraw to show the changed image
flag = !flag;
window.request_redraw();
}
_ => {}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Space),
..
},
..
},
window_id,
} if window_id == window.id() => {
// Flip the rectangle flag and request a redraw to show the changed image
flag = !flag;
window.request_redraw();
}
_ => {}
}
});
})
.unwrap();
}

View file

@ -1,11 +1,12 @@
use std::num::NonZeroU32;
use std::rc::Rc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let event_loop = EventLoop::new().unwrap();
let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
#[cfg(target_arch = "wasm32")]
{
@ -17,50 +18,50 @@ fn main() {
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.append_child(&window.canvas().unwrap())
.unwrap();
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
let (width, height) = {
let size = window.inner_size();
(size.width, size.height)
};
match event {
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
} if window_id == window.id() => {
if let (Some(width), Some(height)) = {
let size = window.inner_size();
(NonZeroU32::new(size.width), NonZeroU32::new(size.height))
} {
surface.resize(width, height).unwrap();
surface
.resize(
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
)
.unwrap();
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..height.get() {
for x in 0..width.get() {
let red = x % 255;
let green = y % 255;
let blue = (x * y) % 255;
let index = y as usize * width.get() as usize + x as usize;
buffer[index] = blue | (green << 8) | (red << 16);
}
}
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..height {
for x in 0..width {
let red = x % 255;
let green = y % 255;
let blue = (x * y) % 255;
let index = y as usize * width as usize + x as usize;
buffer[index] = blue | (green << 8) | (red << 16);
buffer.present().unwrap();
}
}
buffer.present().unwrap();
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
elwt.exit();
}
_ => {}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
})
.unwrap();
}

View file

@ -1,4 +1,5 @@
use std::num::NonZeroU32;
use std::rc::Rc;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
@ -7,8 +8,8 @@ const BUFFER_WIDTH: usize = 256;
const BUFFER_HEIGHT: usize = 128;
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
let event_loop = EventLoop::new().unwrap();
let window = Rc::new(WindowBuilder::new().build(&event_loop).unwrap());
#[cfg(target_arch = "wasm32")]
{
@ -20,45 +21,50 @@ fn main() {
.unwrap()
.body()
.unwrap()
.append_child(&window.canvas())
.append_child(&window.canvas().unwrap())
.unwrap();
}
let context = unsafe { softbuffer::Context::new(&window) }.unwrap();
let mut surface = unsafe { softbuffer::Surface::new(&context, &window) }.unwrap();
let context = softbuffer::Context::new(window.clone()).unwrap();
let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop
.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::RedrawRequested(window_id) if window_id == window.id() => {
surface
.resize(
NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(),
NonZeroU32::new(BUFFER_HEIGHT as u32).unwrap(),
)
.unwrap();
match event {
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
} if window_id == window.id() => {
surface
.resize(
NonZeroU32::new(BUFFER_WIDTH as u32).unwrap(),
NonZeroU32::new(BUFFER_HEIGHT as u32).unwrap(),
)
.unwrap();
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..BUFFER_HEIGHT {
for x in 0..BUFFER_WIDTH {
let red = x as u32 % 255;
let green = y as u32 % 255;
let blue = (x as u32 * y as u32) % 255;
let mut buffer = surface.buffer_mut().unwrap();
for y in 0..BUFFER_HEIGHT {
for x in 0..BUFFER_WIDTH {
let red = x as u32 % 255;
let green = y as u32 % 255;
let blue = (x as u32 * y as u32) % 255;
let color = blue | (green << 8) | (red << 16);
buffer[y * BUFFER_WIDTH + x] = color;
let color = blue | (green << 8) | (red << 16);
buffer[y * BUFFER_WIDTH + x] = color;
}
}
buffer.present().unwrap();
}
buffer.present().unwrap();
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
elwt.exit();
}
_ => {}
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => {
*control_flow = ControlFlow::Exit;
}
_ => {}
}
});
})
.unwrap();
}

View file

@ -1,3 +1,4 @@
use crate::error::InitError;
use crate::{Rect, SoftBufferError};
use core_graphics::base::{
kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault,
@ -5,13 +6,14 @@ use core_graphics::base::{
use core_graphics::color_space::CGColorSpace;
use core_graphics::data_provider::CGDataProvider;
use core_graphics::image::CGImage;
use raw_window_handle::AppKitWindowHandle;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow};
use cocoa::base::{id, nil};
use cocoa::quartzcore::{transaction, CALayer, ContentsGravity};
use foreign_types::ForeignType;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::sync::Arc;
@ -23,18 +25,24 @@ impl AsRef<[u8]> for Buffer {
}
}
pub struct CGImpl {
pub struct CGImpl<D, W> {
layer: CALayer,
window: id,
color_space: CGColorSpace,
size: Option<(NonZeroU32, NonZeroU32)>,
_window_source: W,
_display: PhantomData<D>,
}
impl CGImpl {
pub unsafe fn new(handle: AppKitWindowHandle) -> Result<Self, SoftBufferError> {
let window = handle.ns_window as id;
let window: id = msg_send![window, retain];
let view = handle.ns_view as id;
impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
pub(crate) fn new(window_src: W) -> Result<Self, InitError<W>> {
let raw = window_src.window_handle()?.as_raw();
let handle = match raw {
RawWindowHandle::AppKit(handle) => handle,
_ => return Err(InitError::Unsupported(window_src)),
};
let view = handle.ns_view.as_ptr() as id;
let window = unsafe { msg_send![view, window] };
let layer = CALayer::new();
unsafe {
let subview: id = NSView::alloc(nil).initWithFrame_(NSView::frame(view));
@ -52,6 +60,8 @@ impl CGImpl {
window,
color_space,
size: None,
_display: PhantomData,
_window_source: window_src,
})
}
@ -60,10 +70,11 @@ impl CGImpl {
Ok(())
}
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
let (width, height) = self
.size
.expect("Must set size of surface before calling `buffer_mut()`");
Ok(BufferImpl {
buffer: vec![0; width.get() as usize * height.get() as usize],
imp: self,
@ -76,12 +87,12 @@ impl CGImpl {
}
}
pub struct BufferImpl<'a> {
imp: &'a mut CGImpl,
pub struct BufferImpl<'a, D, W> {
imp: &'a mut CGImpl<D, W>,
buffer: Vec<u32>,
}
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
&self.buffer
@ -135,7 +146,7 @@ impl<'a> BufferImpl<'a> {
}
}
impl Drop for CGImpl {
impl<D, W> Drop for CGImpl<D, W> {
fn drop(&mut self) {
unsafe {
let _: () = msg_send![self.window, release];

View file

@ -1,4 +1,4 @@
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use raw_window_handle::{HandleError, RawDisplayHandle, RawWindowHandle};
use std::error::Error;
use std::fmt;
use std::num::NonZeroU32;
@ -7,6 +7,11 @@ use std::num::NonZeroU32;
#[non_exhaustive]
/// A sum type of all of the errors that can occur during the operation of this crate.
pub enum SoftBufferError {
/// A [`raw-window-handle`] error occurred.
///
/// [`raw-window-handle`]: raw_window_handle
RawWindowHandle(HandleError),
/// The [`RawDisplayHandle`] passed into [`Context::new`] is not supported by this crate.
///
/// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle
@ -102,6 +107,7 @@ pub enum SoftBufferError {
impl fmt::Display for SoftBufferError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::RawWindowHandle(err) => fmt::Display::fmt(err, f),
Self::UnsupportedDisplayPlatform {
human_readable_display_platform_name,
display_handle,
@ -137,7 +143,42 @@ impl fmt::Display for SoftBufferError {
}
}
impl std::error::Error for SoftBufferError {}
impl std::error::Error for SoftBufferError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::RawWindowHandle(err) => Some(err),
Self::PlatformError(_, err) => err.as_deref(),
_ => None,
}
}
}
impl From<HandleError> for SoftBufferError {
fn from(err: HandleError) -> Self {
Self::RawWindowHandle(err)
}
}
/// Simple unit error type used to bubble up rejected platforms.
pub(crate) enum InitError<D> {
/// Failed to initialize.
Failure(SoftBufferError),
/// Cannot initialize this handle on this platform.
Unsupported(D),
}
impl<T> From<SoftBufferError> for InitError<T> {
fn from(err: SoftBufferError) -> Self {
Self::Failure(err)
}
}
impl<T> From<HandleError> for InitError<T> {
fn from(err: HandleError) -> Self {
Self::Failure(err.into())
}
}
/// Convenient wrapper to cast errors into SoftBufferError.
pub(crate) trait SwResultExt<T> {

View file

@ -9,54 +9,59 @@ use drm::control::{
};
use drm::Device;
use raw_window_handle::{DrmDisplayHandle, DrmWindowHandle};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use std::collections::HashSet;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::os::unix::io::{AsFd, BorrowedFd};
use std::rc::Rc;
use crate::error::{SoftBufferError, SwResultExt};
use crate::error::{InitError, SoftBufferError, SwResultExt};
#[derive(Debug)]
pub(crate) struct KmsDisplayImpl {
pub(crate) struct KmsDisplayImpl<D: ?Sized> {
/// The underlying raw device file descriptor.
///
/// Once rwh v0.6 support is merged, this an be made safe. Until then,
/// we use this hacky workaround, since this FD's validity is guaranteed by
/// the unsafe constructor.
fd: BorrowedFd<'static>,
/// Holds a reference to the display.
_display: D,
}
impl AsFd for KmsDisplayImpl {
impl<D: ?Sized> AsFd for KmsDisplayImpl<D> {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd
}
}
impl Device for KmsDisplayImpl {}
impl CtrlDevice for KmsDisplayImpl {}
impl<D: ?Sized> Device for KmsDisplayImpl<D> {}
impl<D: ?Sized> CtrlDevice for KmsDisplayImpl<D> {}
impl KmsDisplayImpl {
/// SAFETY: The underlying fd must not outlive the display.
pub(crate) unsafe fn new(handle: DrmDisplayHandle) -> Result<KmsDisplayImpl, SoftBufferError> {
let fd = handle.fd;
impl<D: HasDisplayHandle> KmsDisplayImpl<D> {
pub(crate) fn new(display: D) -> Result<Self, InitError<D>> {
let fd = match display.display_handle()?.as_raw() {
RawDisplayHandle::Drm(drm) => drm.fd,
_ => return Err(InitError::Unsupported(display)),
};
if fd == -1 {
return Err(SoftBufferError::IncompleteDisplayHandle);
return Err(SoftBufferError::IncompleteDisplayHandle.into());
}
// SAFETY: Invariants guaranteed by the user.
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
Ok(KmsDisplayImpl { fd })
Ok(KmsDisplayImpl {
fd,
_display: display,
})
}
}
/// All the necessary types for the Drm/Kms backend.
#[derive(Debug)]
pub(crate) struct KmsImpl {
pub(crate) struct KmsImpl<D: ?Sized, W: ?Sized> {
/// The display implementation.
display: Rc<KmsDisplayImpl>,
display: Rc<KmsDisplayImpl<D>>,
/// The connectors to use.
connectors: Vec<connector::Handle>,
@ -66,6 +71,9 @@ pub(crate) struct KmsImpl {
/// The dumb buffer we're using as a buffer.
buffer: Option<Buffers>,
/// Window handle that we are keeping around.
_window: W,
}
#[derive(Debug)]
@ -81,7 +89,7 @@ struct Buffers {
}
/// The buffer implementation.
pub(crate) struct BufferImpl<'a> {
pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> {
/// The mapping of the dump buffer.
mapping: DumbMapping<'a>,
@ -101,13 +109,16 @@ pub(crate) struct BufferImpl<'a> {
size: (NonZeroU32, NonZeroU32),
/// The display implementation.
display: &'a KmsDisplayImpl,
display: &'a KmsDisplayImpl<D>,
/// Age of the front buffer.
front_age: &'a mut u8,
/// Age of the back buffer.
back_age: &'a mut u8,
/// Window reference.
_window: PhantomData<&'a mut W>,
}
/// The combined frame buffer and dumb buffer.
@ -123,22 +134,16 @@ struct SharedBuffer {
age: u8,
}
impl KmsImpl {
impl<D: ?Sized, W: HasWindowHandle> KmsImpl<D, W> {
/// Create a new KMS backend.
///
/// # Safety
///
/// The plane must be valid for the lifetime of the backend.
pub(crate) unsafe fn new(
window_handle: DrmWindowHandle,
display: Rc<KmsDisplayImpl>,
) -> Result<Self, SoftBufferError> {
log::trace!("new: window_handle={:X}", window_handle.plane);
pub(crate) fn new(window: W, display: Rc<KmsDisplayImpl<D>>) -> Result<Self, InitError<W>> {
// Make sure that the window handle is valid.
let plane_handle = match NonZeroU32::new(window_handle.plane) {
Some(handle) => plane::Handle::from(handle),
None => return Err(SoftBufferError::IncompleteWindowHandle),
let plane_handle = match window.window_handle()?.as_raw() {
RawWindowHandle::Drm(drm) => match NonZeroU32::new(drm.plane) {
Some(handle) => plane::Handle::from(handle),
None => return Err(SoftBufferError::IncompleteWindowHandle.into()),
},
_ => return Err(InitError::Unsupported(window)),
};
let plane_info = display
@ -195,6 +200,7 @@ impl KmsImpl {
connectors,
display,
buffer: None,
_window: window,
})
}
@ -232,7 +238,7 @@ impl KmsImpl {
}
/// Get a mutable reference to the buffer.
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
// Map the dumb buffer.
let set = self
.buffer
@ -267,11 +273,12 @@ impl KmsImpl {
zeroes: &set.zeroes,
front_age,
back_age,
_window: PhantomData,
})
}
}
impl Drop for KmsImpl {
impl<D: ?Sized, W: ?Sized> Drop for KmsImpl<D, W> {
fn drop(&mut self) {
// Map the CRTC to the information that was there before.
self.display
@ -286,7 +293,7 @@ impl Drop for KmsImpl {
}
}
impl BufferImpl<'_> {
impl<D: ?Sized, W: ?Sized> BufferImpl<'_, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
// drm-rs doesn't let us have the immutable reference... so just use a bunch of zeroes.
@ -310,7 +317,7 @@ impl BufferImpl<'_> {
.iter()
.map(|&rect| {
let err = || SoftBufferError::DamageOutOfRange { rect };
Ok(ClipRect::new(
Ok::<_, SoftBufferError>(ClipRect::new(
rect.x.try_into().map_err(|_| err())?,
rect.y.try_into().map_err(|_| err())?,
rect.x
@ -375,8 +382,8 @@ impl BufferImpl<'_> {
impl SharedBuffer {
/// Create a new buffer set.
pub(crate) fn new(
display: &KmsDisplayImpl,
pub(crate) fn new<D: ?Sized>(
display: &KmsDisplayImpl<D>,
width: NonZeroU32,
height: NonZeroU32,
) -> Result<Self, SoftBufferError> {

View file

@ -32,39 +32,41 @@ use std::ops;
#[cfg(any(wayland_platform, x11_platform, kms_platform))]
use std::rc::Rc;
use error::InitError;
pub use error::SoftBufferError;
use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
#[cfg(target_arch = "wasm32")]
pub use self::web::SurfaceExtWeb;
/// An instance of this struct contains the platform-specific data that must be managed in order to
/// write to a window on that platform.
pub struct Context {
/// The inner static dispatch object.
context_impl: ContextDispatch,
pub struct Context<D> {
_marker: PhantomData<*mut ()>,
/// The inner static dispatch object.
context_impl: ContextDispatch<D>,
}
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
macro_rules! make_dispatch {
(
<$dgen: ident, $wgen: ident> =>
$(
$(#[$attr:meta])*
$name: ident ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
$name: ident
($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
)*
) => {
enum ContextDispatch {
enum ContextDispatch<$dgen> {
$(
$(#[$attr])*
$name($context_inner),
)*
}
impl ContextDispatch {
impl<D: HasDisplayHandle> ContextDispatch<D> {
fn variant_name(&self) -> &'static str {
match self {
$(
@ -76,14 +78,14 @@ macro_rules! make_dispatch {
}
#[allow(clippy::large_enum_variant)] // it's boxed anyways
enum SurfaceDispatch {
enum SurfaceDispatch<$dgen, $wgen> {
$(
$(#[$attr])*
$name($surface_inner),
)*
}
impl SurfaceDispatch {
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceDispatch<D, W> {
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
match self {
$(
@ -93,7 +95,7 @@ macro_rules! make_dispatch {
}
}
pub fn buffer_mut(&mut self) -> Result<BufferDispatch, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<BufferDispatch<'_, D, W>, SoftBufferError> {
match self {
$(
$(#[$attr])*
@ -112,14 +114,14 @@ macro_rules! make_dispatch {
}
}
enum BufferDispatch<'a> {
enum BufferDispatch<'a, $dgen, $wgen> {
$(
$(#[$attr])*
$name($buffer_inner),
)*
}
impl<'a> BufferDispatch<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferDispatch<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
match self {
@ -173,76 +175,61 @@ macro_rules! make_dispatch {
// XXX empty enum with generic bound is invalid?
make_dispatch! {
<D, W> =>
#[cfg(x11_platform)]
X11(Rc<x11::X11DisplayImpl>, x11::X11Impl, x11::BufferImpl<'a>),
X11(Rc<x11::X11DisplayImpl<D>>, x11::X11Impl<D, W>, x11::BufferImpl<'a, D, W>),
#[cfg(wayland_platform)]
Wayland(Rc<wayland::WaylandDisplayImpl>, wayland::WaylandImpl, wayland::BufferImpl<'a>),
Wayland(Rc<wayland::WaylandDisplayImpl<D>>, wayland::WaylandImpl<D, W>, wayland::BufferImpl<'a, D, W>),
#[cfg(kms_platform)]
Kms(Rc<kms::KmsDisplayImpl>, kms::KmsImpl, kms::BufferImpl<'a>),
Kms(Rc<kms::KmsDisplayImpl<D>>, kms::KmsImpl<D, W>, kms::BufferImpl<'a, D, W>),
#[cfg(target_os = "windows")]
Win32((), win32::Win32Impl, win32::BufferImpl<'a>),
Win32(D, win32::Win32Impl<D, W>, win32::BufferImpl<'a, D, W>),
#[cfg(target_os = "macos")]
CG((), cg::CGImpl, cg::BufferImpl<'a>),
CG(D, cg::CGImpl<D, W>, cg::BufferImpl<'a, D, W>),
#[cfg(target_arch = "wasm32")]
Web(web::WebDisplayImpl, web::WebImpl, web::BufferImpl<'a>),
Web(web::WebDisplayImpl<D>, web::WebImpl<D, W>, web::BufferImpl<'a, D, W>),
#[cfg(target_os = "redox")]
Orbital((), orbital::OrbitalImpl, orbital::BufferImpl<'a>),
Orbital(D, orbital::OrbitalImpl<D, W>, orbital::BufferImpl<'a, D, W>),
}
impl Context {
impl<D: HasDisplayHandle> Context<D> {
/// Creates a new instance of this struct, using the provided display.
///
/// # Safety
///
/// - Ensure that the provided object is valid for the lifetime of the Context
pub unsafe fn new<D: HasRawDisplayHandle>(display: &D) -> Result<Self, SoftBufferError> {
unsafe { Self::from_raw(display.raw_display_handle()) }
}
pub fn new(mut dpy: D) -> Result<Self, SoftBufferError> {
macro_rules! try_init {
($imp:ident, $x:ident => $make_it:expr) => {{
let $x = dpy;
match { $make_it } {
Ok(x) => {
return Ok(Self {
context_impl: ContextDispatch::$imp(x),
_marker: PhantomData,
})
}
Err(InitError::Unsupported(d)) => dpy = d,
Err(InitError::Failure(f)) => return Err(f),
}
}};
}
/// Creates a new instance of this struct, using the provided display handles
///
/// # Safety
///
/// - Ensure that the provided handle is valid for the lifetime of the Context
pub unsafe fn from_raw(raw_display_handle: RawDisplayHandle) -> Result<Self, SoftBufferError> {
let imple: ContextDispatch = match raw_display_handle {
#[cfg(x11_platform)]
RawDisplayHandle::Xlib(xlib_handle) => unsafe {
ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?))
},
#[cfg(x11_platform)]
RawDisplayHandle::Xcb(xcb_handle) => unsafe {
ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xcb(xcb_handle)?))
},
#[cfg(wayland_platform)]
RawDisplayHandle::Wayland(wayland_handle) => unsafe {
ContextDispatch::Wayland(Rc::new(wayland::WaylandDisplayImpl::new(wayland_handle)?))
},
#[cfg(kms_platform)]
RawDisplayHandle::Drm(drm_handle) => unsafe {
ContextDispatch::Kms(Rc::new(kms::KmsDisplayImpl::new(drm_handle)?))
},
#[cfg(target_os = "windows")]
RawDisplayHandle::Windows(_) => ContextDispatch::Win32(()),
#[cfg(target_os = "macos")]
RawDisplayHandle::AppKit(_) => ContextDispatch::CG(()),
#[cfg(target_arch = "wasm32")]
RawDisplayHandle::Web(_) => ContextDispatch::Web(web::WebDisplayImpl::new()?),
#[cfg(target_os = "redox")]
RawDisplayHandle::Orbital(_) => ContextDispatch::Orbital(()),
unimplemented_display_handle => {
return Err(SoftBufferError::UnsupportedDisplayPlatform {
human_readable_display_platform_name: display_handle_type_name(
&unimplemented_display_handle,
),
display_handle: unimplemented_display_handle,
})
}
};
#[cfg(x11_platform)]
try_init!(X11, display => x11::X11DisplayImpl::new(display).map(Rc::new));
#[cfg(wayland_platform)]
try_init!(Wayland, display => wayland::WaylandDisplayImpl::new(display).map(Rc::new));
#[cfg(kms_platform)]
try_init!(Kms, display => kms::KmsDisplayImpl::new(display).map(Rc::new));
#[cfg(target_os = "windows")]
try_init!(Win32, display => Ok(display));
#[cfg(target_os = "macos")]
try_init!(CG, display => Ok(display));
#[cfg(target_arch = "wasm32")]
try_init!(Web, display => web::WebDisplayImpl::new(display));
#[cfg(target_os = "redox")]
try_init!(Orbital, display => Ok(display));
Ok(Self {
context_impl: imple,
_marker: PhantomData,
let raw = dpy.display_handle()?.as_raw();
Err(SoftBufferError::UnsupportedDisplayPlatform {
human_readable_display_platform_name: display_handle_type_name(&raw),
display_handle: raw,
})
}
}
@ -261,87 +248,60 @@ pub struct Rect {
}
/// A surface for drawing to a window with software buffers.
pub struct Surface {
pub struct Surface<D, W> {
/// This is boxed so that `Surface` is the same size on every platform.
surface_impl: Box<SurfaceDispatch>,
surface_impl: Box<SurfaceDispatch<D, W>>,
_marker: PhantomData<*mut ()>,
}
impl Surface {
impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
/// Creates a new surface for the context for the provided window.
///
/// # Safety
///
/// - Ensure that the provided objects are valid to draw a 2D buffer to, and are valid for the
/// lifetime of the Context
pub unsafe fn new<W: HasRawWindowHandle>(
context: &Context,
window: &W,
) -> Result<Self, SoftBufferError> {
unsafe { Self::from_raw(context, window.raw_window_handle()) }
}
pub fn new(context: &Context<D>, window: W) -> Result<Self, SoftBufferError> {
macro_rules! leap {
($e:expr) => {{
match ($e) {
Ok(x) => x,
Err(InitError::Unsupported(window)) => {
let raw = window.window_handle()?.as_raw();
return 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)) => return Err(f),
}
}};
}
/// Creates a new surface for the context for the provided raw window handle.
///
/// # Safety
///
/// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the
/// lifetime of the Context
pub unsafe fn from_raw(
context: &Context,
raw_window_handle: RawWindowHandle,
) -> Result<Self, SoftBufferError> {
let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle) {
let imple = match &context.context_impl {
#[cfg(x11_platform)]
(
ContextDispatch::X11(xcb_display_handle),
RawWindowHandle::Xlib(xlib_window_handle),
) => SurfaceDispatch::X11(unsafe {
x11::X11Impl::from_xlib(xlib_window_handle, xcb_display_handle.clone())?
}),
#[cfg(x11_platform)]
(ContextDispatch::X11(xcb_display_handle), RawWindowHandle::Xcb(xcb_window_handle)) => {
SurfaceDispatch::X11(unsafe {
x11::X11Impl::from_xcb(xcb_window_handle, xcb_display_handle.clone())?
})
ContextDispatch::X11(xcb_display_handle) => {
SurfaceDispatch::X11(leap!(x11::X11Impl::new(window, xcb_display_handle.clone())))
}
#[cfg(wayland_platform)]
(
ContextDispatch::Wayland(wayland_display_impl),
RawWindowHandle::Wayland(wayland_window_handle),
) => SurfaceDispatch::Wayland(unsafe {
wayland::WaylandImpl::new(wayland_window_handle, wayland_display_impl.clone())?
}),
ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!(
wayland::WaylandImpl::new(window, wayland_display_impl.clone())
)),
#[cfg(kms_platform)]
(ContextDispatch::Kms(kms_display_impl), RawWindowHandle::Drm(drm_window_handle)) => {
SurfaceDispatch::Kms(unsafe {
kms::KmsImpl::new(drm_window_handle, kms_display_impl.clone())?
})
ContextDispatch::Kms(kms_display_impl) => {
SurfaceDispatch::Kms(leap!(kms::KmsImpl::new(window, kms_display_impl.clone())))
}
#[cfg(target_os = "windows")]
(ContextDispatch::Win32(()), RawWindowHandle::Win32(win32_handle)) => {
SurfaceDispatch::Win32(unsafe { win32::Win32Impl::new(&win32_handle)? })
ContextDispatch::Win32(_) => {
SurfaceDispatch::Win32(leap!(win32::Win32Impl::new(window)))
}
#[cfg(target_os = "macos")]
(ContextDispatch::CG(()), RawWindowHandle::AppKit(appkit_handle)) => {
SurfaceDispatch::CG(unsafe { cg::CGImpl::new(appkit_handle)? })
}
ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(cg::CGImpl::new(window))),
#[cfg(target_arch = "wasm32")]
(ContextDispatch::Web(context), RawWindowHandle::Web(web_handle)) => {
SurfaceDispatch::Web(web::WebImpl::new(context, web_handle)?)
ContextDispatch::Web(web_display_impl) => {
SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window)))
}
#[cfg(target_os = "redox")]
(ContextDispatch::Orbital(()), RawWindowHandle::Orbital(orbital_handle)) => {
SurfaceDispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?)
}
(unsupported_display_impl, unimplemented_window_handle) => {
return Err(SoftBufferError::UnsupportedWindowPlatform {
human_readable_window_platform_name: window_handle_type_name(
&unimplemented_window_handle,
),
human_readable_display_platform_name: unsupported_display_impl.variant_name(),
window_handle: unimplemented_window_handle,
})
ContextDispatch::Orbital(_) => {
SurfaceDispatch::Orbital(leap!(orbital::OrbitalImpl::new(window)))
}
};
@ -382,7 +342,7 @@ impl Surface {
/// - On DRM/KMS, there is no reliable and sound way to wait for the page flip to happen from within
/// `softbuffer`. Therefore it is the responsibility of the user to wait for the page flip before
/// sending another frame.
pub fn buffer_mut(&mut self) -> Result<Buffer, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<Buffer<'_, D, W>, SoftBufferError> {
Ok(Buffer {
buffer_impl: self.surface_impl.buffer_mut()?,
_marker: PhantomData,
@ -426,12 +386,12 @@ impl Surface {
/// Currently [`Buffer::present`] must block copying image data on:
/// - Web
/// - macOS
pub struct Buffer<'a> {
buffer_impl: BufferDispatch<'a>,
pub struct Buffer<'a, D, W> {
buffer_impl: BufferDispatch<'a, D, W>,
_marker: PhantomData<*mut ()>,
}
impl<'a> Buffer<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> {
/// Is age is the number of frames ago this buffer was last presented. So if the value is
/// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame
/// before that (for backends using double buffering). If the value is `0`, it is a new
@ -474,7 +434,7 @@ impl<'a> Buffer<'a> {
}
}
impl<'a> ops::Deref for Buffer<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::Deref for Buffer<'a, D, W> {
type Target = [u32];
#[inline]
@ -483,13 +443,37 @@ impl<'a> ops::Deref for Buffer<'a> {
}
}
impl<'a> ops::DerefMut for Buffer<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::DerefMut for Buffer<'a, D, W> {
#[inline]
fn deref_mut(&mut self) -> &mut [u32] {
self.buffer_impl.pixels_mut()
}
}
/// There is no display handle.
#[derive(Debug)]
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 {}
}
}
/// There is no window handle.
#[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",

View file

@ -1,5 +1,6 @@
use raw_window_handle::OrbitalWindowHandle;
use std::{cmp, num::NonZeroU32, slice, str};
use crate::error::InitError;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle};
use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str};
use crate::{Rect, SoftBufferError};
@ -53,20 +54,30 @@ impl Drop for OrbitalMap {
}
}
pub struct OrbitalImpl {
pub struct OrbitalImpl<D, W> {
handle: OrbitalWindowHandle,
width: u32,
height: u32,
presented: bool,
_window_source: W,
_display: PhantomData<D>,
}
impl OrbitalImpl {
pub fn new(handle: OrbitalWindowHandle) -> Result<Self, SoftBufferError> {
impl<D: HasDisplayHandle, W: HasWindowHandle> OrbitalImpl<D, W> {
pub(crate) fn new(window: W) -> Result<Self, InitError<W>> {
let raw = window.window_handle()?.as_raw();
let handle = match raw {
RawWindowHandle::Orbital(handle) => handle,
_ => return Err(InitError::Unsupported(window)),
};
Ok(Self {
handle,
width: 0,
height: 0,
presented: false,
_window_source: window,
_display: PhantomData,
})
}
@ -82,7 +93,7 @@ impl OrbitalImpl {
}
fn window_fd(&self) -> usize {
self.handle.window as usize
self.handle.window.as_ptr() as usize
}
// Read the current width and size
@ -105,7 +116,7 @@ impl OrbitalImpl {
(window_width, window_height)
}
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
let (window_width, window_height) = self.window_size();
let pixels = if self.width as usize == window_width && self.height as usize == window_height
{
@ -162,12 +173,12 @@ enum Pixels {
Buffer(Vec<u32>),
}
pub struct BufferImpl<'a> {
imp: &'a mut OrbitalImpl,
pub struct BufferImpl<'a, D, W> {
imp: &'a mut OrbitalImpl<D, W>,
pixels: Pixels,
}
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
match &self.pixels {

View file

@ -13,13 +13,13 @@ use crate::SoftBufferError;
///
/// This should be consistent with stacked borrow rules, and miri seems to
/// accept it at least in simple cases.
pub struct BorrowStack<'a, T: 'static + ?Sized, U: 'static + ?Sized> {
pub struct BorrowStack<'a, T: 'a + ?Sized, U: 'a + ?Sized> {
container: *mut T,
member: *mut U,
_phantom: std::marker::PhantomData<&'a mut T>,
}
impl<'a, T: 'static + ?Sized, U: 'static + ?Sized> BorrowStack<'a, T, U> {
impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> {
pub fn new<F>(container: &'a mut T, f: F) -> Result<Self, SoftBufferError>
where
F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>,

View file

@ -1,5 +1,8 @@
use crate::{error::SwResultExt, util, Rect, SoftBufferError};
use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};
use crate::{
error::{InitError, SwResultExt},
util, Rect, SoftBufferError,
};
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use std::{
cell::RefCell,
num::{NonZeroI32, NonZeroU32},
@ -17,17 +20,31 @@ use buffer::WaylandBuffer;
struct State;
pub struct WaylandDisplayImpl {
conn: Connection,
pub struct WaylandDisplayImpl<D: ?Sized> {
conn: Option<Connection>,
event_queue: RefCell<EventQueue<State>>,
qh: QueueHandle<State>,
shm: wl_shm::WlShm,
/// The object that owns the display handle.
///
/// This has to be dropped *after* the `conn` field, because the `conn` field implicitly borrows
/// this.
_display: D,
}
impl WaylandDisplayImpl {
pub unsafe fn new(display_handle: WaylandDisplayHandle) -> Result<Self, SoftBufferError> {
// SAFETY: Ensured by user
let backend = unsafe { Backend::from_foreign_display(display_handle.display as *mut _) };
impl<D: HasDisplayHandle + ?Sized> WaylandDisplayImpl<D> {
pub(crate) fn new(display: D) -> Result<Self, InitError<D>>
where
D: Sized,
{
let raw = display.display_handle()?.as_raw();
let wayland_handle = match raw {
RawDisplayHandle::Wayland(w) => w.display,
_ => return Err(InitError::Unsupported(display)),
};
let backend = unsafe { Backend::from_foreign_display(wayland_handle.as_ptr().cast()) };
let conn = Connection::from_backend(backend);
let (globals, event_queue) =
registry_queue_init(&conn).swbuf_err("Failed to make round trip to server")?;
@ -36,41 +53,63 @@ impl WaylandDisplayImpl {
.bind(&qh, 1..=1, ())
.swbuf_err("Failed to instantiate Wayland Shm")?;
Ok(Self {
conn,
conn: Some(conn),
event_queue: RefCell::new(event_queue),
qh,
shm,
_display: display,
})
}
fn conn(&self) -> &Connection {
self.conn.as_ref().unwrap()
}
}
pub struct WaylandImpl {
display: Rc<WaylandDisplayImpl>,
surface: wl_surface::WlSurface,
buffers: Option<(WaylandBuffer, WaylandBuffer)>,
size: Option<(NonZeroI32, NonZeroI32)>,
impl<D: ?Sized> Drop for WaylandDisplayImpl<D> {
fn drop(&mut self) {
// Make sure the connection is dropped first.
self.conn = None;
}
}
impl WaylandImpl {
pub unsafe fn new(
window_handle: WaylandWindowHandle,
display: Rc<WaylandDisplayImpl>,
) -> Result<Self, SoftBufferError> {
// SAFETY: Ensured by user
pub struct WaylandImpl<D: ?Sized, W: ?Sized> {
display: Rc<WaylandDisplayImpl<D>>,
surface: Option<wl_surface::WlSurface>,
buffers: Option<(WaylandBuffer, WaylandBuffer)>,
size: Option<(NonZeroI32, NonZeroI32)>,
/// The pointer to the window object.
///
/// This has to be dropped *after* the `surface` field, because the `surface` field implicitly
/// borrows this.
_window: W,
}
impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> WaylandImpl<D, W> {
pub(crate) fn new(window: W, display: Rc<WaylandDisplayImpl<D>>) -> Result<Self, InitError<W>> {
// Get the raw Wayland window.
let raw = window.window_handle()?.as_raw();
let wayland_handle = match raw {
RawWindowHandle::Wayland(w) => w.surface,
_ => return Err(InitError::Unsupported(window)),
};
let surface_id = unsafe {
ObjectId::from_ptr(
wl_surface::WlSurface::interface(),
window_handle.surface as _,
wayland_handle.as_ptr().cast(),
)
}
.swbuf_err("Failed to create proxy for surface ID.")?;
let surface = wl_surface::WlSurface::from_id(&display.conn, surface_id)
let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id)
.swbuf_err("Failed to create proxy for surface ID.")?;
Ok(Self {
display,
surface,
surface: Some(surface),
buffers: Default::default(),
size: None,
_window: window,
})
}
@ -86,7 +125,7 @@ impl WaylandImpl {
Ok(())
}
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
let (width, height) = self
.size
.expect("Must set size of surface before calling `buffer_mut()`");
@ -155,13 +194,13 @@ impl WaylandImpl {
// Swap front and back buffer
std::mem::swap(front, back);
front.attach(&self.surface);
front.attach(self.surface.as_ref().unwrap());
// Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if
// the compositor doesn't support `damage_buffer`.
// https://bugs.freedesktop.org/show_bug.cgi?id=78190
if self.surface.version() < 4 {
self.surface.damage(0, 0, i32::MAX, i32::MAX);
if self.surface().version() < 4 {
self.surface().damage(0, 0, i32::MAX, i32::MAX);
} else {
for rect in damage {
// Introduced in version 4, it is an error to use this request in version 3 or lower.
@ -174,25 +213,36 @@ impl WaylandImpl {
))
})()
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
self.surface.damage_buffer(x, y, width, height);
self.surface().damage_buffer(x, y, width, height);
}
}
self.surface.commit();
self.surface().commit();
}
let _ = self.display.event_queue.borrow_mut().flush();
Ok(())
}
fn surface(&self) -> &wl_surface::WlSurface {
self.surface.as_ref().unwrap()
}
}
pub struct BufferImpl<'a> {
stack: util::BorrowStack<'a, WaylandImpl, [u32]>,
impl<D: ?Sized, W: ?Sized> Drop for WaylandImpl<D, W> {
fn drop(&mut self) {
// Make sure the surface is dropped first.
self.surface = None;
}
}
pub struct BufferImpl<'a, D: ?Sized, W> {
stack: util::BorrowStack<'a, WaylandImpl<D, W>, [u32]>,
age: u8,
}
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
self.stack.member()

View file

@ -2,39 +2,48 @@
#![allow(clippy::uninlined_format_args)]
use std::convert::TryInto;
use std::marker::PhantomData;
use std::num::NonZeroU32;
use js_sys::Object;
use raw_window_handle::WebWindowHandle;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
use wasm_bindgen::{JsCast, JsValue};
use web_sys::ImageData;
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
use crate::error::SwResultExt;
use crate::{util, Rect, SoftBufferError};
use crate::error::{InitError, SwResultExt};
use crate::{util, NoDisplayHandle, NoWindowHandle, Rect, SoftBufferError};
use std::convert::TryInto;
use std::marker::PhantomData;
use std::num::NonZeroU32;
/// Display implementation for the web platform.
///
/// This just caches the document to prevent having to query it every time.
pub struct WebDisplayImpl {
pub struct WebDisplayImpl<D> {
document: web_sys::Document,
_display: D,
}
impl WebDisplayImpl {
pub(super) fn new() -> Result<Self, SoftBufferError> {
impl<D: HasDisplayHandle> WebDisplayImpl<D> {
pub(super) fn new(display: D) -> Result<Self, InitError<D>> {
let raw = display.display_handle()?.as_raw();
match raw {
RawDisplayHandle::Web(..) => {}
_ => return Err(InitError::Unsupported(display)),
}
let document = web_sys::window()
.swbuf_err("`Window` is not present in this runtime")?
.document()
.swbuf_err("`Document` is not present in this runtime")?;
Ok(Self { document })
Ok(Self {
document,
_display: display,
})
}
}
pub struct WebImpl {
pub struct WebImpl<D, W> {
/// The handle and context to the canvas that we're drawing to.
canvas: Canvas,
@ -46,6 +55,12 @@ pub struct WebImpl {
/// The current canvas width/height.
size: Option<(NonZeroU32, NonZeroU32)>,
/// The underlying window handle.
_window: W,
/// The underlying display handle.
_display: PhantomData<D>,
}
/// Holding canvas and context for [`HtmlCanvasElement`] or [`OffscreenCanvas`],
@ -61,8 +76,13 @@ enum Canvas {
},
}
impl WebImpl {
pub fn new(display: &WebDisplayImpl, handle: WebWindowHandle) -> Result<Self, SoftBufferError> {
impl<D: HasDisplayHandle, W: HasWindowHandle> WebImpl<D, W> {
pub(crate) fn new(display: &WebDisplayImpl<D>, window: W) -> Result<Self, InitError<W>> {
let raw = window.window_handle()?.as_raw();
let handle = match raw {
RawWindowHandle::Web(handle) => handle,
_ => return Err(InitError::Unsupported(window)),
};
let canvas: HtmlCanvasElement = display
.document
.query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id))
@ -72,10 +92,10 @@ impl WebImpl {
// We already made sure this was a canvas in `querySelector`.
.unchecked_into();
Self::from_canvas(canvas)
Self::from_canvas(canvas, window).map_err(InitError::Failure)
}
fn from_canvas(canvas: HtmlCanvasElement) -> Result<Self, SoftBufferError> {
fn from_canvas(canvas: HtmlCanvasElement, window: W) -> Result<Self, SoftBufferError> {
let ctx = Self::resolve_ctx(canvas.get_context("2d").ok(), "CanvasRenderingContext2d")?;
Ok(Self {
@ -83,10 +103,12 @@ impl WebImpl {
buffer: Vec::new(),
buffer_presented: false,
size: None,
_window: window,
_display: PhantomData,
})
}
fn from_offscreen_canvas(canvas: OffscreenCanvas) -> Result<Self, SoftBufferError> {
fn from_offscreen_canvas(canvas: OffscreenCanvas, window: W) -> Result<Self, SoftBufferError> {
let ctx = Self::resolve_ctx(
canvas.get_context("2d").ok(),
"OffscreenCanvasRenderingContext2d",
@ -97,6 +119,8 @@ impl WebImpl {
buffer: Vec::new(),
buffer_presented: false,
size: None,
_window: window,
_display: PhantomData,
})
}
@ -134,7 +158,7 @@ impl WebImpl {
}
/// Get a pointer to the mutable buffer.
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
Ok(BufferImpl { imp: self })
}
@ -258,9 +282,9 @@ pub trait SurfaceExtWeb: Sized {
fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result<Self, SoftBufferError>;
}
impl SurfaceExtWeb for crate::Surface {
impl SurfaceExtWeb for crate::Surface<NoDisplayHandle, NoWindowHandle> {
fn from_canvas(canvas: HtmlCanvasElement) -> Result<Self, SoftBufferError> {
let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas)?);
let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas, NoWindowHandle(()))?);
Ok(Self {
surface_impl: Box::new(imple),
@ -269,7 +293,10 @@ impl SurfaceExtWeb for crate::Surface {
}
fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result<Self, SoftBufferError> {
let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas(offscreen_canvas)?);
let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas(
offscreen_canvas,
NoWindowHandle(()),
)?);
Ok(Self {
surface_impl: Box::new(imple),
@ -326,11 +353,11 @@ impl Canvas {
}
}
pub struct BufferImpl<'a> {
imp: &'a mut WebImpl,
pub struct BufferImpl<'a, D, W> {
imp: &'a mut WebImpl<D, W>,
}
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
pub fn pixels(&self) -> &[u32] {
&self.imp.buffer
}

View file

@ -3,9 +3,10 @@
//! This module converts the input buffer into a bitmap and then stretches it to the window.
use crate::{Rect, SoftBufferError};
use raw_window_handle::Win32WindowHandle;
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
use std::io;
use std::marker::PhantomData;
use std::mem;
use std::num::{NonZeroI32, NonZeroU32};
use std::ptr::{self, NonNull};
@ -128,7 +129,7 @@ impl Buffer {
}
/// The handle to a window for software buffering.
pub struct Win32Impl {
pub struct Win32Impl<D: ?Sized, W> {
/// The window handle.
window: HWND,
@ -137,6 +138,16 @@ pub struct Win32Impl {
/// The buffer used to hold the image.
buffer: Option<Buffer>,
/// The handle for the window.
///
/// This should be kept alive in order to keep `window` valid.
_window: W,
/// The display handle.
///
/// We don't use this, but other code might.
_display: PhantomData<D>,
}
/// The Win32-compatible bitmap information.
@ -146,21 +157,18 @@ struct BitmapInfo {
bmi_colors: [Gdi::RGBQUAD; 3],
}
impl Win32Impl {
impl<D: HasDisplayHandle, W: HasWindowHandle> Win32Impl<D, W> {
/// Create a new `Win32Impl` from a `Win32WindowHandle`.
///
/// # Safety
///
/// The `Win32WindowHandle` must be a valid window handle.
pub unsafe fn new(handle: &Win32WindowHandle) -> Result<Self, crate::SoftBufferError> {
// It is valid for the window handle to be null here. Error out if it is.
if handle.hwnd.is_null() {
return Err(SoftBufferError::IncompleteWindowHandle);
}
pub(crate) fn new(window: W) -> Result<Self, crate::error::InitError<W>> {
let raw = window.window_handle()?.as_raw();
let handle = match raw {
RawWindowHandle::Win32(handle) => handle,
_ => return Err(crate::InitError::Unsupported(window)),
};
// Get the handle to the device context.
// SAFETY: We have confirmed that the window handle is valid.
let hwnd = handle.hwnd as HWND;
let hwnd = handle.hwnd.get() as HWND;
let dc = unsafe { Gdi::GetDC(hwnd) };
// GetDC returns null if there is a platform error.
@ -168,13 +176,16 @@ impl Win32Impl {
return Err(SoftBufferError::PlatformError(
Some("Device Context is null".into()),
Some(Box::new(io::Error::last_os_error())),
));
)
.into());
}
Ok(Self {
dc,
window: hwnd,
buffer: None,
_window: window,
_display: PhantomData,
})
}
@ -197,7 +208,7 @@ impl Win32Impl {
Ok(())
}
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
if self.buffer.is_none() {
panic!("Must set size of surface before calling `buffer_mut()`");
}
@ -235,9 +246,9 @@ impl Win32Impl {
}
}
pub struct BufferImpl<'a>(&'a mut Win32Impl);
pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl<D, W>);
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
self.0.buffer.as_ref().unwrap().pixels()

View file

@ -5,10 +5,14 @@
#![allow(clippy::uninlined_format_args)]
use crate::error::SwResultExt;
use crate::error::{InitError, SwResultExt};
use crate::{Rect, SoftBufferError};
use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle};
use raw_window_handle::{
HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle, XcbDisplayHandle,
XcbWindowHandle,
};
use rustix::{fd, mm, shm as posix_shm};
use std::{
fmt,
fs::File,
@ -27,57 +31,62 @@ use x11rb::protocol::shm::{self, ConnectionExt as _};
use x11rb::protocol::xproto::{self, ConnectionExt as _};
use x11rb::xcb_ffi::XCBConnection;
pub struct X11DisplayImpl {
pub struct X11DisplayImpl<D: ?Sized> {
/// The handle to the XCB connection.
connection: XCBConnection,
connection: Option<XCBConnection>,
/// SHM extension is available.
is_shm_available: bool,
/// The generic display where the `connection` field comes from.
///
/// Without `&mut`, the underlying connection cannot be closed without other unsafe behavior.
/// With `&mut`, the connection can be dropped without us knowing about it. Therefore, we
/// cannot provide `&mut` access to this field.
_display: D,
}
impl X11DisplayImpl {
pub(crate) unsafe fn from_xlib(
display_handle: XlibDisplayHandle,
) -> Result<X11DisplayImpl, SoftBufferError> {
// Validate the display handle to ensure we can use it.
if display_handle.display.is_null() {
return Err(SoftBufferError::IncompleteDisplayHandle);
}
impl<D: HasDisplayHandle + ?Sized> X11DisplayImpl<D> {
/// Create a new `X11DisplayImpl`.
pub(crate) fn new(display: D) -> Result<Self, InitError<D>>
where
D: Sized,
{
// Get the underlying libxcb handle.
let raw = display.display_handle()?.as_raw();
let xcb_handle = match raw {
RawDisplayHandle::Xcb(xcb_handle) => xcb_handle,
RawDisplayHandle::Xlib(xlib) => {
// Convert to an XCB handle.
let display = match xlib.display {
Some(display) => display,
None => return Err(SoftBufferError::IncompleteDisplayHandle.into()),
};
// Get the underlying XCB connection.
// SAFETY: The user has asserted that the display handle is valid.
let connection = unsafe {
let display = tiny_xlib::Display::from_ptr(display_handle.display);
display.as_raw_xcb_connection()
// Get the underlying XCB connection.
// SAFETY: The user has asserted that the display handle is valid.
let connection = unsafe {
let display = tiny_xlib::Display::from_ptr(display.as_ptr());
NonNull::new_unchecked(display.as_raw_xcb_connection())
};
// Construct the equivalent XCB display and window handles.
XcbDisplayHandle::new(Some(connection.cast()), xlib.screen)
}
_ => return Err(InitError::Unsupported(display)),
};
// Construct the equivalent XCB display and window handles.
let mut xcb_display_handle = XcbDisplayHandle::empty();
xcb_display_handle.connection = connection.cast();
xcb_display_handle.screen = display_handle.screen;
// SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles.
unsafe { Self::from_xcb(xcb_display_handle) }
}
/// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`.
///
/// # Safety
///
/// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid.
pub(crate) unsafe fn from_xcb(
display_handle: XcbDisplayHandle,
) -> Result<Self, SoftBufferError> {
// Check that the handle is valid.
if display_handle.connection.is_null() {
return Err(SoftBufferError::IncompleteDisplayHandle);
}
// Validate the display handle to ensure we can use it.
let connection = match xcb_handle.connection {
Some(conn) => conn,
None => return Err(SoftBufferError::IncompleteDisplayHandle.into()),
};
// Wrap the display handle in an x11rb connection.
// SAFETY: We don't own the connection, so don't drop it. We also assert that the connection is valid.
let connection = {
let result =
unsafe { XCBConnection::from_raw_xcb_connection(display_handle.connection, false) };
unsafe { XCBConnection::from_raw_xcb_connection(connection.as_ptr(), false) };
result.swbuf_err("Failed to wrap XCB connection")?
};
@ -88,16 +97,25 @@ impl X11DisplayImpl {
}
Ok(Self {
connection,
connection: Some(connection),
is_shm_available,
_display: display,
})
}
}
impl<D: ?Sized> X11DisplayImpl<D> {
fn connection(&self) -> &XCBConnection {
self.connection
.as_ref()
.expect("X11DisplayImpl::connection() called after X11DisplayImpl::drop()")
}
}
/// The handle to an X11 drawing context.
pub struct X11Impl {
pub struct X11Impl<D: ?Sized, W: ?Sized> {
/// X display this window belongs to.
display: Rc<X11DisplayImpl>,
display: Rc<X11DisplayImpl<D>>,
/// The window to draw to.
window: xproto::Window,
@ -119,6 +137,9 @@ pub struct X11Impl {
/// The current buffer width/height.
size: Option<(NonZeroU16, NonZeroU16)>,
/// Keep the window alive.
_window_handle: W,
}
/// The buffer that is being drawn to.
@ -149,53 +170,41 @@ struct ShmBuffer {
done_processing: Option<SequenceNumber>,
}
impl X11Impl {
/// Create a new `X11Impl` from a `XlibWindowHandle` and `XlibDisplayHandle`.
///
/// # Safety
///
/// The `XlibWindowHandle` and `XlibDisplayHandle` must be valid.
pub unsafe fn from_xlib(
window_handle: XlibWindowHandle,
display: Rc<X11DisplayImpl>,
) -> Result<Self, SoftBufferError> {
let mut xcb_window_handle = XcbWindowHandle::empty();
xcb_window_handle.window = window_handle.window as _;
xcb_window_handle.visual_id = window_handle.visual_id as _;
impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> X11Impl<D, W> {
/// Create a new `X11Impl` from a `HasWindowHandle`.
pub(crate) fn new(window_src: W, display: Rc<X11DisplayImpl<D>>) -> Result<Self, InitError<W>> {
// Get the underlying raw window handle.
let raw = window_src.window_handle()?.as_raw();
let window_handle = match raw {
RawWindowHandle::Xcb(xcb) => xcb,
RawWindowHandle::Xlib(xlib) => {
let window = match NonZeroU32::new(xlib.window as u32) {
Some(window) => window,
None => return Err(SoftBufferError::IncompleteWindowHandle.into()),
};
let mut xcb_window_handle = XcbWindowHandle::new(window);
xcb_window_handle.visual_id = NonZeroU32::new(xlib.visual_id as u32);
xcb_window_handle
}
_ => {
return Err(InitError::Unsupported(window_src));
}
};
// SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles.
unsafe { Self::from_xcb(xcb_window_handle, display) }
}
/// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`.
///
/// # Safety
///
/// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid.
pub(crate) unsafe fn from_xcb(
window_handle: XcbWindowHandle,
display: Rc<X11DisplayImpl>,
) -> Result<Self, SoftBufferError> {
log::trace!("new: window_handle={:X}", window_handle.window,);
// Check that the handle is valid.
if window_handle.window == 0 {
return Err(SoftBufferError::IncompleteWindowHandle);
}
let window = window_handle.window;
log::trace!("new: window_handle={:X}", window_handle.window);
let window = window_handle.window.get();
// Run in parallel: start getting the window depth and (if necessary) visual.
let display2 = display.clone();
let tokens = {
let geometry_token = display2
.connection
.connection()
.get_geometry(window)
.swbuf_err("Failed to send geometry request")?;
let window_attrs_token = if window_handle.visual_id == 0 {
let window_attrs_token = if window_handle.visual_id.is_none() {
Some(
display2
.connection
.connection()
.get_window_attributes(window)
.swbuf_err("Failed to send window attributes request")?,
)
@ -208,11 +217,11 @@ impl X11Impl {
// Create a new graphics context to draw to.
let gc = display
.connection
.connection()
.generate_id()
.swbuf_err("Failed to generate GC ID")?;
display
.connection
.connection()
.create_gc(
gc,
window,
@ -229,7 +238,7 @@ impl X11Impl {
.reply()
.swbuf_err("Failed to get geometry reply")?;
let visual_id = match window_attrs_token {
None => window_handle.visual_id,
None => window_handle.visual_id.unwrap().get(),
Some(window_attrs) => {
window_attrs
.reply()
@ -262,6 +271,7 @@ impl X11Impl {
buffer,
buffer_presented: false,
size: None,
_window_handle: window_src,
})
}
@ -290,7 +300,7 @@ impl X11Impl {
if self.size != Some((width, height)) {
self.buffer_presented = false;
self.buffer
.resize(&self.display.connection, width.get(), height.get())
.resize(self.display.connection(), width.get(), height.get())
.swbuf_err("Failed to resize X11 buffer")?;
// We successfully resized the buffer.
@ -301,11 +311,11 @@ impl X11Impl {
}
/// Get a mutable reference to the buffer.
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
log::trace!("buffer_mut: window={:X}", self.window);
// Finish waiting on the previous `shm::PutImage` request, if any.
self.buffer.finish_wait(&self.display.connection)?;
self.buffer.finish_wait(self.display.connection())?;
// We can now safely call `buffer_mut` on the buffer.
Ok(BufferImpl(self))
@ -322,7 +332,7 @@ impl X11Impl {
// TODO: Is it worth it to do SHM here? Probably not.
let reply = self
.display
.connection
.connection()
.get_image(
xproto::ImageFormat::Z_PIXMAP,
self.window,
@ -349,9 +359,9 @@ impl X11Impl {
}
}
pub struct BufferImpl<'a>(&'a mut X11Impl);
pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl<D, W>);
impl<'a> BufferImpl<'a> {
impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<'a, D, W> {
#[inline]
pub fn pixels(&self) -> &[u32] {
// SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`.
@ -388,7 +398,7 @@ impl<'a> BufferImpl<'a> {
log::debug!("Falling back to non-SHM method for window drawing.");
imp.display
.connection
.connection()
.put_image(
xproto::ImageFormat::Z_PIXMAP,
imp.window,
@ -427,7 +437,7 @@ impl<'a> BufferImpl<'a> {
)
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
imp.display
.connection
.connection()
.shm_put_image(
imp.window,
imp.gc,
@ -451,7 +461,7 @@ impl<'a> BufferImpl<'a> {
})
.and_then(|()| {
// Send a short request to act as a notification for when the X server is done processing the image.
shm.begin_wait(&imp.display.connection)
shm.begin_wait(imp.display.connection())
.swbuf_err("Failed to draw image to window")
})?;
}
@ -743,15 +753,22 @@ impl Drop for ShmSegment {
}
}
impl Drop for X11Impl {
impl<D: ?Sized> Drop for X11DisplayImpl<D> {
fn drop(&mut self) {
// Make sure that the x11rb connection is dropped before its source is.
self.connection = None;
}
}
impl<D: ?Sized, W: ?Sized> Drop for X11Impl<D, W> {
fn drop(&mut self) {
// If we used SHM, make sure it's detached from the server.
if let Buffer::Shm(mut shm) = mem::replace(&mut self.buffer, Buffer::Wire(Vec::new())) {
// If we were in the middle of processing a buffer, wait for it to finish.
shm.finish_wait(&self.display.connection).ok();
shm.finish_wait(self.display.connection()).ok();
if let Some((segment, seg_id)) = shm.seg.take() {
if let Ok(token) = self.display.connection.shm_detach(seg_id) {
if let Ok(token) = self.display.connection().shm_detach(seg_id) {
token.ignore_error();
}
@ -761,7 +778,7 @@ impl Drop for X11Impl {
}
// Close the graphics context that we created.
if let Ok(token) = self.display.connection.free_gc(self.gc) {
if let Ok(token) = self.display.connection().free_gc(self.gc) {
token.ignore_error();
}
}

View file

@ -1,3 +1,5 @@
// TODO: Once winit is updated again, restore this test.
/*
use softbuffer::{Context, Surface};
use std::num::NonZeroU32;
use winit::event_loop::EventLoopWindowTarget;
@ -26,8 +28,8 @@ fn all_red(elwt: &EventLoopWindowTarget<()>) {
#[cfg(not(target_arch = "wasm32"))]
std::thread::sleep(std::time::Duration::from_millis(1));
let context = unsafe { Context::new(elwt) }.unwrap();
let mut surface = unsafe { Surface::new(&context, &window) }.unwrap();
let context = Context::new(elwt).unwrap();
let mut surface = Surface::new(&context, &window).unwrap();
let size = window.inner_size();
// Set the size of the surface to the size of the window.
@ -54,3 +56,6 @@ fn all_red(elwt: &EventLoopWindowTarget<()>) {
}
winit_test::main!(all_red);
*/
fn main() {}