Skip to content

Commit 3dc11f7

Browse files
ids1024jackpot51
authored andcommitted
Improvements to wayland backend
- Use wayland-client `0.30.0-beta.14` - Use `memfd` instead of temporary file - Make sure buffer and buffer pool objects are destroyed
1 parent 7351d68 commit 3dc11f7

File tree

2 files changed

+159
-41
lines changed

2 files changed

+159
-41
lines changed

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ thiserror = "1.0.30"
1616
raw-window-handle = "0.5.0"
1717

1818
[target.'cfg(target_os = "linux")'.dependencies]
19-
tempfile = "3.3.0"
20-
wayland-client = {version = "0.29", features = ["use_system_lib"], default_features = false}
19+
nix = "0.26.1"
20+
wayland-backend = {version = "0.1.0-beta.14", features = ["client_system"]}
21+
wayland-client = {version = "0.30.0-beta.14"}
2122
x11-dl = "2.19.1"
2223

2324
[target.'cfg(target_os = "windows")'.dependencies.winapi]

src/wayland.rs

Lines changed: 156 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,201 @@
1+
use crate::{error::unwrap, GraphicsContextImpl, SoftBufferError};
2+
use nix::sys::memfd::{memfd_create, MemFdCreateFlag};
13
use raw_window_handle::{HasRawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle};
2-
use tempfile::tempfile;
3-
use wayland_client::{Display, sys::client::wl_display, GlobalManager, protocol::{wl_shm::WlShm, wl_buffer::WlBuffer, wl_surface::WlSurface}, Main, Proxy, EventQueue};
4-
use crate::{GraphicsContextImpl, SoftBufferError, error::unwrap};
5-
use std::{fs::File, os::unix::prelude::{AsRawFd, FileExt}, io::Write};
4+
use std::{
5+
ffi::CStr,
6+
fs::File,
7+
io::Write,
8+
os::unix::prelude::{AsRawFd, FileExt, FromRawFd},
9+
};
10+
use wayland_client::{
11+
backend::{Backend, ObjectId},
12+
globals::{registry_queue_init, GlobalListContents},
13+
protocol::{wl_buffer, wl_registry, wl_shm, wl_shm_pool, wl_surface},
14+
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
15+
};
16+
17+
struct State;
618

719
pub struct WaylandImpl {
8-
_event_queue: EventQueue,
9-
surface: WlSurface,
10-
shm: Main<WlShm>,
20+
event_queue: EventQueue<State>,
21+
qh: QueueHandle<State>,
22+
surface: wl_surface::WlSurface,
23+
shm: wl_shm::WlShm,
1124
tempfile: File,
12-
buffer: Option<WaylandBuffer>
25+
buffer: Option<WaylandBuffer>,
1326
}
1427

15-
struct WaylandBuffer{
28+
struct WaylandBuffer {
1629
width: i32,
1730
height: i32,
18-
buffer: Main<WlBuffer>
31+
pool: wl_shm_pool::WlShmPool,
32+
buffer: wl_buffer::WlBuffer,
1933
}
2034

21-
impl WaylandImpl {
35+
impl Drop for WaylandBuffer {
36+
fn drop(&mut self) {
37+
self.buffer.destroy();
38+
self.pool.destroy();
39+
}
40+
}
2241

23-
pub unsafe fn new<W: HasRawWindowHandle>(window_handle: WaylandWindowHandle, display_handle: WaylandDisplayHandle) -> Result<Self, SoftBufferError<W>> {
24-
let display = Display::from_external_display(display_handle.display as *mut wl_display);
25-
let mut event_queue = display.create_event_queue();
26-
let attached_display = (*display).clone().attach(event_queue.token());
27-
let globals = GlobalManager::new(&attached_display);
28-
unwrap(event_queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()), "Failed to make round trip to server")?;
29-
let shm = unwrap(globals.instantiate_exact::<WlShm>(1), "Failed to instantiate Wayland Shm")?;
30-
let tempfile = unwrap(tempfile(), "Failed to create temporary file to store buffer.")?;
31-
let surface = Proxy::from_c_ptr(window_handle.surface as _).into();
32-
Ok(Self{
33-
_event_queue: event_queue,
34-
surface, shm, tempfile,
35-
buffer: None
42+
impl WaylandImpl {
43+
pub unsafe fn new<W: HasRawWindowHandle>(
44+
window_handle: WaylandWindowHandle,
45+
display_handle: WaylandDisplayHandle,
46+
) -> Result<Self, SoftBufferError<W>> {
47+
let conn = Connection::from_backend(Backend::from_foreign_display(
48+
display_handle.display as *mut _,
49+
));
50+
let (globals, event_queue) = unwrap(
51+
registry_queue_init(&conn),
52+
"Failed to make round trip to server",
53+
)?;
54+
let qh = event_queue.handle();
55+
let shm: wl_shm::WlShm = unwrap(
56+
globals.bind(&qh, 1..=1, ()),
57+
"Failed to instantiate Wayland Shm",
58+
)?;
59+
let name = CStr::from_bytes_with_nul_unchecked("swbuf\0".as_bytes());
60+
let tempfile_fd = unwrap(
61+
memfd_create(name, MemFdCreateFlag::MFD_CLOEXEC),
62+
"Failed to create temporary file to store buffer.",
63+
)?;
64+
let tempfile = File::from_raw_fd(tempfile_fd);
65+
let surface_id = unwrap(
66+
ObjectId::from_ptr(
67+
wl_surface::WlSurface::interface(),
68+
window_handle.surface as _,
69+
),
70+
"Failed to create proxy for surface ID.",
71+
)?;
72+
let surface = unwrap(
73+
wl_surface::WlSurface::from_id(&conn, surface_id),
74+
"Failed to create proxy for surface ID.",
75+
)?;
76+
Ok(Self {
77+
event_queue: event_queue,
78+
qh,
79+
surface,
80+
shm,
81+
tempfile,
82+
buffer: None,
3683
})
3784
}
3885

39-
fn ensure_buffer_size(&mut self, width: i32, height: i32){
40-
if !self.check_buffer_size_equals(width, height){
41-
let pool = self.shm.create_pool(self.tempfile.as_raw_fd(), width*height*4);
42-
let buffer = pool.create_buffer(0, width, height, width*4, wayland_client::protocol::wl_shm::Format::Xrgb8888);
43-
self.buffer = Some(WaylandBuffer{
86+
fn ensure_buffer_size(&mut self, width: i32, height: i32) {
87+
if !self.check_buffer_size_equals(width, height) {
88+
let pool =
89+
self.shm
90+
.create_pool(self.tempfile.as_raw_fd(), width * height * 4, &self.qh, ());
91+
let buffer = pool.create_buffer(
92+
0,
4493
width,
4594
height,
46-
buffer
95+
width * 4,
96+
wayland_client::protocol::wl_shm::Format::Xrgb8888,
97+
&self.qh,
98+
(),
99+
);
100+
self.buffer = Some(WaylandBuffer {
101+
width,
102+
height,
103+
pool,
104+
buffer,
47105
});
48106
}
49107
}
50108

51-
fn check_buffer_size_equals(&self, width: i32, height: i32) -> bool{
52-
match &self.buffer{
109+
fn check_buffer_size_equals(&self, width: i32, height: i32) -> bool {
110+
match &self.buffer {
53111
Some(buffer) => buffer.width == width && buffer.height == height,
54-
None => false
112+
None => false,
55113
}
56114
}
57-
58115
}
59116

60117
impl GraphicsContextImpl for WaylandImpl {
61118
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
62119
self.ensure_buffer_size(width as i32, height as i32);
63120
let wayland_buffer = self.buffer.as_mut().unwrap();
64-
self.tempfile.write_at(std::slice::from_raw_parts(buffer.as_ptr() as *const u8, buffer.len()*4), 0).expect("Failed to write buffer to temporary file.");
65-
self.tempfile.flush().expect("Failed to flush buffer to temporary file.");
121+
self.tempfile.set_len(buffer.len() as u64 * 4)
122+
.expect("Failed to truncate temporary file.");
123+
self.tempfile
124+
.write_at(
125+
std::slice::from_raw_parts(buffer.as_ptr() as *const u8, buffer.len() * 4),
126+
0,
127+
)
128+
.expect("Failed to write buffer to temporary file.");
129+
self.tempfile
130+
.flush()
131+
.expect("Failed to flush buffer to temporary file.");
66132
self.surface.attach(Some(&wayland_buffer.buffer), 0, 0);
67133

68134
// FIXME: Proper damaging mechanism.
69135
//
70136
// In order to propagate changes on compositors which track damage, for now damage the entire surface.
71-
if self.surface.as_ref().version() < 4 {
137+
if self.surface.version() < 4 {
72138
// FIXME: Accommodate scale factor since wl_surface::damage is in terms of surface coordinates while
73139
// wl_surface::damage_buffer is in buffer coordinates.
74140
//
75141
// i32::MAX is a valid damage box (most compositors interpret the damage box as "the entire surface")
76142
self.surface.damage(0, 0, i32::MAX, i32::MAX);
77143
} else {
78144
// Introduced in version 4, it is an error to use this request in version 3 or lower.
79-
self.surface.damage_buffer(0, 0, width as i32, height as i32);
145+
self.surface
146+
.damage_buffer(0, 0, width as i32, height as i32);
80147
}
81148

82149
self.surface.commit();
150+
let _ = self.event_queue.flush();
151+
}
152+
}
153+
154+
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
155+
fn event(
156+
_: &mut State,
157+
_: &wl_registry::WlRegistry,
158+
_: wl_registry::Event,
159+
_: &GlobalListContents,
160+
_: &Connection,
161+
_: &QueueHandle<State>,
162+
) {
163+
// Ignore globals added after initialization
83164
}
84-
}
165+
}
166+
167+
impl Dispatch<wl_shm::WlShm, ()> for State {
168+
fn event(
169+
_: &mut State,
170+
_: &wl_shm::WlShm,
171+
_: wl_shm::Event,
172+
_: &(),
173+
_: &Connection,
174+
_: &QueueHandle<State>,
175+
) {
176+
}
177+
}
178+
179+
impl Dispatch<wl_shm_pool::WlShmPool, ()> for State {
180+
fn event(
181+
_: &mut State,
182+
_: &wl_shm_pool::WlShmPool,
183+
_: wl_shm_pool::Event,
184+
_: &(),
185+
_: &Connection,
186+
_: &QueueHandle<State>,
187+
) {
188+
}
189+
}
190+
191+
impl Dispatch<wl_buffer::WlBuffer, ()> for State {
192+
fn event(
193+
_: &mut State,
194+
_: &wl_buffer::WlBuffer,
195+
_: wl_buffer::Event,
196+
_: &(),
197+
_: &Connection,
198+
_: &QueueHandle<State>,
199+
) {
200+
}
201+
}

0 commit comments

Comments
 (0)