2022-07-04 15:26:26 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
|
|
|
|
// Re-export only the actual code, and then only use this re-export
|
|
|
|
|
// The `generated` module below is just some boilerplate to properly isolate stuff
|
|
|
|
|
// and avoid exposing internal details.
|
|
|
|
|
//
|
|
|
|
|
// You can use all the types from my_protocol as if they went from `wayland_client::protocol`.
|
|
|
|
|
pub use generated::wl_drm;
|
|
|
|
|
|
|
|
|
|
mod generated {
|
|
|
|
|
use smithay::reexports::wayland_server::{self, protocol::*};
|
|
|
|
|
|
|
|
|
|
pub mod __interfaces {
|
|
|
|
|
use smithay::reexports::wayland_server::protocol::__interfaces::*;
|
|
|
|
|
use wayland_backend;
|
|
|
|
|
wayland_scanner::generate_interfaces!("resources/protocols/wayland-drm.xml");
|
|
|
|
|
}
|
|
|
|
|
use self::__interfaces::*;
|
|
|
|
|
|
|
|
|
|
wayland_scanner::generate_server_code!("resources/protocols/wayland-drm.xml");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use smithay::{
|
|
|
|
|
backend::allocator::{
|
|
|
|
|
dmabuf::{Dmabuf, DmabufFlags},
|
|
|
|
|
Format, Fourcc, Modifier,
|
|
|
|
|
},
|
|
|
|
|
reexports::wayland_server::{
|
2022-08-30 13:28:36 +02:00
|
|
|
backend::GlobalId, protocol::wl_buffer::WlBuffer, Client, DataInit, Dispatch,
|
|
|
|
|
DisplayHandle, GlobalDispatch, New, Resource,
|
2022-07-04 15:26:26 +02:00
|
|
|
},
|
|
|
|
|
wayland::{
|
|
|
|
|
buffer::BufferHandler,
|
|
|
|
|
dmabuf::{DmabufGlobal, DmabufHandler, ImportError},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
use std::{convert::TryFrom, path::PathBuf, sync::Arc};
|
2022-07-04 15:26:26 +02:00
|
|
|
|
|
|
|
|
pub struct WlDrmState;
|
|
|
|
|
|
|
|
|
|
/// Data associated with a drm global.
|
|
|
|
|
pub struct DrmGlobalData {
|
|
|
|
|
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
|
|
|
|
formats: Arc<Vec<Fourcc>>,
|
|
|
|
|
device_path: PathBuf,
|
|
|
|
|
_logger: slog::Logger,
|
|
|
|
|
dmabuf_global: DmabufGlobal,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct DrmInstanceData {
|
|
|
|
|
formats: Arc<Vec<Fourcc>>,
|
|
|
|
|
dmabuf_global: DmabufGlobal,
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-18 18:04:02 +02:00
|
|
|
impl<D> GlobalDispatch<wl_drm::WlDrm, DrmGlobalData, D> for WlDrmState
|
2022-07-04 15:26:26 +02:00
|
|
|
where
|
|
|
|
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
|
|
|
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
|
|
|
|
+ BufferHandler
|
|
|
|
|
+ DmabufHandler
|
|
|
|
|
+ 'static,
|
|
|
|
|
{
|
|
|
|
|
fn bind(
|
|
|
|
|
_state: &mut D,
|
|
|
|
|
_dh: &DisplayHandle,
|
|
|
|
|
_client: &Client,
|
|
|
|
|
resource: New<wl_drm::WlDrm>,
|
|
|
|
|
global_data: &DrmGlobalData,
|
|
|
|
|
data_init: &mut DataInit<'_, D>,
|
|
|
|
|
) {
|
|
|
|
|
let data = DrmInstanceData {
|
|
|
|
|
formats: global_data.formats.clone(),
|
|
|
|
|
dmabuf_global: global_data.dmabuf_global.clone(),
|
|
|
|
|
};
|
|
|
|
|
let drm_instance = data_init.init(resource, data);
|
|
|
|
|
|
|
|
|
|
drm_instance.device(global_data.device_path.to_string_lossy().into_owned());
|
|
|
|
|
if drm_instance.version() >= 2 {
|
|
|
|
|
drm_instance.capabilities(wl_drm::Capability::Prime as u32);
|
|
|
|
|
}
|
|
|
|
|
for format in global_data.formats.iter() {
|
|
|
|
|
if let Ok(converted) = wl_drm::Format::try_from(*format as u32) {
|
|
|
|
|
drm_instance.format(converted as u32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn can_view(client: Client, global_data: &DrmGlobalData) -> bool {
|
|
|
|
|
(global_data.filter)(&client)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-18 18:04:02 +02:00
|
|
|
impl<D> Dispatch<wl_drm::WlDrm, DrmInstanceData, D> for WlDrmState
|
2022-07-04 15:26:26 +02:00
|
|
|
where
|
|
|
|
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
|
|
|
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
|
|
|
|
+ Dispatch<WlBuffer, Dmabuf>
|
|
|
|
|
+ BufferHandler
|
|
|
|
|
+ DmabufHandler
|
|
|
|
|
+ 'static,
|
|
|
|
|
{
|
|
|
|
|
fn request(
|
|
|
|
|
state: &mut D,
|
|
|
|
|
_client: &Client,
|
|
|
|
|
drm: &wl_drm::WlDrm,
|
|
|
|
|
request: wl_drm::Request,
|
|
|
|
|
data: &DrmInstanceData,
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
data_init: &mut DataInit<'_, D>,
|
|
|
|
|
) {
|
|
|
|
|
match request {
|
|
|
|
|
wl_drm::Request::Authenticate { .. } => drm.authenticated(),
|
2022-07-04 16:00:29 +02:00
|
|
|
wl_drm::Request::CreateBuffer { .. } => drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidName,
|
|
|
|
|
String::from("Flink handles are unsupported, use PRIME"),
|
|
|
|
|
),
|
|
|
|
|
wl_drm::Request::CreatePlanarBuffer { .. } => drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidName,
|
|
|
|
|
String::from("Flink handles are unsupported, use PRIME"),
|
|
|
|
|
),
|
2022-07-04 15:26:26 +02:00
|
|
|
wl_drm::Request::CreatePrimeBuffer {
|
|
|
|
|
id,
|
|
|
|
|
name,
|
|
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
format,
|
|
|
|
|
offset0,
|
|
|
|
|
stride0,
|
|
|
|
|
..
|
|
|
|
|
} => {
|
|
|
|
|
let format = match Fourcc::try_from(format) {
|
|
|
|
|
Ok(format) => {
|
|
|
|
|
if !data.formats.contains(&format) {
|
|
|
|
|
drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidFormat,
|
|
|
|
|
String::from("Format not advertised by wl_drm"),
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
format
|
2022-07-04 16:00:29 +02:00
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
Err(_) => {
|
|
|
|
|
drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidFormat,
|
|
|
|
|
String::from("Format unknown / not advertised by wl_drm"),
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if width < 1 || height < 1 {
|
|
|
|
|
drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidFormat,
|
|
|
|
|
String::from("width or height not positive"),
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut dma = Dmabuf::builder((width, height), format, DmabufFlags::empty());
|
|
|
|
|
dma.add_plane(name, 0, offset0 as u32, stride0 as u32, Modifier::Invalid);
|
|
|
|
|
match dma.build() {
|
2022-07-04 16:00:29 +02:00
|
|
|
Some(dmabuf) => {
|
|
|
|
|
match state.dmabuf_imported(dh, &data.dmabuf_global, dmabuf.clone()) {
|
|
|
|
|
Ok(_) => {
|
|
|
|
|
// import was successful
|
|
|
|
|
data_init.init(id, dmabuf);
|
|
|
|
|
slog_scope::trace!(
|
|
|
|
|
"Created a new validated dma wl_buffer via wl_drm."
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
Err(ImportError::InvalidFormat) => {
|
|
|
|
|
drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidFormat,
|
|
|
|
|
"format and plane combination are not valid",
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
Err(ImportError::Failed) => {
|
|
|
|
|
// Buffer import failed. The protocol documentation heavily implies killing the
|
|
|
|
|
// client is the right thing to do here.
|
|
|
|
|
drm.post_error(wl_drm::Error::InvalidName, "buffer import failed");
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
2022-07-04 16:00:29 +02:00
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
None => {
|
|
|
|
|
// Buffer import failed. The protocol documentation heavily implies killing the
|
|
|
|
|
// client is the right thing to do here.
|
|
|
|
|
drm.post_error(
|
|
|
|
|
wl_drm::Error::InvalidName,
|
|
|
|
|
"dmabuf global was destroyed on server",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl WlDrmState {
|
|
|
|
|
pub fn create_global<D>(
|
|
|
|
|
&mut self,
|
|
|
|
|
display: &DisplayHandle,
|
|
|
|
|
device_path: PathBuf,
|
|
|
|
|
formats: Vec<Format>,
|
|
|
|
|
dmabuf_global: &DmabufGlobal,
|
|
|
|
|
) -> GlobalId
|
|
|
|
|
where
|
|
|
|
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
|
|
|
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
|
|
|
|
+ BufferHandler
|
|
|
|
|
+ DmabufHandler
|
|
|
|
|
+ 'static,
|
|
|
|
|
{
|
2022-07-04 16:00:29 +02:00
|
|
|
self.create_global_with_filter::<D, _>(display, device_path, formats, dmabuf_global, |_| {
|
|
|
|
|
true
|
|
|
|
|
})
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn create_global_with_filter<D, F>(
|
|
|
|
|
&mut self,
|
|
|
|
|
display: &DisplayHandle,
|
|
|
|
|
device_path: PathBuf,
|
|
|
|
|
formats: Vec<Format>,
|
|
|
|
|
dmabuf_global: &DmabufGlobal,
|
|
|
|
|
client_filter: F,
|
|
|
|
|
) -> GlobalId
|
|
|
|
|
where
|
|
|
|
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
|
|
|
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
|
|
|
|
+ BufferHandler
|
|
|
|
|
+ DmabufHandler
|
|
|
|
|
+ 'static,
|
|
|
|
|
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
|
|
|
|
{
|
2022-07-04 16:00:29 +02:00
|
|
|
let formats = Arc::new(
|
|
|
|
|
formats
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter(|f| f.modifier == Modifier::Invalid)
|
|
|
|
|
.map(|f| f.code)
|
|
|
|
|
.collect(),
|
|
|
|
|
);
|
2022-07-04 15:26:26 +02:00
|
|
|
let data = DrmGlobalData {
|
|
|
|
|
filter: Box::new(client_filter),
|
|
|
|
|
formats,
|
|
|
|
|
device_path,
|
|
|
|
|
dmabuf_global: dmabuf_global.clone(),
|
|
|
|
|
_logger: slog_scope::logger().new(slog::o!("cosmic_module" => "wayland_drm")),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
display.create_global::<D, wl_drm::WlDrm, _>(2, data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
macro_rules! delegate_wl_drm {
|
|
|
|
|
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
|
|
|
|
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
|
|
|
|
$crate::wayland::protocols::drm::wl_drm::WlDrm: $crate::wayland::protocols::drm::DrmGlobalData
|
|
|
|
|
] => $crate::wayland::protocols::drm::WlDrmState);
|
|
|
|
|
smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
|
|
|
|
$crate::wayland::protocols::drm::wl_drm::WlDrm: $crate::wayland::protocols::drm::DrmInstanceData
|
|
|
|
|
] => $crate::wayland::protocols::drm::WlDrmState);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
pub(crate) use delegate_wl_drm;
|