Skip to content

Commit

Permalink
WIP linux-drm-syncobj-v1
Browse files Browse the repository at this point in the history
  • Loading branch information
ids1024 committed Apr 8, 2024
1 parent e58193b commit b732491
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 12 deletions.
22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ smallvec = "1.11"
pixman = { version = "0.1.0", features = ["drm-fourcc"], optional = true }

[patch.crates-io]
wayland-egl = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2"}
wayland-protocols = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-protocols-wlr = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-protocols-misc = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-server = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-client = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-sys = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-backend = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-scanner = { git = "https://github.com/PolyMeilex/wayland-rs.git", branch = "new-delegate-v2" }
wayland-egl = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-protocols = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-protocols-wlr = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-protocols-misc = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-server = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-client = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-sys = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-backend = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
wayland-scanner = { git = "https://github.com/ids1024/wayland-rs", branch = "drm-syncobj" }
# wayland-egl = { path = "../wayland-rs/wayland-egl/" }
# wayland-protocols = { path = "../wayland-rs/wayland-protocols/" }
# wayland-protocols-wlr = { path = "../wayland-rs/wayland-protocols-wlr/" }
Expand All @@ -102,7 +102,7 @@ pkg-config = { version = "0.3.17", optional = true }
cc = { version = "1.0.79", optional = true }

[features]
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"]
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
backend_winit = ["winit", "backend_egl", "wayland-egl", "renderer_gl"]
backend_x11 = ["x11rb", "x11rb/dri3", "x11rb/xfixes", "x11rb/present", "x11rb_event_source", "backend_gbm", "backend_drm", "backend_egl"]
backend_drm = ["drm", "drm-ffi"]
Expand Down Expand Up @@ -154,4 +154,4 @@ harness = false

[profile.release-with-debug]
inherits = "release"
debug = true
debug = true
2 changes: 1 addition & 1 deletion anvil/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ gl_generator = "0.14"

[features]
debug = ["fps_ticker", "image/png", "renderdoc"]
default = ["egl", "winit", "x11", "udev", "xwayland"]
default = ["egl", "x11", "udev", "xwayland"] # XXX
egl = ["smithay/use_system_lib", "smithay/backend_egl"]
test_all_features = ["default", "debug"]
udev = [
Expand Down
2 changes: 2 additions & 0 deletions anvil/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use smithay::{
wayland::{
compositor::{get_parent, with_states, CompositorClientState, CompositorState},
dmabuf::DmabufFeedback,
drm_syncobj::DrmSyncobjState,
fractional_scale::{with_fractional_scale, FractionalScaleHandler, FractionalScaleManagerState},
input_method::{InputMethodHandler, InputMethodManagerState, PopupSurface},
keyboard_shortcuts_inhibit::{
Expand Down Expand Up @@ -547,6 +548,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
.get_data::<ClientState>()
.map_or(true, |client_state| client_state.security_context.is_none())
});
DrmSyncobjState::new::<Self>(&dh);

// init input
let seat_name = backend_data.seat_name();
Expand Down
239 changes: 239 additions & 0 deletions src/wayland/drm_syncobj/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
use std::{cell::RefCell, os::unix::io::OwnedFd, sync::Arc};
use wayland_protocols::wp::linux_drm_syncobj::v1::server::{
wp_linux_drm_syncobj_manager_v1::{self, WpLinuxDrmSyncobjManagerV1},
wp_linux_drm_syncobj_surface_v1::{self, WpLinuxDrmSyncobjSurfaceV1},
wp_linux_drm_syncobj_timeline_v1::{self, WpLinuxDrmSyncobjTimelineV1},
};
use wayland_server::{
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New,
Resource, Weak,
};

use super::compositor::{self, with_states, BufferAssignment, Cacheable, SurfaceAttributes};

#[derive(Clone)]
struct SyncPoint {
fd: Arc<OwnedFd>,
point: u64,
}

#[derive(Default)]
struct DrmSyncobjCachedState {
acquire_point: Option<SyncPoint>,
release_point: Option<SyncPoint>,
}

impl Cacheable for DrmSyncobjCachedState {
fn commit(&mut self, _dh: &DisplayHandle) -> Self {
Self {
acquire_point: None,
release_point: None,
}
}

fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) {
if self.acquire_point.is_some() && self.release_point.is_some() {
into.acquire_point = self.acquire_point;
into.release_point = self.release_point;
} else {
into.acquire_point = None;
into.release_point = None;
}
}
}

pub struct DrmSyncobjState {}

impl DrmSyncobjState {
pub fn new<D: 'static>(display: &DisplayHandle) -> Self {
display.create_delegated_global::<D, WpLinuxDrmSyncobjManagerV1, _, Self>(1, ());
Self {}
}

// TODO new_with_filter
}

impl<D> GlobalDispatch<WpLinuxDrmSyncobjManagerV1, (), D> for DrmSyncobjState {
fn bind(
state: &mut D,
dh: &DisplayHandle,
client: &Client,
resource: New<WpLinuxDrmSyncobjManagerV1>,
_global_data: &(),
data_init: &mut DataInit<'_, D>,
) {
data_init.init_delegated::<_, _, Self>(resource, ());
}
}

fn commit_hook<D>(_: &mut D, _dh: &DisplayHandle, surface: &WlSurface) {
compositor::with_states(&surface, |states| {
let cached = &states.cached_state;
let has_new_buffer = matches!(
cached.pending::<SurfaceAttributes>().buffer,
Some(BufferAssignment::NewBuffer(_))
);
// TODO what if syncobj surface is destroyed?
if let Some(data) = states
.data_map
.get::<RefCell<Option<WpLinuxDrmSyncobjSurfaceV1>>>()
{
if let Some(syncobj_surface) = data.borrow().as_ref() {
let pending = cached.pending::<DrmSyncobjCachedState>();
if pending.acquire_point.is_some() && !has_new_buffer {
syncobj_surface.post_error(
wp_linux_drm_syncobj_surface_v1::Error::NoBuffer as u32,
"acquire point without buffer".to_string(),
);
} else if pending.acquire_point.is_some() && pending.release_point.is_none() {
syncobj_surface.post_error(
wp_linux_drm_syncobj_surface_v1::Error::NoReleasePoint as u32,
"acquire point without release point".to_string(),
);
} else if pending.acquire_point.is_none() && pending.release_point.is_some() {
syncobj_surface.post_error(
wp_linux_drm_syncobj_surface_v1::Error::NoAcquirePoint as u32,
"release point without acquire point".to_string(),
);
} else if let (Some(acquire), Some(release)) =
(pending.acquire_point.as_ref(), pending.release_point.as_ref())
{
if Arc::ptr_eq(&acquire.fd, &release.fd) && acquire.point <= release.point {
syncobj_surface.post_error(
wp_linux_drm_syncobj_surface_v1::Error::ConflictingPoints as u32,
format!(
"release point '{}' is not greater than acquire point '{}'",
release.point, acquire.point
),
);
}
}
// TODO unsupported buffer error
}
}
});
}

impl<D> Dispatch<WpLinuxDrmSyncobjManagerV1, (), D> for DrmSyncobjState {
fn request(
state: &mut D,
_client: &Client,
resource: &WpLinuxDrmSyncobjManagerV1,
request: wp_linux_drm_syncobj_manager_v1::Request,
_data: &(),
_dh: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
wp_linux_drm_syncobj_manager_v1::Request::GetSurface { id, surface } => {
let already_exists = with_states(&surface, |states| {
states
.data_map
.get::<RefCell<Option<WpLinuxDrmSyncobjSurfaceV1>>>()
.map(|v| v.borrow().is_some())
.unwrap_or(false)
});
if already_exists {
resource.post_error(
wp_linux_drm_syncobj_manager_v1::Error::SurfaceExists as u32,
"the surface already has a syncobj_surface object associated".to_string(),
);
return;
}
let syncobj_surface = data_init.init_delegated::<_, _, Self>(
id,
DrmSyncobjSurfaceData {
surface: surface.downgrade(),
},
);
with_states(&surface, |states| {
states
.data_map
.insert_if_missing(|| RefCell::new(Some(syncobj_surface)))
});
compositor::add_pre_commit_hook::<D, _>(&surface, commit_hook);
}
wp_linux_drm_syncobj_manager_v1::Request::ImportTimeline { id, fd } => {
data_init.init_delegated::<_, _, Self>(id, DrmSyncobjTimelineData { fd: Arc::new(fd) });
// TODO import, protocol error if it fails? On which GPU?
}
wp_linux_drm_syncobj_manager_v1::Request::Destroy => {}
_ => unreachable!(),
}
}
}

struct DrmSyncobjSurfaceData {
surface: Weak<WlSurface>,
}

impl<D> Dispatch<WpLinuxDrmSyncobjSurfaceV1, DrmSyncobjSurfaceData, D> for DrmSyncobjState {
fn request(
state: &mut D,
_client: &Client,
_resource: &WpLinuxDrmSyncobjSurfaceV1,
request: wp_linux_drm_syncobj_surface_v1::Request,
data: &DrmSyncobjSurfaceData,
_dh: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
let Ok(surface) = data.surface.upgrade() else {
return;
};
match request {
wp_linux_drm_syncobj_surface_v1::Request::Destroy => {
// TODO
}
wp_linux_drm_syncobj_surface_v1::Request::SetAcquirePoint {
timeline,
point_hi,
point_lo,
} => {
let sync_point = SyncPoint {
fd: timeline.data::<DrmSyncobjTimelineData>().unwrap().fd.clone(),
point: ((point_hi as u64) << 32) + (point_lo as u64),
};
with_states(&surface, |states| {
let mut cached_state = states.cached_state.pending::<DrmSyncobjCachedState>();
cached_state.acquire_point = Some(sync_point);
});
}
wp_linux_drm_syncobj_surface_v1::Request::SetReleasePoint {
timeline,
point_hi,
point_lo,
} => {
let sync_point = SyncPoint {
fd: timeline.data::<DrmSyncobjTimelineData>().unwrap().fd.clone(),
point: ((point_hi as u64) << 32) + (point_lo as u64),
};
with_states(&surface, |states| {
let mut cached_state = states.cached_state.pending::<DrmSyncobjCachedState>();
cached_state.release_point = Some(sync_point);
});
}
_ => unreachable!(),
}
}
}

struct DrmSyncobjTimelineData {
fd: Arc<OwnedFd>,
}

impl<D> Dispatch<WpLinuxDrmSyncobjTimelineV1, DrmSyncobjTimelineData, D> for DrmSyncobjState {
fn request(
state: &mut D,
_client: &Client,
_resource: &WpLinuxDrmSyncobjTimelineV1,
request: wp_linux_drm_syncobj_timeline_v1::Request,
_data: &DrmSyncobjTimelineData,
_dh: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
wp_linux_drm_syncobj_timeline_v1::Request::Destroy => {}
_ => unreachable!(),
}
}
}
2 changes: 2 additions & 0 deletions src/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub mod cursor_shape;
pub mod dmabuf;
#[cfg(feature = "backend_drm")]
pub mod drm_lease;
#[cfg(feature = "backend_drm")]
pub mod drm_syncobj;
pub mod fractional_scale;
pub mod idle_inhibit;
pub mod idle_notify;
Expand Down

0 comments on commit b732491

Please sign in to comment.