Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wayland: implement zwp_linux_dmabuf v4 #80

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ fn start_compositor2(
default_keymap: xkb_keymap,
eng: engine.clone(),
render_ctx: Default::default(),
drm_feedback: Default::default(),
drm_feedback_consumers: Default::default(),
render_ctx_version: NumCell::new(1),
render_ctx_ever_initialized: Cell::new(false),
cursors: Default::default(),
Expand Down
58 changes: 58 additions & 0 deletions src/drm_feedback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use {
crate::{gfx_api::GfxContext, utils::oserror::OsError},
byteorder::{NativeEndian, WriteBytesExt},
std::{io::Write, rc::Rc},
thiserror::Error,
uapi::{c, OwnedFd},
};

pub struct DrmFeedback {
pub fd: Rc<OwnedFd>,
pub size: usize,
pub indices: Vec<u16>,
pub main_device: c::dev_t,
}

impl DrmFeedback {
pub fn new(ctx: &dyn GfxContext) -> Result<Self, DrmFeedbackError> {
let dev_t = uapi::fstat(ctx.gbm().drm.raw())
.map_err(OsError::from)?
.st_rdev;
let data = create_fd_data(ctx);
let mut memfd =
uapi::memfd_create("drm_feedback", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
memfd.write_all(&data).unwrap();
uapi::lseek(memfd.raw(), 0, c::SEEK_SET).unwrap();
uapi::fcntl_add_seals(
memfd.raw(),
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
)
.unwrap();
let num_indices = data.len() / 16;
let indices = (0..num_indices).map(|v| v as u16).collect();
Ok(Self {
fd: Rc::new(memfd),
size: data.len(),
indices,
main_device: dev_t,
})
}
}

fn create_fd_data(ctx: &dyn GfxContext) -> Vec<u8> {
let mut vec = vec![];
for (format, info) in &*ctx.formats() {
for modifier in info.modifiers.keys() {
vec.write_u32::<NativeEndian>(*format).unwrap();
vec.write_u32::<NativeEndian>(0).unwrap();
vec.write_u64::<NativeEndian>(*modifier).unwrap();
}
}
vec
}

#[derive(Debug, Error)]
pub enum DrmFeedbackError {
#[error("Could not stat drm device")]
Stat(#[from] OsError),
}
1 change: 1 addition & 0 deletions src/ifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub mod zwlr_screencopy_frame_v1;
pub mod zwlr_screencopy_manager_v1;
pub mod zwp_idle_inhibit_manager_v1;
pub mod zwp_linux_buffer_params_v1;
pub mod zwp_linux_dmabuf_feedback_v1;
pub mod zwp_linux_dmabuf_v1;
pub mod zxdg_decoration_manager_v1;
pub mod zxdg_output_manager_v1;
Expand Down
124 changes: 124 additions & 0 deletions src/ifs/zwp_linux_dmabuf_feedback_v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use {
crate::{
client::{Client, ClientError},
drm_feedback::DrmFeedback,
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwp_linux_dmabuf_feedback_v1::*, ZwpLinuxDmabufFeedbackV1Id},
},
std::rc::Rc,
thiserror::Error,
uapi::{c, OwnedFd},
};

#[allow(dead_code)]
pub const SCANOUT: u32 = 1;

pub struct ZwpLinuxDmabufFeedbackV1 {
pub id: ZwpLinuxDmabufFeedbackV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
}

impl ZwpLinuxDmabufFeedbackV1 {
pub fn new(id: ZwpLinuxDmabufFeedbackV1Id, client: &Rc<Client>) -> Self {
Self {
id,
client: client.clone(),
tracker: Default::default(),
}
}

pub fn send_feedback(&self, feedback: &DrmFeedback) {
self.send_format_table(&feedback.fd, feedback.size);
self.send_main_device(feedback.main_device);
self.send_tranche_target_device(feedback.main_device);
self.send_tranche_formats(&feedback.indices);
self.send_tranche_flags(0);
self.send_tranche_done();
self.send_done();
}

fn send_done(&self) {
self.client.event(Done { self_id: self.id });
}

fn send_format_table(&self, fd: &Rc<OwnedFd>, size: usize) {
self.client.event(FormatTable {
self_id: self.id,
fd: fd.clone(),
size: size as _,
});
}

fn send_main_device(&self, dev: c::dev_t) {
self.client.event(MainDevice {
self_id: self.id,
device: dev,
});
}

fn send_tranche_done(&self) {
self.client.event(TrancheDone { self_id: self.id });
}

fn send_tranche_target_device(&self, dev: c::dev_t) {
self.client.event(TrancheTargetDevice {
self_id: self.id,
device: dev,
});
}

fn send_tranche_formats(&self, indices: &[u16]) {
self.client.event(TrancheFormats {
self_id: self.id,
indices,
});
}

fn send_tranche_flags(&self, flags: u32) {
self.client.event(TrancheFlags {
self_id: self.id,
flags,
});
}

fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpLinuxDmabufFeedbackV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.detach();
self.client.remove_obj(self)?;
Ok(())
}

fn detach(&self) {
self.client
.state
.drm_feedback_consumers
.remove(&(self.client.id, self.id));
}
}

object_base! {
self = ZwpLinuxDmabufFeedbackV1;

DESTROY => destroy,
}

impl Object for ZwpLinuxDmabufFeedbackV1 {
fn break_loops(&self) {
self.detach();
}
}

simple_add_obj!(ZwpLinuxDmabufFeedbackV1);

#[derive(Debug, Error)]
pub enum ZwpLinuxDmabufFeedbackV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
}
efrom!(ZwpLinuxDmabufFeedbackV1Error, ClientError);
efrom!(ZwpLinuxDmabufFeedbackV1Error, MsgParserError);
72 changes: 57 additions & 15 deletions src/ifs/zwp_linux_dmabuf_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1,
ifs::{
zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id},
wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufFeedbackV1Id, ZwpLinuxDmabufV1Id},
},
std::rc::Rc,
thiserror::Error,
Expand Down Expand Up @@ -35,19 +38,21 @@ impl ZwpLinuxDmabufV1Global {
});
track!(client, obj);
client.add_client_obj(&obj)?;
if let Some(ctx) = client.state.render_ctx.get() {
let formats = ctx.formats();
for format in formats.values() {
if format.implicit_external_only && !ctx.supports_external_texture() {
continue;
}
obj.send_format(format.format.drm);
if version >= MODIFIERS_SINCE_VERSION {
for modifier in format.modifiers.values() {
if modifier.external_only && !ctx.supports_external_texture() {
continue;
if version < FEEDBACK_SINCE_VERSION {
if let Some(ctx) = client.state.render_ctx.get() {
let formats = ctx.formats();
for format in formats.values() {
if format.implicit_external_only && !ctx.supports_external_texture() {
continue;
}
obj.send_format(format.format.drm);
if version >= MODIFIERS_SINCE_VERSION {
for modifier in format.modifiers.values() {
if modifier.external_only && !ctx.supports_external_texture() {
continue;
}
obj.send_modifier(format.format.drm, modifier.modifier);
}
obj.send_modifier(format.format.drm, modifier.modifier);
}
}
}
Expand All @@ -57,6 +62,7 @@ impl ZwpLinuxDmabufV1Global {
}

const MODIFIERS_SINCE_VERSION: u32 = 3;
const FEEDBACK_SINCE_VERSION: u32 = 4;

global_base!(
ZwpLinuxDmabufV1Global,
Expand All @@ -70,7 +76,7 @@ impl Global for ZwpLinuxDmabufV1Global {
}

fn version(&self) -> u32 {
3
5
}
}

Expand Down Expand Up @@ -116,13 +122,49 @@ impl ZwpLinuxDmabufV1 {
self.client.add_client_obj(&params)?;
Ok(())
}

fn get_feedback(
self: &Rc<Self>,
id: ZwpLinuxDmabufFeedbackV1Id,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let fb = Rc::new(ZwpLinuxDmabufFeedbackV1::new(id, &self.client));
track!(self.client, fb);
self.client.add_client_obj(&fb)?;
self.client
.state
.drm_feedback_consumers
.set((self.client.id, id), fb.clone());
if let Some(feedback) = self.client.state.drm_feedback.get() {
fb.send_feedback(&feedback);
}
Ok(())
}

fn get_default_feedback(
self: &Rc<Self>,
parser: MsgParser<'_, '_>,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let req: GetDefaultFeedback = self.client.parse(&**self, parser)?;
self.get_feedback(req.id)
}

fn get_surface_feedback(
self: &Rc<Self>,
parser: MsgParser<'_, '_>,
) -> Result<(), ZwpLinuxDmabufV1Error> {
let req: GetSurfaceFeedback = self.client.parse(&**self, parser)?;
let _surface = self.client.lookup(req.surface)?;
self.get_feedback(req.id)
}
}

object_base! {
self = ZwpLinuxDmabufV1;

DESTROY => destroy,
CREATE_PARAMS => create_params,
GET_DEFAULT_FEEDBACK => get_default_feedback if self.version >= 4,
GET_SURFACE_FEEDBACK => get_surface_feedback if self.version >= 4,
}

impl Object for ZwpLinuxDmabufV1 {}
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod compositor;
mod config;
mod cursor;
mod dbus;
mod drm_feedback;
mod edid;
mod fixed;
mod forker;
Expand Down
26 changes: 25 additions & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use {
config::ConfigProxy,
cursor::{Cursor, ServerCursors},
dbus::Dbus,
drm_feedback::DrmFeedback,
forker::ForkerProxy,
gfx_api::GfxContext,
globals::{Globals, GlobalsError, WaylandGlobal},
Expand All @@ -26,6 +27,7 @@ use {
zwp_idle_inhibitor_v1::{IdleInhibitorId, IdleInhibitorIds, ZwpIdleInhibitorV1},
NoneSurfaceExt, WlSurface,
},
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global,
},
io_uring::IoUring,
Expand All @@ -44,7 +46,9 @@ use {
queue::AsyncQueue, refcounted::RefCounted, run_toplevel::RunToplevel,
},
wheel::Wheel,
wire::{JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId},
wire::{
JayRenderCtxId, JaySeatEventsId, JayWorkspaceWatcherId, ZwpLinuxDmabufFeedbackV1Id,
},
xkbcommon::{XkbContext, XkbKeymap},
xwayland::{self, XWaylandEvent},
},
Expand All @@ -70,6 +74,9 @@ pub struct State {
pub default_keymap: Rc<XkbKeymap>,
pub eng: Rc<AsyncEngine>,
pub render_ctx: CloneCell<Option<Rc<dyn GfxContext>>>,
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
pub drm_feedback_consumers:
CopyHashMap<(ClientId, ZwpLinuxDmabufFeedbackV1Id), Rc<ZwpLinuxDmabufFeedbackV1>>,
pub render_ctx_version: NumCell<u32>,
pub render_ctx_ever_initialized: Cell<bool>,
pub cursors: CloneCell<Option<Rc<ServerCursors>>>,
Expand Down Expand Up @@ -309,6 +316,23 @@ impl State {
self.render_ctx.set(ctx.clone());
self.render_ctx_version.fetch_add(1);
self.cursors.set(None);
self.drm_feedback.set(None);

'handle_new_feedback: {
if let Some(ctx) = &ctx {
let feedback = match DrmFeedback::new(&**ctx) {
Ok(fb) => fb,
Err(e) => {
log::error!("Could not create new DRM feedback: {}", ErrorFmt(e));
break 'handle_new_feedback;
}
};
for watcher in self.drm_feedback_consumers.lock().values() {
watcher.send_feedback(&feedback);
}
self.drm_feedback.set(Some(Rc::new(feedback)));
}
}

{
struct Walker;
Expand Down
Loading