backend: Adopt to new wayland-display handling
This commit is contained in:
parent
b126dfaf77
commit
270f06182e
7 changed files with 351 additions and 379 deletions
|
|
@ -1,46 +1,42 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::Format,
|
||||
drm::DrmNode,
|
||||
renderer::{gles2::Gles2Renderbuffer, ImportDma},
|
||||
drm::{DrmNode, NodeType},
|
||||
},
|
||||
reexports::{
|
||||
calloop::{generic::Generic, Interest, Mode, PostAction, RegistrationToken},
|
||||
wayland_protocols::unstable::linux_dmabuf,
|
||||
wayland_server::Client,
|
||||
calloop::RegistrationToken,
|
||||
wayland_server::{Client, DisplayHandle, backend::GlobalId},
|
||||
},
|
||||
wayland::dmabuf::init_dmabuf_global_with_filter,
|
||||
};
|
||||
|
||||
use std::{
|
||||
env,
|
||||
os::unix::{
|
||||
io::{AsRawFd, IntoRawFd, RawFd},
|
||||
net::UnixListener,
|
||||
wayland::{
|
||||
dmabuf::DmabufGlobal,
|
||||
socket::ListeningSocketSource,
|
||||
},
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{state::State, utils::GlobalDrop, wayland::init_wl_drm_global};
|
||||
use crate::{
|
||||
state::{ClientState, Data},
|
||||
utils::prelude::*,
|
||||
};
|
||||
|
||||
pub struct Socket {
|
||||
pub token: RegistrationToken,
|
||||
pub drm_global: GlobalDrop<crate::wayland::wl_drm::WlDrm>,
|
||||
pub dmabuf_global: GlobalDrop<linux_dmabuf::v1::server::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1>,
|
||||
pub drm_global: GlobalId,
|
||||
pub dmabuf_global: DmabufGlobal,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub(super) fn create_socket(
|
||||
&mut self,
|
||||
dh: &DisplayHandle,
|
||||
render_node: DrmNode,
|
||||
formats: impl Iterator<Item = Format>,
|
||||
) -> Result<Socket> {
|
||||
let formats = formats.collect::<Vec<_>>();
|
||||
let is_primary = self.backend.kms().primary == render_node;
|
||||
let socket_path = PathBuf::from(env::var("XDG_RUNTIME_DIR").unwrap()).join(format!(
|
||||
let socket_name = format!(
|
||||
"{}-{}",
|
||||
&self.common.socket.to_string_lossy(),
|
||||
render_node
|
||||
|
|
@ -49,125 +45,63 @@ impl State {
|
|||
.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
));
|
||||
// HACK!
|
||||
let _ = std::fs::remove_file(&socket_path);
|
||||
|
||||
let listener = UnixListener::bind(socket_path.clone())
|
||||
.with_context(|| format!("Failed to bind socket to {}", socket_path.display()))?;
|
||||
listener.set_nonblocking(true)?;
|
||||
let listener = WaylandListener(listener);
|
||||
let token = self
|
||||
.common
|
||||
.event_loop_handle
|
||||
.insert_source(
|
||||
Generic::new(listener, Interest::READ, Mode::Edge),
|
||||
move |_, listener, state: &mut State| {
|
||||
loop {
|
||||
match listener.0.accept() {
|
||||
Ok((stream, _)) => {
|
||||
let display = state.common.display.clone();
|
||||
let client = unsafe {
|
||||
display
|
||||
.borrow_mut()
|
||||
.create_client(stream.into_raw_fd(), state)
|
||||
};
|
||||
client
|
||||
.data_map()
|
||||
.insert_if_missing_threadsafe(|| render_node);
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||
// we have exhausted all the pending connections
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
// this is a legitimate error
|
||||
if let Ok(addr) = listener.0.local_addr() {
|
||||
if let Some(path) = addr.as_pathname() {
|
||||
slog_scope::error!(
|
||||
"Error accepting connection on listening socket {} : {}",
|
||||
path.display(),
|
||||
e
|
||||
);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
slog_scope::error!(
|
||||
"Error accepting connection on listening socket <unnamed> : {}",
|
||||
e
|
||||
);
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PostAction::Continue)
|
||||
},
|
||||
)
|
||||
.context("Failed to add gpu-wayland socket to the event loop")?;
|
||||
);
|
||||
|
||||
// initialize globals
|
||||
let filter = move |client: Client| {
|
||||
let dev_id = client.data_map().get::<DrmNode>();
|
||||
if dev_id.is_none() && is_primary {
|
||||
client
|
||||
.data_map()
|
||||
.insert_if_missing_threadsafe(|| render_node);
|
||||
}
|
||||
dev_id.map(|x| *x == render_node).unwrap_or(is_primary)
|
||||
let filter = move |client: &Client| {
|
||||
let dev_id = client.get_data::<ClientState>().unwrap().drm_node.unwrap();
|
||||
dev_id == render_node
|
||||
};
|
||||
|
||||
let drm_global = init_wl_drm_global(
|
||||
&mut *self.common.display.borrow_mut(),
|
||||
render_node.dev_path().unwrap(),
|
||||
let dmabuf_global = self.common.dmabuf_state.create_global_with_filter::<State, _, _>(
|
||||
dh,
|
||||
formats.clone(),
|
||||
filter.clone(),
|
||||
);
|
||||
let dmabuf_global = init_dmabuf_global_with_filter(
|
||||
&mut *self.common.display.borrow_mut(),
|
||||
formats,
|
||||
move |buf, mut ddata| {
|
||||
let state = ddata.get::<State>().unwrap();
|
||||
state
|
||||
.backend
|
||||
.kms()
|
||||
.api
|
||||
.renderer::<Gles2Renderbuffer>(&render_node, &render_node)
|
||||
.map(|mut renderer| renderer.import_dmabuf(buf, None).is_ok())
|
||||
.unwrap_or(false)
|
||||
},
|
||||
filter,
|
||||
None,
|
||||
);
|
||||
|
||||
slog_scope::info!(
|
||||
"Adding socket at {} for gpu {}",
|
||||
socket_path.display(),
|
||||
let drm_global_id = self.common.wl_drm_state.create_global_with_filter::<State, _>(
|
||||
dh,
|
||||
render_node
|
||||
.dev_path_with_type(NodeType::Render)
|
||||
.or_else(|| render_node.dev_path())
|
||||
.ok_or(anyhow!("Could not determine path for gpu node: {}", render_node))?,
|
||||
formats,
|
||||
&dmabuf_global,
|
||||
filter,
|
||||
);
|
||||
|
||||
// add a special socket for the gpu
|
||||
let listener = ListeningSocketSource::with_name(&socket_name, None)
|
||||
.with_context(|| format!("Failed to bind socket to {}", socket_name))?;
|
||||
let token = self
|
||||
.common
|
||||
.event_loop_handle
|
||||
.insert_source(
|
||||
listener,
|
||||
move |client_stream, _, data: &mut Data| {
|
||||
if let Err(err) = data
|
||||
.display
|
||||
.handle()
|
||||
.insert_client(client_stream, Arc::new(data.state.new_client_state_with_node(render_node)))
|
||||
{
|
||||
slog_scope::warn!("Error adding wayland client ({}): {}", render_node, err);
|
||||
}
|
||||
}
|
||||
)
|
||||
.context("Failed to add gpu-wayland socket to the event loop")?;
|
||||
|
||||
|
||||
slog_scope::info!(
|
||||
"Added socket at {} for gpu {}",
|
||||
socket_name,
|
||||
render_node,
|
||||
);
|
||||
|
||||
Ok(Socket {
|
||||
token,
|
||||
drm_global: GlobalDrop::from(drm_global),
|
||||
dmabuf_global: GlobalDrop::from(dmabuf_global),
|
||||
drm_global: drm_global_id,
|
||||
dmabuf_global,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct WaylandListener(UnixListener);
|
||||
|
||||
impl AsRawFd for WaylandListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WaylandListener {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(socketaddr) = self.0.local_addr() {
|
||||
if let Some(path) = socketaddr.as_pathname() {
|
||||
let _ = ::std::fs::remove_file(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue