Skip to content

Commit bad4088

Browse files
committed
WIP linux-drm-syncobj-v1
1 parent 3731734 commit bad4088

File tree

10 files changed

+735
-18
lines changed

10 files changed

+735
-18
lines changed

anvil/src/shell/mod.rs

+29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ use std::cell::RefCell;
22

33
#[cfg(feature = "xwayland")]
44
use smithay::xwayland::XWaylandClientData;
5+
6+
#[cfg(feature = "udev")]
7+
use smithay::wayland::drm_syncobj::DrmSyncobjCachedState;
8+
59
use smithay::{
610
backend::renderer::utils::on_commit_buffer_handler,
711
desktop::{
@@ -111,7 +115,17 @@ impl<BackendData: Backend> CompositorHandler for AnvilState<BackendData> {
111115

112116
fn new_surface(&mut self, surface: &WlSurface) {
113117
add_pre_commit_hook::<Self, _>(surface, move |state, _dh, surface| {
118+
#[cfg(feature = "udev")]
119+
let mut acquire_point = None;
114120
let maybe_dmabuf = with_states(surface, |surface_data| {
121+
#[cfg(feature = "udev")]
122+
acquire_point.clone_from(
123+
&surface_data
124+
.cached_state
125+
.get::<DrmSyncobjCachedState>()
126+
.pending()
127+
.acquire_point,
128+
);
115129
surface_data
116130
.cached_state
117131
.get::<SurfaceAttributes>()
@@ -124,6 +138,21 @@ impl<BackendData: Backend> CompositorHandler for AnvilState<BackendData> {
124138
})
125139
});
126140
if let Some(dmabuf) = maybe_dmabuf {
141+
#[cfg(feature = "udev")]
142+
if let Some(acquire_point) = acquire_point {
143+
if let Ok((blocker, source)) = acquire_point.generate_blocker() {
144+
let client = surface.client().unwrap();
145+
let res = state.handle.insert_source(source, move |_, _, data| {
146+
let dh = data.display_handle.clone();
147+
data.client_compositor_state(&client).blocker_cleared(data, &dh);
148+
Ok(())
149+
});
150+
if res.is_ok() {
151+
add_blocker(surface, blocker);
152+
return;
153+
}
154+
}
155+
}
127156
if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) {
128157
if let Some(client) = surface.client() {
129158
let res = state.handle.insert_source(source, move |_, _, data| {

anvil/src/udev.rs

+27
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ use smithay::{
8585
drm_lease::{
8686
DrmLease, DrmLeaseBuilder, DrmLeaseHandler, DrmLeaseRequest, DrmLeaseState, LeaseRejected,
8787
},
88+
drm_syncobj::{supports_syncobj_eventfd, DrmSyncobjHandler, DrmSyncobjState},
8889
},
8990
};
9091
use smithay_drm_extras::{
@@ -124,6 +125,7 @@ pub struct UdevData {
124125
pub session: LibSeatSession,
125126
dh: DisplayHandle,
126127
dmabuf_state: Option<(DmabufState, DmabufGlobal)>,
128+
syncobj_state: Option<DrmSyncobjState>,
127129
primary_gpu: DrmNode,
128130
gpus: GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>,
129131
backends: HashMap<DrmNode, BackendData>,
@@ -247,6 +249,7 @@ pub fn run_udev() {
247249
let data = UdevData {
248250
dh: display_handle.clone(),
249251
dmabuf_state: None,
252+
syncobj_state: None,
250253
session,
251254
primary_gpu,
252255
gpus,
@@ -434,6 +437,23 @@ pub fn run_udev() {
434437
});
435438
});
436439

440+
// Expose syncobj protocol if supported by primary GPU
441+
if let Some(primary_node) = state
442+
.backend_data
443+
.primary_gpu
444+
.node_with_type(NodeType::Primary)
445+
.and_then(|x| x.ok())
446+
{
447+
if let Some(backend) = state.backend_data.backends.get(&primary_node) {
448+
let import_device = backend.drm.device_fd().clone();
449+
if supports_syncobj_eventfd(&import_device) {
450+
let syncobj_state =
451+
DrmSyncobjState::new::<AnvilState<UdevData>>(&display_handle, import_device);
452+
state.backend_data.syncobj_state = Some(syncobj_state);
453+
}
454+
}
455+
}
456+
437457
event_loop
438458
.handle()
439459
.insert_source(udev_backend, move |event, _, data| match event {
@@ -553,6 +573,13 @@ impl DrmLeaseHandler for AnvilState<UdevData> {
553573

554574
delegate_drm_lease!(AnvilState<UdevData>);
555575

576+
impl DrmSyncobjHandler for AnvilState<UdevData> {
577+
fn drm_syncobj_state(&mut self) -> &mut DrmSyncobjState {
578+
self.backend_data.syncobj_state.as_mut().unwrap()
579+
}
580+
}
581+
smithay::delegate_drm_syncobj!(AnvilState<UdevData>);
582+
556583
pub type RenderSurface = GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>;
557584

558585
pub type GbmDrmCompositor = DrmCompositor<

src/backend/drm/compositor/mod.rs

+41-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ use std::{
130130
};
131131

132132
use drm::{
133-
control::{connector, crtc, framebuffer, plane, Mode, PlaneType},
133+
control::{connector, crtc, framebuffer, plane, Device as _, Mode, PlaneType},
134134
Device, DriverCapability,
135135
};
136136
use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier};
@@ -203,6 +203,22 @@ enum ScanoutBuffer<B: Buffer> {
203203
Cursor(GbmBuffer),
204204
}
205205

206+
impl<B: Buffer> ScanoutBuffer<B> {
207+
fn acquire_point(
208+
&self,
209+
signaled_fence: Option<&Arc<OwnedFd>>,
210+
) -> Option<(SyncPoint, Option<Arc<OwnedFd>>)> {
211+
if let Self::Wayland(buffer) = self {
212+
// Assume `DrmSyncobjBlocker` is used, so acquire point has already
213+
// been signaled. Instead of converting with `SyncPoint::from`.
214+
if buffer.acquire_point().is_some() {
215+
return Some((SyncPoint::signaled(), signaled_fence.cloned()));
216+
}
217+
}
218+
None
219+
}
220+
}
221+
206222
impl<B: Buffer> ScanoutBuffer<B> {
207223
#[inline]
208224
fn from_underlying_storage(storage: UnderlyingStorage<'_>) -> Option<Self> {
@@ -1562,6 +1578,7 @@ where
15621578
supports_fencing: bool,
15631579
direct_scanout: bool,
15641580
reset_pending: bool,
1581+
signaled_fence: Option<Arc<OwnedFd>>,
15651582

15661583
framebuffer_exporter: F,
15671584

@@ -1628,6 +1645,24 @@ where
16281645
cursor_size: Size<u32, BufferCoords>,
16291646
gbm: Option<GbmDevice<G>>,
16301647
) -> FrameResult<Self, A, F> {
1648+
let signaled_fence = match surface.create_syncobj(true) {
1649+
Ok(signaled_syncobj) => match surface.syncobj_to_fd(signaled_syncobj, true) {
1650+
Ok(signaled_fence) => {
1651+
let _ = surface.destroy_syncobj(signaled_syncobj);
1652+
Some(Arc::new(signaled_fence))
1653+
}
1654+
Err(err) => {
1655+
tracing::warn!(?err, "failed to export signaled syncobj");
1656+
let _ = surface.destroy_syncobj(signaled_syncobj);
1657+
None
1658+
}
1659+
},
1660+
Err(err) => {
1661+
tracing::warn!(?err, "failed to create signaled syncobj");
1662+
None
1663+
}
1664+
};
1665+
16311666
let span = info_span!(
16321667
parent: None,
16331668
"drm_compositor",
@@ -1730,6 +1765,7 @@ where
17301765
primary_is_opaque: is_opaque,
17311766
direct_scanout: true,
17321767
reset_pending: true,
1768+
signaled_fence,
17331769
current_frame,
17341770
pending_frame: None,
17351771
queued_frame: None,
@@ -3969,7 +4005,10 @@ where
39694005
buffer: element_config.buffer.clone(),
39704006
damage_clips,
39714007
plane_claim,
3972-
sync: None,
4008+
sync: element_config
4009+
.buffer
4010+
.buffer
4011+
.acquire_point(self.signaled_fence.as_ref()),
39734012
};
39744013

39754014
let is_compatible = previous_state

src/backend/drm/device/fd.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use tracing::{error, info, warn};
77

88
use crate::utils::{DevPath, DeviceFd};
99

10-
#[derive(Debug)]
10+
#[derive(Debug, PartialEq)]
1111
struct InternalDrmDeviceFd {
1212
fd: DeviceFd,
1313
privileged: bool,
@@ -33,7 +33,7 @@ impl BasicDevice for InternalDrmDeviceFd {}
3333
impl ControlDevice for InternalDrmDeviceFd {}
3434

3535
/// Ref-counted file descriptor of an open drm device
36-
#[derive(Debug, Clone)]
36+
#[derive(Debug, Clone, PartialEq)]
3737
pub struct DrmDeviceFd(Arc<InternalDrmDeviceFd>);
3838

3939
impl AsFd for DrmDeviceFd {

src/backend/renderer/sync/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ impl SyncPoint {
5858
}
5959
}
6060

61+
/// Returns `true` if `SyncPoint` contains a [`Fence`]
62+
pub fn contains_fence(&self) -> bool {
63+
self.fence.is_some()
64+
}
65+
6166
/// Get a reference to the underlying [`Fence`] if any
6267
///
6368
/// Returns `None` if the sync point does not contain a fence

src/backend/renderer/utils/wayland.rs

+40-14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(feature = "backend_drm")]
2+
use crate::wayland::drm_syncobj::{DrmSyncPoint, DrmSyncobjCachedState};
13
use crate::{
24
backend::renderer::{buffer_dimensions, buffer_has_alpha, element::RenderElement, ImportAll, Renderer},
35
utils::{Buffer as BufferCoord, Coordinate, Logical, Physical, Point, Rectangle, Scale, Size, Transform},
@@ -56,12 +58,24 @@ unsafe impl Send for RendererSurfaceState {}
5658
unsafe impl Sync for RendererSurfaceState {}
5759

5860
#[derive(Debug)]
59-
struct InnerBuffer(WlBuffer);
61+
struct InnerBuffer {
62+
buffer: WlBuffer,
63+
#[cfg(feature = "backend_drm")]
64+
acquire_point: Option<DrmSyncPoint>,
65+
#[cfg(feature = "backend_drm")]
66+
release_point: Option<DrmSyncPoint>,
67+
}
6068

6169
impl Drop for InnerBuffer {
6270
#[inline]
6371
fn drop(&mut self) {
64-
self.0.release();
72+
self.buffer.release();
73+
#[cfg(feature = "backend_drm")]
74+
if let Some(release_point) = &self.release_point {
75+
if let Err(err) = release_point.signal() {
76+
tracing::error!("Failed to signal syncobj release point: {}", err);
77+
}
78+
}
6579
}
6680
}
6781

@@ -71,12 +85,11 @@ pub struct Buffer {
7185
inner: Arc<InnerBuffer>,
7286
}
7387

74-
impl From<WlBuffer> for Buffer {
75-
#[inline]
76-
fn from(buffer: WlBuffer) -> Self {
77-
Buffer {
78-
inner: Arc::new(InnerBuffer(buffer)),
79-
}
88+
impl Buffer {
89+
#[cfg(feature = "backend_drm")]
90+
#[allow(dead_code)]
91+
pub(crate) fn acquire_point(&self) -> Option<&DrmSyncPoint> {
92+
self.inner.acquire_point.as_ref()
8093
}
8194
}
8295

@@ -85,29 +98,34 @@ impl std::ops::Deref for Buffer {
8598

8699
#[inline]
87100
fn deref(&self) -> &Self::Target {
88-
&self.inner.0
101+
&self.inner.buffer
89102
}
90103
}
91104

92105
impl PartialEq<WlBuffer> for Buffer {
93106
#[inline]
94107
fn eq(&self, other: &WlBuffer) -> bool {
95-
self.inner.0 == *other
108+
self.inner.buffer == *other
96109
}
97110
}
98111

99112
impl PartialEq<WlBuffer> for &Buffer {
100113
#[inline]
101114
fn eq(&self, other: &WlBuffer) -> bool {
102-
self.inner.0 == *other
115+
self.inner.buffer == *other
103116
}
104117
}
105118

106119
impl RendererSurfaceState {
107120
#[profiling::function]
108121
pub(crate) fn update_buffer(&mut self, states: &SurfaceData) {
109-
let mut attrs_state = states.cached_state.get::<SurfaceAttributes>();
110-
let attrs = attrs_state.current();
122+
#[cfg(feature = "backend_drm")]
123+
let mut guard = states.cached_state.get::<DrmSyncobjCachedState>();
124+
#[cfg(feature = "backend_drm")]
125+
let syncobj_state = guard.current();
126+
127+
let mut guard = states.cached_state.get::<SurfaceAttributes>();
128+
let attrs = guard.current();
111129
self.buffer_delta = attrs.buffer_delta.take();
112130

113131
if let Some(delta) = self.buffer_delta {
@@ -129,7 +147,15 @@ impl RendererSurfaceState {
129147
self.buffer_transform = attrs.buffer_transform.into();
130148

131149
if !self.buffer.as_ref().map_or(false, |b| b == buffer) {
132-
self.buffer = Some(Buffer::from(buffer));
150+
self.buffer = Some(Buffer {
151+
inner: Arc::new(InnerBuffer {
152+
buffer,
153+
#[cfg(feature = "backend_drm")]
154+
acquire_point: syncobj_state.acquire_point.take(),
155+
#[cfg(feature = "backend_drm")]
156+
release_point: syncobj_state.release_point.take(),
157+
}),
158+
});
133159
}
134160

135161
self.textures.clear();

src/wayland/compositor/tree.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#[cfg(feature = "backend_drm")]
2+
use crate::wayland::drm_syncobj::DrmSyncobjCachedState;
13
use crate::{utils::Serial, wayland::compositor::SUBSURFACE_ROLE};
24

35
use super::{
@@ -145,9 +147,25 @@ impl PrivateSurfaceData {
145147
if let Some(BufferAssignment::NewBuffer(buffer)) = guard.pending().buffer.take() {
146148
buffer.release();
147149
};
150+
drop(guard);
151+
#[cfg(feature = "backend_drm")]
152+
let mut guard = my_data.public_data.cached_state.get::<DrmSyncobjCachedState>();
153+
#[cfg(feature = "backend_drm")]
154+
if let Some(release_point) = &guard.pending().release_point {
155+
if let Err(err) = release_point.signal() {
156+
tracing::error!("Failed to signal syncobj release point: {}", err);
157+
}
158+
}
159+
#[cfg(feature = "backend_drm")]
160+
if let Some(release_point) = &guard.current().release_point {
161+
if let Err(err) = release_point.signal() {
162+
tracing::error!("Failed to signal syncobj release point: {}", err);
163+
}
164+
}
148165

149166
let hooks = my_data.destruction_hooks.clone();
150167
// don't hold the mutex while the hooks are invoked
168+
#[cfg(feature = "backend_drm")]
151169
drop(guard);
152170
drop(my_data);
153171
for hook in hooks {

0 commit comments

Comments
 (0)