1
0
Fork 0
forked from wry/wry

screencast: implement format negotation

This commit is contained in:
Julian Orth 2024-09-04 12:03:42 +02:00
parent 8d2bd6f660
commit e7c63fd09a
19 changed files with 649 additions and 201 deletions

View file

@ -70,7 +70,7 @@ impl Global for JayCompositorGlobal {
}
fn version(&self) -> u32 {
6
7
}
fn required_caps(&self) -> ClientCaps {
@ -309,6 +309,7 @@ impl JayCompositorRequestHandler for JayCompositor {
id: req.id,
client: self.client.clone(),
tracker: Default::default(),
version: self.version,
});
track!(self.client, ctx);
self.client.add_client_obj(&ctx)?;
@ -340,7 +341,7 @@ impl JayCompositorRequestHandler for JayCompositor {
}
fn create_screencast(&self, req: CreateScreencast, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let sc = Rc::new_cyclic(|slf| JayScreencast::new(req.id, &self.client, slf));
let sc = Rc::new_cyclic(|slf| JayScreencast::new(req.id, &self.client, slf, self.version));
track!(self.client, sc);
self.client.add_client_obj(&sc)?;
Ok(())

View file

@ -11,16 +11,41 @@ use {
thiserror::Error,
};
pub const FORMATS_SINCE: Version = Version(7);
pub struct JayRenderCtx {
pub id: JayRenderCtxId,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: Version,
}
impl JayRenderCtx {
pub fn send_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
let mut fd = None;
if let Some(ctx) = ctx {
if self.version >= FORMATS_SINCE {
for format in ctx.formats().values() {
self.client.event(Format {
self_id: self.id,
format: format.format.drm,
});
for modifier in &format.write_modifiers {
self.client.event(WriteModifier {
self_id: self.id,
format: format.format.drm,
modifier: *modifier,
});
}
for modifier in &format.read_modifiers {
self.client.event(ReadModifier {
self_id: self.id,
format: format.format.drm,
modifier: *modifier,
});
}
}
}
let allocator = ctx.allocator();
match allocator.drm() {
Some(drm) => match drm.dup_render() {
@ -33,8 +58,6 @@ impl JayRenderCtx {
log::error!("Allocator does not have a DRM device");
}
}
} else {
self.client.event(NoDevice { self_id: self.id });
}
match fd {
Some(fd) => self.client.event(Device {

View file

@ -4,7 +4,7 @@ use {
client::{Client, ClientError},
format::XRGB8888,
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
ifs::{jay_output::JayOutput, jay_toplevel::JayToplevel},
ifs::{jay_output::JayOutput, jay_toplevel::JayToplevel, wl_buffer::WlBufferStorage},
leaks::Tracker,
object::{Object, Version},
scale::Scale,
@ -39,8 +39,11 @@ pub async fn perform_toplevel_screencasts(state: Rc<State>) {
pub async fn perform_screencast_realloc(state: Rc<State>) {
loop {
let screencast = state.pending_toplevel_screencast_reallocs.pop().await;
screencast.realloc_scheduled.set(false);
let screencast = state
.pending_screencast_reallocs_or_reconfigures
.pop()
.await;
screencast.realloc_or_reconfigure_scheduled.set(false);
match state.render_ctx.get() {
None => screencast.do_destroy(),
Some(ctx) => {
@ -52,8 +55,11 @@ pub async fn perform_screencast_realloc(state: Rc<State>) {
}
}
pub const CLIENT_BUFFERS_SINCE: Version = Version(7);
pub struct JayScreencast {
pub id: JayScreencastId,
pub version: Version,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
config_serial: NumCell<u32>,
@ -69,8 +75,8 @@ pub struct JayScreencast {
show_workspaces: RefCell<AHashSet<WorkspaceNodeId>>,
linear: Cell<bool>,
pending: Pending,
need_realloc: Cell<bool>,
realloc_scheduled: Cell<bool>,
need_realloc_or_reconfigure: Cell<bool>,
realloc_or_reconfigure_scheduled: Cell<bool>,
latch_listener: EventListener<dyn LatchListener>,
}
@ -100,11 +106,13 @@ struct Pending {
target: Cell<Option<Option<PendingTarget>>>,
show_all: Cell<Option<bool>>,
show_workspaces: RefCell<Option<AHashSet<WorkspaceNodeId>>>,
clear_buffers: Cell<bool>,
buffers: RefCell<Vec<Rc<dyn GfxFramebuffer>>>,
}
struct ScreencastBuffer {
_bo: Rc<dyn BufferObject>,
dmabuf: DmaBuf,
_bo: Option<Rc<dyn BufferObject>>,
dmabuf: Option<DmaBuf>,
fb: Rc<dyn GfxFramebuffer>,
free: bool,
}
@ -122,9 +130,15 @@ impl JayScreencast {
false
}
pub fn new(id: JayScreencastId, client: &Rc<Client>, slf: &Weak<Self>) -> Self {
pub fn new(
id: JayScreencastId,
client: &Rc<Client>,
slf: &Weak<Self>,
version: Version,
) -> Self {
Self {
id,
version,
client: client.clone(),
tracker: Default::default(),
config_serial: Default::default(),
@ -140,8 +154,8 @@ impl JayScreencast {
show_workspaces: Default::default(),
linear: Cell::new(false),
pending: Default::default(),
need_realloc: Cell::new(false),
realloc_scheduled: Cell::new(false),
need_realloc_or_reconfigure: Cell::new(false),
realloc_or_reconfigure_scheduled: Cell::new(false),
latch_listener: EventListener::new(slf.clone()),
}
}
@ -210,7 +224,12 @@ impl JayScreencast {
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 {
let Some(dmabuf) = &buffer.dmabuf else {
log::error!("Trying to send buffers but buffers are client allocated");
self.do_destroy();
return;
};
for plane in &dmabuf.planes {
self.client.event(Plane {
self_id: self.id,
fd: plane.fd.clone(),
@ -220,10 +239,10 @@ impl JayScreencast {
}
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,
format: dmabuf.format.drm,
modifier: dmabuf.modifier,
width: dmabuf.width,
height: dmabuf.height,
});
}
self.client.event(BuffersDone {
@ -232,11 +251,19 @@ impl JayScreencast {
});
}
#[allow(dead_code)]
fn send_config(&self) {
self.need_realloc_or_reconfigure.set(false);
self.config_acked.set(false);
let serial = self.config_serial.fetch_add(1) + 1;
if let Some(target) = self.target.get() {
let (width, height) = target_size(Some(&target));
if self.version >= CLIENT_BUFFERS_SINCE {
self.client.event(ConfigSize {
self_id: self.id,
width,
height,
});
}
if let Target::Output(output) = target {
self.client.event(ConfigOutput {
self_id: self.id,
@ -339,30 +366,39 @@ impl JayScreencast {
pub fn do_destroy(&self) {
self.detach();
self.buffers.borrow_mut().clear();
self.destroyed.set(true);
self.client.event(Destroyed { self_id: self.id });
}
pub fn schedule_realloc(self: &Rc<Self>) {
self.need_realloc.set(true);
if !self.realloc_scheduled.replace(true) {
pub fn schedule_realloc_or_reconfigure(self: &Rc<Self>) {
self.need_realloc_or_reconfigure.set(true);
if !self.realloc_or_reconfigure_scheduled.replace(true) {
self.client
.state
.pending_toplevel_screencast_reallocs
.pending_screencast_reallocs_or_reconfigures
.push(self.clone());
}
}
fn realloc(&self, ctx: &Rc<dyn GfxContext>) -> Result<(), JayScreencastError> {
if !self.destroyed.get() && self.buffers_acked.get() {
self.do_realloc(ctx)
} else {
Ok(())
if self.destroyed.get() {
return Ok(());
}
if self.version < CLIENT_BUFFERS_SINCE {
if self.buffers_acked.get() {
return self.do_realloc(ctx);
}
} else {
if self.config_acked.get() {
self.send_config();
}
}
Ok(())
}
fn do_realloc(&self, ctx: &Rc<dyn GfxContext>) -> Result<(), JayScreencastError> {
self.need_realloc.set(false);
self.need_realloc_or_reconfigure.set(false);
let mut buffers = vec![];
let formats = ctx.formats();
let format = match formats.get(&XRGB8888.drm) {
@ -395,14 +431,14 @@ impl JayScreencast {
&self.client.state.dma_buf_ids,
width,
height,
XRGB8888,
format.format,
&modifiers,
usage,
)?;
let fb = ctx.clone().dmabuf_img(buffer.dmabuf())?.to_framebuffer()?;
buffers.push(ScreencastBuffer {
dmabuf: buffer.dmabuf().clone(),
_bo: buffer,
dmabuf: Some(buffer.dmabuf().clone()),
_bo: Some(buffer),
fb,
free: true,
});
@ -457,7 +493,7 @@ impl JayScreencastRequestHandler for JayScreencast {
} else {
None
};
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending.target.set(Some(output));
@ -469,7 +505,7 @@ impl JayScreencastRequestHandler for JayScreencast {
req: SetAllowAllWorkspaces,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending.show_all.set(Some(req.allow_all != 0));
@ -478,7 +514,7 @@ impl JayScreencastRequestHandler for JayScreencast {
fn allow_workspace(&self, req: AllowWorkspace, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let ws = self.client.lookup(req.workspace)?;
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
let mut sw = self.pending.show_workspaces.borrow_mut();
@ -494,7 +530,7 @@ impl JayScreencastRequestHandler for JayScreencast {
_req: TouchAllowedWorkspaces,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending
@ -509,7 +545,7 @@ impl JayScreencastRequestHandler for JayScreencast {
req: SetUseLinearBuffers,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending.linear.set(Some(req.use_linear != 0));
@ -517,7 +553,7 @@ impl JayScreencastRequestHandler for JayScreencast {
}
fn set_running(&self, req: SetRunning, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending.running.set(Some(req.running != 0));
@ -525,11 +561,11 @@ impl JayScreencastRequestHandler for JayScreencast {
}
fn configure(&self, _req: Configure, slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
let mut need_realloc = false;
let mut need_realloc_or_reconfigure = false;
if let Some(target) = self.pending.target.take() {
self.detach();
@ -561,15 +597,26 @@ impl JayScreencastRequestHandler for JayScreencast {
}
}
if target_size(new_target.as_ref()) != target_size(self.target.get().as_ref()) {
need_realloc = true;
need_realloc_or_reconfigure = true;
}
self.target.set(new_target);
}
if let Some(linear) = self.pending.linear.take() {
if self.linear.replace(linear) != linear {
need_realloc = true;
need_realloc_or_reconfigure = true;
}
}
if self.pending.clear_buffers.take() {
self.buffers.borrow_mut().clear();
}
for buffer in self.pending.buffers.borrow_mut().drain(..) {
self.buffers.borrow_mut().push(ScreencastBuffer {
_bo: None,
dmabuf: None,
fb: buffer,
free: true,
});
}
let mut capture_rules_changed = false;
if let Some(show_all) = self.pending.show_all.take() {
self.show_all.set(show_all);
@ -583,8 +630,8 @@ impl JayScreencastRequestHandler for JayScreencast {
self.running.set(running);
}
if need_realloc {
slf.schedule_realloc();
if need_realloc_or_reconfigure {
slf.schedule_realloc_or_reconfigure();
}
if capture_rules_changed {
@ -606,19 +653,22 @@ impl JayScreencastRequestHandler for JayScreencast {
}
if req.serial == self.buffers_serial.get() {
self.buffers_acked.set(true);
if self.need_realloc.get() {
slf.schedule_realloc();
if self.need_realloc_or_reconfigure.get() {
slf.schedule_realloc_or_reconfigure();
}
}
Ok(())
}
fn ack_config(&self, req: AckConfig, _slf: &Rc<Self>) -> Result<(), Self::Error> {
fn ack_config(&self, req: AckConfig, slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.destroyed.get() {
return Ok(());
}
if req.serial == self.config_serial.get() {
self.config_acked.set(true);
if self.need_realloc_or_reconfigure.get() {
slf.schedule_realloc_or_reconfigure();
}
}
Ok(())
}
@ -628,7 +678,7 @@ impl JayScreencastRequestHandler for JayScreencast {
return Ok(());
}
let idx = req.idx as usize;
if idx > self.buffers.borrow_mut().len() {
if idx >= self.buffers.borrow_mut().len() {
return Err(JayScreencastError::OutOfBounds(req.idx));
}
self.buffers.borrow_mut()[idx].free = true;
@ -644,17 +694,46 @@ impl JayScreencastRequestHandler for JayScreencast {
} else {
None
};
if self.destroyed.get() || !self.config_acked.get() {
if self.destroyed.get() {
return Ok(());
}
self.pending.target.set(Some(toplevel));
Ok(())
}
fn clear_buffers(&self, _req: ClearBuffers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.destroyed.get() {
return Ok(());
}
self.pending.clear_buffers.set(true);
Ok(())
}
fn add_buffer(&self, req: AddBuffer, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if self.destroyed.get() {
return Ok(());
}
let buffer = self.client.lookup(req.buffer)?;
if let Some(WlBufferStorage::Dmabuf { img, .. }) = &*buffer.storage.borrow() {
match img.clone().to_framebuffer() {
Ok(fb) => self.pending.buffers.borrow_mut().push(fb),
Err(e) => {
log::warn!(
"Could not turn GfxImage into GfxFramebuffer: {}",
ErrorFmt(e)
);
self.do_destroy();
}
}
return Ok(());
}
Err(JayScreencastError::NotDmabuf)
}
}
object_base! {
self = JayScreencast;
version = Version(1);
version = self.version;
}
impl Object for JayScreencast {
@ -681,6 +760,8 @@ pub enum JayScreencastError {
XRGB8888Writing,
#[error("Render context supports neither linear or invalid modifier")]
Modifier,
#[error("Buffer is not a dmabuf")]
NotDmabuf,
}
efrom!(JayScreencastError, ClientError);

View file

@ -141,7 +141,7 @@ pub struct SurfaceSendPreferredScaleVisitor;
impl SurfaceSendPreferredScaleVisitor {
fn schedule_realloc(&self, tl: &impl ToplevelNode) {
for sc in tl.tl_data().jay_screencasts.lock().values() {
sc.schedule_realloc();
sc.schedule_realloc_or_reconfigure();
}
}
}