Skip to content

Commit f6cd415

Browse files
committed
WIP linux-drm-syncobj-v1
1 parent ba0121a commit f6cd415

File tree

6 files changed

+424
-8
lines changed

6 files changed

+424
-8
lines changed

Cargo.toml

+22-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ profiling = "1.0"
6969
smallvec = "1.11"
7070
pixman = { version = "0.1.0", features = ["drm-fourcc"], optional = true }
7171

72+
[patch.crates-io]
73+
wayland-egl = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
74+
wayland-protocols = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
75+
wayland-protocols-wlr = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
76+
wayland-protocols-misc = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
77+
wayland-server = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
78+
wayland-client = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
79+
wayland-sys = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
80+
wayland-backend = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
81+
wayland-scanner = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" }
82+
# wayland-egl = { path = "../wayland-rs/wayland-egl/" }
83+
# wayland-protocols = { path = "../wayland-rs/wayland-protocols/" }
84+
# wayland-protocols-wlr = { path = "../wayland-rs/wayland-protocols-wlr/" }
85+
# wayland-protocols-misc = { path = "../wayland-rs/wayland-protocols-misc/" }
86+
# wayland-server = { path = "../wayland-rs/wayland-server/" }
87+
# wayland-client = { path = "../wayland-rs/wayland-client/" }
88+
# wayland-sys = { path = "../wayland-rs/wayland-sys/" }
89+
# wayland-backend = { path = "../wayland-rs/wayland-backend/" }
90+
# wayland-scanner = { path = "../wayland-rs/wayland-scanner/" }
91+
drm = { git = "https://github.com/smithay/drm-rs" }
92+
drm-ffi = { git = "https://github.com/smithay/drm-rs" }
7293

7394
[dev-dependencies]
7495
clap = { version = "4", features = ["derive"] }
@@ -82,7 +103,7 @@ pkg-config = { version = "0.3.17", optional = true }
82103
cc = { version = "1.0.79", optional = true }
83104

84105
[features]
85-
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_libseat", "backend_x11", "backend_winit", "desktop", "renderer_gl", "renderer_pixman", "renderer_multi", "xwayland", "wayland_frontend", "backend_vulkan"]
106+
default = ["backend_drm", "backend_gbm", "backend_libinput", "backend_udev", "backend_session_libseat", "backend_x11", "desktop", "renderer_gl", "renderer_pixman", "renderer_multi", "xwayland", "wayland_frontend", "backend_vulkan"] # XXX
86107
backend_winit = ["winit", "backend_egl", "wayland-egl", "renderer_gl"]
87108
backend_x11 = ["x11rb", "x11rb/dri3", "x11rb/xfixes", "x11rb/present", "x11rb_event_source", "backend_gbm", "backend_drm", "backend_egl"]
88109
backend_drm = ["drm", "drm-ffi"]

anvil/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ gl_generator = "0.14"
3737

3838
[features]
3939
debug = ["fps_ticker", "image/png", "renderdoc"]
40-
default = ["egl", "winit", "x11", "udev", "xwayland"]
40+
default = ["egl", "x11", "udev", "xwayland"] # XXX
4141
egl = ["smithay/use_system_lib", "smithay/backend_egl"]
4242
test_all_features = ["default", "debug"]
4343
udev = [

anvil/src/state.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ use smithay::{
1313
default_primary_scanout_output_compare, utils::select_dmabuf_feedback, RenderElementStates,
1414
},
1515
},
16-
delegate_compositor, delegate_data_control, delegate_data_device, delegate_fractional_scale,
17-
delegate_input_method_manager, delegate_keyboard_shortcuts_inhibit, delegate_layer_shell,
18-
delegate_output, delegate_pointer_constraints, delegate_pointer_gestures, delegate_presentation,
19-
delegate_primary_selection, delegate_relative_pointer, delegate_seat, delegate_security_context,
20-
delegate_shm, delegate_tablet_manager, delegate_text_input_manager, delegate_viewporter,
21-
delegate_virtual_keyboard_manager, delegate_xdg_activation, delegate_xdg_decoration, delegate_xdg_shell,
16+
delegate_compositor, delegate_data_control, delegate_data_device, delegate_drm_syncobj,
17+
delegate_fractional_scale, delegate_input_method_manager, delegate_keyboard_shortcuts_inhibit,
18+
delegate_layer_shell, delegate_output, delegate_pointer_constraints, delegate_pointer_gestures,
19+
delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat,
20+
delegate_security_context, delegate_shm, delegate_tablet_manager, delegate_text_input_manager,
21+
delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation, delegate_xdg_decoration,
22+
delegate_xdg_shell,
2223
desktop::{
2324
space::SpaceElement,
2425
utils::{
@@ -48,6 +49,7 @@ use smithay::{
4849
wayland::{
4950
compositor::{get_parent, with_states, CompositorClientState, CompositorState},
5051
dmabuf::DmabufFeedback,
52+
drm_syncobj::DrmSyncobjState,
5153
fractional_scale::{with_fractional_scale, FractionalScaleHandler, FractionalScaleManagerState},
5254
input_method::{InputMethodHandler, InputMethodManagerState, PopupSurface},
5355
keyboard_shortcuts_inhibit::{
@@ -526,6 +528,8 @@ impl<BackendData: Backend> XdgForeignHandler for AnvilState<BackendData> {
526528
}
527529
smithay::delegate_xdg_foreign!(@<BackendData: Backend + 'static> AnvilState<BackendData>);
528530

531+
delegate_drm_syncobj!(@<BackendData: Backend + 'static> AnvilState<BackendData>);
532+
529533
impl<BackendData: Backend + 'static> AnvilState<BackendData> {
530534
pub fn init(
531535
display: Display<AnvilState<BackendData>>,
@@ -604,6 +608,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
604608
.get_data::<ClientState>()
605609
.map_or(true, |client_state| client_state.security_context.is_none())
606610
});
611+
DrmSyncobjState::new::<Self>(&dh);
607612

608613
// init input
609614
let seat_name = backend_data.seat_name();

src/wayland/drm_syncobj/mod.rs

+281
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
use std::{
2+
cell::RefCell,
3+
os::unix::io::{AsFd, OwnedFd},
4+
sync::Arc,
5+
};
6+
use wayland_protocols::wp::linux_drm_syncobj::v1::server::{
7+
wp_linux_drm_syncobj_manager_v1::{self, WpLinuxDrmSyncobjManagerV1},
8+
wp_linux_drm_syncobj_surface_v1::{self, WpLinuxDrmSyncobjSurfaceV1},
9+
wp_linux_drm_syncobj_timeline_v1::{self, WpLinuxDrmSyncobjTimelineV1},
10+
};
11+
use wayland_server::{
12+
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New,
13+
Resource, Weak,
14+
};
15+
16+
use super::compositor::{self, with_states, BufferAssignment, Cacheable, SurfaceAttributes};
17+
18+
mod sync_point;
19+
pub use sync_point::{SyncPoint, Timeline};
20+
21+
#[derive(Default)]
22+
struct DrmSyncobjCachedState {
23+
acquire_point: Option<SyncPoint>,
24+
release_point: Option<SyncPoint>,
25+
}
26+
27+
impl Cacheable for DrmSyncobjCachedState {
28+
fn commit(&mut self, _dh: &DisplayHandle) -> Self {
29+
Self {
30+
acquire_point: None,
31+
release_point: None,
32+
}
33+
}
34+
35+
fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) {
36+
if self.acquire_point.is_some() && self.release_point.is_some() {
37+
into.acquire_point = self.acquire_point;
38+
into.release_point = self.release_point;
39+
} else {
40+
into.acquire_point = None;
41+
into.release_point = None;
42+
}
43+
}
44+
}
45+
46+
pub struct DrmSyncobjState {}
47+
48+
impl DrmSyncobjState {
49+
pub fn new<D: 'static>(display: &DisplayHandle) -> Self
50+
where
51+
D: GlobalDispatch<WpLinuxDrmSyncobjManagerV1, ()>,
52+
{
53+
display.create_global::<D, WpLinuxDrmSyncobjManagerV1, _>(1, ());
54+
Self {}
55+
}
56+
57+
// TODO new_with_filter
58+
}
59+
60+
impl<D> GlobalDispatch<WpLinuxDrmSyncobjManagerV1, (), D> for DrmSyncobjState
61+
where
62+
D: Dispatch<WpLinuxDrmSyncobjManagerV1, ()>,
63+
{
64+
fn bind(
65+
state: &mut D,
66+
dh: &DisplayHandle,
67+
client: &Client,
68+
resource: New<WpLinuxDrmSyncobjManagerV1>,
69+
_global_data: &(),
70+
data_init: &mut DataInit<'_, D>,
71+
) {
72+
data_init.init::<_, _>(resource, ());
73+
}
74+
}
75+
76+
fn commit_hook<D>(_: &mut D, _dh: &DisplayHandle, surface: &WlSurface) {
77+
compositor::with_states(&surface, |states| {
78+
let cached = &states.cached_state;
79+
let has_new_buffer = matches!(
80+
cached.pending::<SurfaceAttributes>().buffer,
81+
Some(BufferAssignment::NewBuffer(_))
82+
);
83+
// TODO what if syncobj surface is destroyed?
84+
if let Some(data) = states
85+
.data_map
86+
.get::<RefCell<Option<WpLinuxDrmSyncobjSurfaceV1>>>()
87+
{
88+
if let Some(syncobj_surface) = data.borrow().as_ref() {
89+
let pending = cached.pending::<DrmSyncobjCachedState>();
90+
if pending.acquire_point.is_some() && !has_new_buffer {
91+
syncobj_surface.post_error(
92+
wp_linux_drm_syncobj_surface_v1::Error::NoBuffer as u32,
93+
"acquire point without buffer".to_string(),
94+
);
95+
} else if pending.acquire_point.is_some() && pending.release_point.is_none() {
96+
syncobj_surface.post_error(
97+
wp_linux_drm_syncobj_surface_v1::Error::NoReleasePoint as u32,
98+
"acquire point without release point".to_string(),
99+
);
100+
} else if pending.acquire_point.is_none() && pending.release_point.is_some() {
101+
syncobj_surface.post_error(
102+
wp_linux_drm_syncobj_surface_v1::Error::NoAcquirePoint as u32,
103+
"release point without acquire point".to_string(),
104+
);
105+
} else if let (Some(acquire), Some(release)) =
106+
(pending.acquire_point.as_ref(), pending.release_point.as_ref())
107+
{
108+
if acquire.timeline == release.timeline && acquire.point <= release.point {
109+
syncobj_surface.post_error(
110+
wp_linux_drm_syncobj_surface_v1::Error::ConflictingPoints as u32,
111+
format!(
112+
"release point '{}' is not greater than acquire point '{}'",
113+
release.point, acquire.point
114+
),
115+
);
116+
}
117+
}
118+
// TODO unsupported buffer error
119+
}
120+
}
121+
});
122+
}
123+
124+
impl<D> Dispatch<WpLinuxDrmSyncobjManagerV1, (), D> for DrmSyncobjState
125+
where
126+
D: Dispatch<WpLinuxDrmSyncobjSurfaceV1, DrmSyncobjSurfaceData>,
127+
D: Dispatch<WpLinuxDrmSyncobjTimelineV1, DrmSyncobjTimelineData>,
128+
{
129+
fn request(
130+
state: &mut D,
131+
_client: &Client,
132+
resource: &WpLinuxDrmSyncobjManagerV1,
133+
request: wp_linux_drm_syncobj_manager_v1::Request,
134+
_data: &(),
135+
_dh: &DisplayHandle,
136+
data_init: &mut DataInit<'_, D>,
137+
) {
138+
match request {
139+
wp_linux_drm_syncobj_manager_v1::Request::GetSurface { id, surface } => {
140+
let already_exists = with_states(&surface, |states| {
141+
states
142+
.data_map
143+
.get::<RefCell<Option<WpLinuxDrmSyncobjSurfaceV1>>>()
144+
.map(|v| v.borrow().is_some())
145+
.unwrap_or(false)
146+
});
147+
if already_exists {
148+
resource.post_error(
149+
wp_linux_drm_syncobj_manager_v1::Error::SurfaceExists as u32,
150+
"the surface already has a syncobj_surface object associated".to_string(),
151+
);
152+
return;
153+
}
154+
let syncobj_surface = data_init.init::<_, _>(
155+
id,
156+
DrmSyncobjSurfaceData {
157+
surface: surface.downgrade(),
158+
},
159+
);
160+
with_states(&surface, |states| {
161+
states
162+
.data_map
163+
.insert_if_missing(|| RefCell::new(Some(syncobj_surface)))
164+
});
165+
compositor::add_pre_commit_hook::<D, _>(&surface, commit_hook);
166+
}
167+
wp_linux_drm_syncobj_manager_v1::Request::ImportTimeline { id, fd } => {
168+
match Timeline::new(todo!(), fd.as_fd()) {
169+
Ok(timeline) => {
170+
data_init.init::<_, _>(id, DrmSyncobjTimelineData { timeline });
171+
}
172+
Err(err) => {}
173+
}
174+
// TODO import, protocol error if it fails? On which GPU?
175+
}
176+
wp_linux_drm_syncobj_manager_v1::Request::Destroy => {}
177+
_ => unreachable!(),
178+
}
179+
}
180+
}
181+
182+
pub struct DrmSyncobjSurfaceData {
183+
surface: Weak<WlSurface>,
184+
}
185+
186+
impl<D> Dispatch<WpLinuxDrmSyncobjSurfaceV1, DrmSyncobjSurfaceData, D> for DrmSyncobjState {
187+
fn request(
188+
state: &mut D,
189+
_client: &Client,
190+
_resource: &WpLinuxDrmSyncobjSurfaceV1,
191+
request: wp_linux_drm_syncobj_surface_v1::Request,
192+
data: &DrmSyncobjSurfaceData,
193+
_dh: &DisplayHandle,
194+
data_init: &mut DataInit<'_, D>,
195+
) {
196+
let Ok(surface) = data.surface.upgrade() else {
197+
return;
198+
};
199+
match request {
200+
wp_linux_drm_syncobj_surface_v1::Request::Destroy => {
201+
// TODO
202+
}
203+
wp_linux_drm_syncobj_surface_v1::Request::SetAcquirePoint {
204+
timeline,
205+
point_hi,
206+
point_lo,
207+
} => {
208+
let sync_point = SyncPoint {
209+
timeline: timeline
210+
.data::<DrmSyncobjTimelineData>()
211+
.unwrap()
212+
.timeline
213+
.clone(),
214+
point: ((point_hi as u64) << 32) + (point_lo as u64),
215+
};
216+
with_states(&surface, |states| {
217+
let mut cached_state = states.cached_state.pending::<DrmSyncobjCachedState>();
218+
cached_state.acquire_point = Some(sync_point);
219+
});
220+
}
221+
wp_linux_drm_syncobj_surface_v1::Request::SetReleasePoint {
222+
timeline,
223+
point_hi,
224+
point_lo,
225+
} => {
226+
let sync_point = SyncPoint {
227+
timeline: timeline
228+
.data::<DrmSyncobjTimelineData>()
229+
.unwrap()
230+
.timeline
231+
.clone(),
232+
point: ((point_hi as u64) << 32) + (point_lo as u64),
233+
};
234+
with_states(&surface, |states| {
235+
let mut cached_state = states.cached_state.pending::<DrmSyncobjCachedState>();
236+
cached_state.release_point = Some(sync_point);
237+
});
238+
}
239+
_ => unreachable!(),
240+
}
241+
}
242+
}
243+
244+
pub struct DrmSyncobjTimelineData {
245+
timeline: Timeline,
246+
}
247+
248+
impl<D> Dispatch<WpLinuxDrmSyncobjTimelineV1, DrmSyncobjTimelineData, D> for DrmSyncobjState {
249+
fn request(
250+
state: &mut D,
251+
_client: &Client,
252+
_resource: &WpLinuxDrmSyncobjTimelineV1,
253+
request: wp_linux_drm_syncobj_timeline_v1::Request,
254+
_data: &DrmSyncobjTimelineData,
255+
_dh: &DisplayHandle,
256+
data_init: &mut DataInit<'_, D>,
257+
) {
258+
match request {
259+
wp_linux_drm_syncobj_timeline_v1::Request::Destroy => {}
260+
_ => unreachable!(),
261+
}
262+
}
263+
}
264+
265+
#[macro_export]
266+
macro_rules! delegate_drm_syncobj {
267+
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
268+
$crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
269+
$crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1: ()
270+
] => $crate::wayland::drm_syncobj::DrmSyncobjState);
271+
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
272+
$crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1: ()
273+
] => $crate::wayland::drm_syncobj::DrmSyncobjState);
274+
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
275+
$crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_surface_v1::WpLinuxDrmSyncobjSurfaceV1: $crate::wayland::drm_syncobj::DrmSyncobjSurfaceData
276+
] => $crate::wayland::drm_syncobj::DrmSyncobjState);
277+
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
278+
$crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_timeline_v1::WpLinuxDrmSyncobjTimelineV1: $crate::wayland::drm_syncobj::DrmSyncobjTimelineData
279+
] => $crate::wayland::drm_syncobj::DrmSyncobjState);
280+
}
281+
}

0 commit comments

Comments
 (0)