From 5a4e48e54a4a4ca1fd0c67dfbe9d2def963a0d80 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 30 Jul 2022 11:40:15 +0200 Subject: [PATCH] wayland: add jay_screencast --- src/backends/metal/video.rs | 2 +- src/backends/x.rs | 2 +- src/client/objects.rs | 10 +- src/compositor.rs | 1 + src/ifs.rs | 1 + src/ifs/jay_compositor.rs | 16 +- src/ifs/jay_screencast.rs | 452 ++++++++++++++++++++++++++++++++++++ src/state.rs | 10 + src/tasks/connector.rs | 5 + src/tree/output.rs | 34 ++- src/utils.rs | 1 + src/utils/option_ext.rs | 9 + wire/jay_compositor.txt | 4 + wire/jay_screencast.txt | 99 ++++++++ 14 files changed, 635 insertions(+), 11 deletions(-) create mode 100644 src/ifs/jay_screencast.rs create mode 100644 src/utils/option_ext.rs create mode 100644 wire/jay_screencast.txt diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 92e7a0df..4c4ed3a5 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -359,7 +359,7 @@ impl MetalConnector { fr.send_done(); let _ = fr.client.remove_obj(&*fr); } - node.global.perform_screencopies(&buffer.fb, &buffer.tex); + node.perform_screencopies(&buffer.fb, &buffer.tex); } changes.change_object(plane.id, |c| { c.change(plane.fb_id, buffer.drm.id().0 as _); diff --git a/src/backends/x.rs b/src/backends/x.rs index 4a600f79..87d47416 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -706,7 +706,7 @@ impl XBackend { fr.send_done(); let _ = fr.client.remove_obj(&*fr); } - node.global.perform_screencopies(&fb, &image.tex.get()); + node.perform_screencopies(&fb, &image.tex.get()); } let pp = PresentPixmap { diff --git a/src/client/objects.rs b/src/client/objects.rs index 98d3c4cb..30375f2e 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -7,6 +7,7 @@ use { zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, }, jay_output::JayOutput, + jay_screencast::JayScreencast, jay_workspace::JayWorkspace, wl_buffer::WlBuffer, wl_display::WlDisplay, @@ -27,9 +28,9 @@ use { copyhashmap::{CopyHashMap, Locked}, }, wire::{ - JayOutputId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, - WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, XdgSurfaceId, - XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id, + JayOutputId, JayScreencastId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, + WlPointerId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, + XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id, }, }, std::{cell::RefCell, mem, rc::Rc}, @@ -54,6 +55,7 @@ pub struct Objects { pub pointers: CopyHashMap>, pub xdg_wm_bases: CopyHashMap>, pub seats: CopyHashMap>, + pub screencasts: CopyHashMap>, ids: RefCell>, } @@ -80,6 +82,7 @@ impl Objects { pointers: Default::default(), xdg_wm_bases: Default::default(), seats: Default::default(), + screencasts: Default::default(), ids: RefCell::new(vec![]), } } @@ -110,6 +113,7 @@ impl Objects { self.xdg_wm_bases.clear(); self.seats.clear(); self.pointers.clear(); + self.screencasts.clear(); } pub fn id(&self, client_data: &Client) -> Result diff --git a/src/compositor.rs b/src/compositor.rs index 322feaeb..4427e8c1 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -390,6 +390,7 @@ fn create_dummy_output(state: &Rc) { lock_surface: Default::default(), preferred_scale: Cell::new(Fixed::from_int(1)), hardware_cursor: Default::default(), + screencasts: Default::default(), }); let dummy_workspace = Rc::new(WorkspaceNode { id: state.node_ids.next(), diff --git a/src/ifs.rs b/src/ifs.rs index bdc541a3..037856d6 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -7,6 +7,7 @@ pub mod jay_log_file; pub mod jay_output; pub mod jay_pointer; pub mod jay_render_ctx; +pub mod jay_screencast; pub mod jay_screenshot; pub mod jay_seat_events; pub mod jay_workspace; diff --git a/src/ifs/jay_compositor.rs b/src/ifs/jay_compositor.rs index 8f1094a5..87a446d6 100644 --- a/src/ifs/jay_compositor.rs +++ b/src/ifs/jay_compositor.rs @@ -5,8 +5,9 @@ use { globals::{Global, GlobalName}, ifs::{ jay_idle::JayIdle, jay_log_file::JayLogFile, jay_output::JayOutput, - jay_pointer::JayPointer, jay_render_ctx::JayRenderCtx, jay_screenshot::JayScreenshot, - jay_seat_events::JaySeatEvents, jay_workspace_watcher::JayWorkspaceWatcher, + jay_pointer::JayPointer, jay_render_ctx::JayRenderCtx, jay_screencast::JayScreencast, + jay_screenshot::JayScreenshot, jay_seat_events::JaySeatEvents, + jay_workspace_watcher::JayWorkspaceWatcher, }, leaks::Tracker, object::Object, @@ -298,6 +299,14 @@ impl JayCompositor { } Ok(()) } + + fn create_screencast(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> { + let req: CreateScreencast = self.client.parse(self, parser)?; + let sc = Rc::new(JayScreencast::new(req.id, &self.client)); + track!(self.client, sc); + self.client.add_client_obj(&sc)?; + Ok(()) + } } object_base! { @@ -318,11 +327,12 @@ object_base! { GET_POINTER => get_pointer, GET_RENDER_CTX => get_render_ctx, WATCH_WORKSPACES => watch_workspaces, + CREATE_SCREENCAST => create_screencast, } impl Object for JayCompositor { fn num_requests(&self) -> u32 { - WATCH_WORKSPACES + 1 + CREATE_SCREENCAST + 1 } } diff --git a/src/ifs/jay_screencast.rs b/src/ifs/jay_screencast.rs new file mode 100644 index 00000000..7b32c42a --- /dev/null +++ b/src/ifs/jay_screencast.rs @@ -0,0 +1,452 @@ +use { + crate::{ + client::{Client, ClientError}, + format::XRGB8888, + ifs::jay_output::JayOutput, + leaks::Tracker, + object::Object, + render::{Framebuffer, RenderContext, RenderError, Texture}, + tree::{OutputNode, WorkspaceNodeId}, + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + errorfmt::ErrorFmt, + numcell::NumCell, + option_ext::OptionExt, + }, + video::{ + dmabuf::DmaBuf, + gbm::{GbmError, GBM_BO_USE_LINEAR, GBM_BO_USE_RENDERING}, + ModifiedFormat, INVALID_MODIFIER, + }, + wire::{jay_screencast::*, JayScreencastId}, + }, + ahash::AHashSet, + std::{ + cell::{Cell, RefCell}, + ops::{Deref, DerefMut}, + rc::Rc, + }, + thiserror::Error, +}; + +pub struct JayScreencast { + pub id: JayScreencastId, + pub client: Rc, + pub tracker: Tracker, + config_serial: NumCell, + config_acked: Cell, + buffers_serial: NumCell, + buffers_acked: Cell, + buffers: RefCell>, + missed_frame: Cell, + output: CloneCell>>, + destroyed: Cell, + running: Cell, + show_all: Cell, + show_workspaces: RefCell>, + linear: Cell, + pending: Pending, +} + +#[derive(Default)] +struct Pending { + linear: Cell>, + running: Cell>, + output: Cell>>>, + show_all: Cell>, + show_workspaces: RefCell>>, +} + +struct ScreencastBuffer { + dmabuf: DmaBuf, + fb: Rc, + free: bool, +} + +impl JayScreencast { + pub fn new(id: JayScreencastId, client: &Rc) -> Self { + Self { + id, + client: client.clone(), + tracker: Default::default(), + config_serial: Default::default(), + config_acked: Cell::new(true), + buffers_serial: Default::default(), + buffers_acked: Cell::new(false), + buffers: Default::default(), + missed_frame: Cell::new(false), + output: Default::default(), + destroyed: Cell::new(false), + running: Cell::new(false), + show_all: Cell::new(false), + show_workspaces: Default::default(), + linear: Cell::new(false), + pending: Default::default(), + } + } + + fn send_buffers(&self) { + self.buffers_acked.set(false); + let serial = self.buffers_serial.fetch_add(1) + 1; + let buffers = self.buffers.borrow_mut(); + for buffer in buffers.iter() { + for plane in &buffer.dmabuf.planes { + self.client.event(Plane { + self_id: self.id, + fd: plane.fd.clone(), + offset: plane.offset, + stride: plane.stride, + }); + } + self.client.event(Buffer { + self_id: self.id, + format: buffer.dmabuf.format.drm, + modifier: buffer.dmabuf.modifier, + width: buffer.dmabuf.width, + height: buffer.dmabuf.height, + }); + } + self.client.event(BuffersDone { + self_id: self.id, + serial, + }); + } + + #[allow(dead_code)] + fn send_config(&self) { + self.config_acked.set(false); + let serial = self.config_serial.fetch_add(1) + 1; + if let Some(output) = self.output.get() { + self.client.event(ConfigOutput { + self_id: self.id, + linear_id: output.id.raw(), + }); + } + self.client.event(ConfigAllowAllWorkspaces { + self_id: self.id, + allow_all: self.show_all.get() as _, + }); + for &ws in self.show_workspaces.borrow_mut().iter() { + self.client.event(ConfigAllowWorkspace { + self_id: self.id, + linear_id: ws.raw(), + }); + } + self.client.event(ConfigUseLinearBuffers { + self_id: self.id, + use_linear: self.linear.get() as _, + }); + self.client.event(ConfigRunning { + self_id: self.id, + running: self.running.get() as _, + }); + self.client.event(ConfigDone { + self_id: self.id, + serial, + }); + } + + pub fn copy_texture(&self, on: &OutputNode, texture: &Texture) { + if !self.running.get() { + return; + } + if !self.show_all.get() { + let ws = match on.workspace.get() { + Some(ws) => ws, + _ => return, + }; + if !self.show_workspaces.borrow_mut().contains(&ws.id) { + return; + } + } + let mut buffer = self.buffers.borrow_mut(); + for (idx, buffer) in buffer.deref_mut().iter_mut().enumerate() { + if buffer.free { + buffer.fb.copy_texture(&self.client.state, texture, 0, 0); + self.client.event(Ready { + self_id: self.id, + idx: idx as _, + }); + buffer.free = false; + return; + } + } + self.missed_frame.set(true); + self.client.event(MissedFrame { self_id: self.id }) + } + + fn detach(&self) { + if let Some(output) = self.output.take() { + output.screencasts.remove(&(self.client.id, self.id)); + } + } + + pub fn do_destroy(&self) { + self.detach(); + self.destroyed.set(true); + self.client.event(Destroyed { self_id: self.id }); + } + + pub fn realloc(&self, ctx: &Rc) -> Result<(), JayScreencastError> { + let mut buffers = vec![]; + if let Some(output) = self.output.get() { + let mode = output.global.mode.get(); + let num = 3; + for _ in 0..num { + let format = ModifiedFormat { + format: XRGB8888, + modifier: INVALID_MODIFIER, + }; + let mut flags = GBM_BO_USE_RENDERING; + if self.linear.get() { + flags |= GBM_BO_USE_LINEAR; + } + let buffer = ctx.gbm.create_bo(mode.width, mode.height, &format, flags)?; + let fb = ctx.dmabuf_img(buffer.dmabuf())?.to_framebuffer()?; + buffers.push(ScreencastBuffer { + dmabuf: buffer.dmabuf().clone(), + fb, + free: true, + }); + } + } + *self.buffers.borrow_mut() = buffers; + self.send_buffers(); + self.damage(); + Ok(()) + } + + fn damage(&self) { + if let Some(output) = self.output.get() { + output.global.connector.connector.damage(); + } + } +} + +impl JayScreencast { + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let _req: Destroy = self.client.parse(self, parser)?; + self.detach(); + self.client.remove_obj(self)?; + Ok(()) + } + + fn set_output(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: SetOutput = self.client.parse(self, parser)?; + let output = if req.output.is_some() { + Some(self.client.lookup(req.output)?) + } else { + None + }; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + self.pending.output.set(Some(output)); + Ok(()) + } + + fn set_allow_all_workspaces( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), JayScreencastError> { + let req: SetAllowAllWorkspaces = self.client.parse(self, parser)?; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + self.pending.show_all.set(Some(req.allow_all != 0)); + Ok(()) + } + + fn allow_workspace(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: AllowWorkspace = self.client.parse(self, parser)?; + let ws = self.client.lookup(req.workspace)?; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + let mut sw = self.pending.show_workspaces.borrow_mut(); + let sw = sw.get_or_insert_default_ext(); + if let Some(ws) = ws.workspace.get() { + sw.insert(ws.id); + } + Ok(()) + } + + fn touch_allowed_workspaces( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), JayScreencastError> { + let _req: TouchAllowedWorkspaces = self.client.parse(self, parser)?; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + self.pending + .show_workspaces + .borrow_mut() + .get_or_insert_default_ext(); + Ok(()) + } + + fn set_use_linear_buffers(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: SetUseLinearBuffers = self.client.parse(self, parser)?; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + self.pending.linear.set(Some(req.use_linear != 0)); + Ok(()) + } + + fn set_running(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: SetRunning = self.client.parse(self, parser)?; + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + self.pending.running.set(Some(req.running != 0)); + Ok(()) + } + + fn configure(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let _req: Configure = self.client.parse(self.deref(), parser)?; + + if self.destroyed.get() || !self.config_acked.get() { + return Ok(()); + } + + let mut need_realloc = false; + + if let Some(output) = self.pending.output.take() { + let output = output.and_then(|o| o.output.get()); + if output_size(&output) != output_size(&self.output.get()) { + need_realloc = true; + } + self.detach(); + if let Some(new) = &output { + new.screencasts.set((self.client.id, self.id), self.clone()); + } + self.output.set(output); + } + if let Some(linear) = self.pending.linear.take() { + if self.linear.replace(linear) != linear { + need_realloc = true; + } + } + if let Some(show_all) = self.pending.show_all.take() { + self.show_all.set(show_all); + } + if let Some(new_workspaces) = self.pending.show_workspaces.borrow_mut().take() { + *self.show_workspaces.borrow_mut() = new_workspaces; + } + if let Some(running) = self.pending.running.take() { + self.running.set(running); + } + + if need_realloc { + let ctx = match self.client.state.render_ctx.get() { + Some(ctx) => ctx, + _ => { + self.do_destroy(); + return Ok(()); + } + }; + if let Err(e) = self.realloc(&ctx) { + log::error!("Could not allocate buffers: {}", ErrorFmt(e)); + self.do_destroy(); + return Ok(()); + } + } + + Ok(()) + } + + fn ack_buffers(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: AckBuffers = self.client.parse(self, parser)?; + if self.destroyed.get() { + return Ok(()); + } + if req.serial == self.buffers_serial.get() { + self.buffers_acked.set(true); + } + Ok(()) + } + + fn ack_config(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: AckConfig = self.client.parse(self, parser)?; + if self.destroyed.get() { + return Ok(()); + } + if req.serial == self.config_serial.get() { + self.config_acked.set(true); + } + Ok(()) + } + + fn release_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), JayScreencastError> { + let req: ReleaseBuffer = self.client.parse(self, parser)?; + if self.destroyed.get() || !self.buffers_acked.get() { + return Ok(()); + } + let idx = req.idx as usize; + if idx > self.buffers.borrow_mut().len() { + return Err(JayScreencastError::OutOfBounds(req.idx)); + } + self.buffers.borrow_mut()[idx].free = true; + if self.missed_frame.replace(false) { + self.damage(); + } + Ok(()) + } +} + +object_base! { + JayScreencast; + + DESTROY => destroy, + SET_OUTPUT => set_output, + SET_ALLOW_ALL_WORKSPACES => set_allow_all_workspaces, + ALLOW_WORKSPACE => allow_workspace, + TOUCH_ALLOWED_WORKSPACES => touch_allowed_workspaces, + SET_USE_LINEAR_BUFFERS => set_use_linear_buffers, + SET_RUNNING => set_running, + CONFIGURE => configure, + ACK_CONFIG => ack_config, + ACK_BUFFERS => ack_buffers, + RELEASE_BUFFER => release_buffer, +} + +impl Object for JayScreencast { + fn num_requests(&self) -> u32 { + RELEASE_BUFFER + 1 + } + + fn break_loops(&self) { + self.detach(); + } +} + +dedicated_add_obj!(JayScreencast, JayScreencastId, screencasts); + +#[derive(Debug, Error)] +pub enum JayScreencastError { + #[error("Parsing failed")] + MsgParserError(Box), + #[error(transparent)] + ClientError(Box), + #[error("Buffer index {0} is out-of-bounds")] + OutOfBounds(u32), + #[error(transparent)] + GbmError(#[from] GbmError), + #[error(transparent)] + RenderError(#[from] RenderError), +} +efrom!(JayScreencastError, MsgParserError); +efrom!(JayScreencastError, ClientError); + +fn output_size(output: &Option>) -> (i32, i32) { + match output { + Some(o) => { + let mode = o.global.mode.get(); + (mode.width, mode.height) + } + _ => (0, 0), + } +} diff --git a/src/state.rs b/src/state.rs index 32fb7283..2b93123b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -328,6 +328,16 @@ impl State { for watcher in self.render_ctx_watchers.lock().values() { watcher.send_render_ctx(ctx); } + + let mut scs = vec![]; + for client in self.clients.clients.borrow_mut().values() { + for sc in client.data.objects.screencasts.lock().values() { + scs.push(sc.clone()); + } + } + for sc in scs { + sc.do_destroy(); + } } fn reload_cursors(&self) { diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index 17344f86..122c13a7 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -125,6 +125,7 @@ impl ConnectorHandler { preferred_scale: Cell::new(Fixed::from_int(1)), hardware_cursor: Default::default(), jay_outputs: Default::default(), + screencasts: Default::default(), }); self.state.add_output_scale(on.preferred_scale.get()); let mode = info.initial_mode; @@ -217,6 +218,10 @@ impl ConnectorHandler { jo.send_destroyed(); jo.output.take(); } + let screencasts: Vec<_> = on.screencasts.lock().values().cloned().collect(); + for sc in screencasts { + sc.do_destroy(); + } global.destroyed.set(true); self.state.root.outputs.remove(&self.id); self.data.connected.set(false); diff --git a/src/tree/output.rs b/src/tree/output.rs index 274a2e1d..d1d6cdf9 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -6,6 +6,7 @@ use { fixed::Fixed, ifs::{ jay_output::JayOutput, + jay_screencast::JayScreencast, wl_output::WlOutputGlobal, wl_seat::{ collect_kb_foci2, wl_pointer::PendingScroll, NodeSeatState, SeatId, WlSeatGlobal, @@ -18,7 +19,7 @@ use { zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP}, }, rect::Rect, - render::{Renderer, Texture}, + render::{Framebuffer, Renderer, Texture}, state::State, text, tree::{ @@ -28,7 +29,7 @@ use { clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, linkedlist::LinkedList, scroller::Scroller, }, - wire::JayOutputId, + wire::{JayOutputId, JayScreencastId}, }, ahash::AHashMap, smallvec::SmallVec, @@ -58,9 +59,17 @@ pub struct OutputNode { pub lock_surface: CloneCell>>, pub preferred_scale: Cell, pub hardware_cursor: CloneCell>>, + pub screencasts: CopyHashMap<(ClientId, JayScreencastId), Rc>, } impl OutputNode { + pub fn perform_screencopies(&self, fb: &Framebuffer, tex: &Texture) { + self.global.perform_screencopies(fb, tex); + for sc in self.screencasts.lock().values() { + sc.copy_texture(self, tex); + } + } + pub fn clear(&self) { self.global.clear(); self.workspace.set(None); @@ -337,12 +346,31 @@ impl OutputNode { } pub fn update_mode(&self, mode: Mode) { - if self.global.mode.get() == mode { + let old_mode = self.global.mode.get(); + if old_mode == mode { return; } self.global.mode.set(mode); let rect = self.calculate_extents(); self.change_extents_(&rect); + + if (old_mode.width, old_mode.height) != (mode.width, mode.height) { + let mut to_destroy = vec![]; + if let Some(ctx) = self.state.render_ctx.get() { + for sc in self.screencasts.lock().values() { + if let Err(e) = sc.realloc(&ctx) { + log::error!( + "Could not re-allocate buffers for screencast after mode change: {}", + ErrorFmt(e) + ); + to_destroy.push(sc.clone()); + } + } + } + for sc in to_destroy { + sc.do_destroy(); + } + } } fn calculate_extents(&self) -> Rect { diff --git a/src/utils.rs b/src/utils.rs index e851cf03..6e2a3aac 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,6 +18,7 @@ pub mod nonblock; pub mod num_cpus; pub mod numcell; pub mod once; +pub mod option_ext; pub mod oserror; pub mod ptr_ext; pub mod queue; diff --git a/src/utils/option_ext.rs b/src/utils/option_ext.rs new file mode 100644 index 00000000..c6bc7632 --- /dev/null +++ b/src/utils/option_ext.rs @@ -0,0 +1,9 @@ +pub trait OptionExt { + fn get_or_insert_default_ext(&mut self) -> &mut T; +} + +impl OptionExt for Option { + fn get_or_insert_default_ext(&mut self) -> &mut T { + self.get_or_insert_with(|| Default::default()) + } +} diff --git a/wire/jay_compositor.txt b/wire/jay_compositor.txt index 1e4f318a..f51335be 100644 --- a/wire/jay_compositor.txt +++ b/wire/jay_compositor.txt @@ -61,6 +61,10 @@ msg watch_workspaces = 14 { id: id(jay_workspace_watcher), } +msg create_screencast = 15 { + id: id(jay_screencast), +} + # events msg client_id = 0 { diff --git a/wire/jay_screencast.txt b/wire/jay_screencast.txt new file mode 100644 index 00000000..de1afe3d --- /dev/null +++ b/wire/jay_screencast.txt @@ -0,0 +1,99 @@ +# requests + +msg destroy = 0 { + +} + +msg set_output = 1 { + output: id(jay_output), +} + +msg set_allow_all_workspaces = 2 { + allow_all: u32, +} + +msg allow_workspace = 3 { + workspace: id(jay_workspace), +} + +msg touch_allowed_workspaces = 4 { +} + +msg set_use_linear_buffers = 5 { + use_linear: u32, +} + +msg set_running = 6 { + running: u32, +} + +msg configure = 7 { + +} + +msg ack_buffers = 8 { + serial: u32, +} + +msg ack_config = 9 { + serial: u32, +} + +msg release_buffer = 10 { + idx: u32, +} + +# events + +msg plane = 0 { + fd: fd, + offset: u32, + stride: u32, +} + +msg buffer = 1 { + format: u32, + modifier: pod(u64), + width: i32, + height: i32, +} + +msg buffers_done = 2 { + serial: u32, +} + +msg ready = 3 { + idx: u32, +} + +msg destroyed = 4 { + +} + +msg missed_frame = 5 { + +} + +msg config_output = 6 { + linear_id: u32, +} + +msg config_allow_all_workspaces = 7 { + allow_all: u32, +} + +msg config_allow_workspace = 8 { + linear_id: u32, +} + +msg config_use_linear_buffers = 9 { + use_linear: u32, +} + +msg config_running = 10 { + running: u32, +} + +msg config_done = 11 { + serial: u32, +}