screencast: implement format negotation
This commit is contained in:
parent
8d2bd6f660
commit
e7c63fd09a
19 changed files with 649 additions and 201 deletions
|
|
@ -180,7 +180,7 @@ fn start_compositor2(
|
|||
pending_float_titles: Default::default(),
|
||||
pending_input_popup_positioning: Default::default(),
|
||||
pending_toplevel_screencasts: Default::default(),
|
||||
pending_toplevel_screencast_reallocs: Default::default(),
|
||||
pending_screencast_reallocs_or_reconfigures: Default::default(),
|
||||
dbus: Dbus::new(&engine, &ring, &run_toplevel),
|
||||
fdcloser: FdCloser::new(),
|
||||
logger: logger.clone(),
|
||||
|
|
|
|||
|
|
@ -586,3 +586,39 @@ impl Debug for GfxError {
|
|||
Debug::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl GfxFormat {
|
||||
pub fn cross_intersect(&self, other: &GfxFormat) -> GfxFormat {
|
||||
assert_eq!(self.format, other.format);
|
||||
GfxFormat {
|
||||
format: self.format,
|
||||
read_modifiers: self
|
||||
.read_modifiers
|
||||
.intersection(&other.write_modifiers)
|
||||
.copied()
|
||||
.collect(),
|
||||
write_modifiers: self
|
||||
.write_modifiers
|
||||
.intersection(&other.read_modifiers)
|
||||
.copied()
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cross_intersect_formats(
|
||||
local: &AHashMap<u32, GfxFormat>,
|
||||
remote: &AHashMap<u32, GfxFormat>,
|
||||
) -> AHashMap<u32, GfxFormat> {
|
||||
let mut res = AHashMap::new();
|
||||
for lf in local.values() {
|
||||
if let Some(rf) = remote.get(&lf.format.drm) {
|
||||
let f = lf.cross_intersect(rf);
|
||||
if f.read_modifiers.is_empty() && f.write_modifiers.is_empty() {
|
||||
continue;
|
||||
}
|
||||
res.insert(f.format.drm, f);
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ use {
|
|||
pw_pod::{
|
||||
pw_node_activation, spa_chunk, spa_io_buffers, spa_meta_bitmap, spa_meta_busy,
|
||||
spa_meta_cursor, spa_meta_header, spa_meta_region, PW_CHOICE_Enum, PW_CHOICE_Flags,
|
||||
PW_OBJECT_Format, PW_OBJECT_ParamBuffers, PW_OBJECT_ParamMeta, PwIoType,
|
||||
PwPodFraction, PwPodObject, PwPodRectangle, PwPropFlag, SPA_DATA_DmaBuf,
|
||||
SPA_DATA_MemFd, SPA_DATA_MemPtr, SPA_FORMAT_VIDEO_format,
|
||||
PW_OBJECT_Format, PW_OBJECT_ParamBuffers, PW_OBJECT_ParamMeta, PW_TYPE_Long,
|
||||
PwIoType, PwPod, PwPodFraction, PwPodObject, PwPodRectangle, PwPropFlag,
|
||||
SPA_DATA_DmaBuf, SPA_DATA_MemFd, SPA_DATA_MemPtr, SPA_FORMAT_VIDEO_format,
|
||||
SPA_FORMAT_VIDEO_framerate, SPA_FORMAT_VIDEO_modifier, SPA_FORMAT_VIDEO_size,
|
||||
SPA_FORMAT_mediaSubtype, SPA_FORMAT_mediaType, SPA_IO_Buffers, SPA_META_Bitmap,
|
||||
SPA_META_Busy, SPA_META_Control, SPA_META_Cursor, SPA_META_Header,
|
||||
|
|
@ -26,21 +26,21 @@ use {
|
|||
SpaMediaSubtype, SpaMediaType, SpaMetaType, SpaNodeBuffersFlags, SpaNodeCommand,
|
||||
SpaParamType, SpaVideoFormat, PW_NODE_ACTIVATION_FINISHED,
|
||||
PW_NODE_ACTIVATION_NOT_TRIGGERED, PW_NODE_ACTIVATION_TRIGGERED,
|
||||
SPA_DATA_FLAG_READABLE, SPA_DIRECTION_INPUT, SPA_DIRECTION_OUTPUT,
|
||||
SPA_NODE_BUFFERS_FLAG_ALLOC, SPA_PARAM_INFO, SPA_PARAM_INFO_READ,
|
||||
SPA_PARAM_INFO_SERIAL, SPA_PORT_FLAG, SPA_PORT_FLAG_CAN_ALLOC_BUFFERS,
|
||||
PW_PROP_DONT_FIXATE, SPA_DATA_FLAG_READABLE, SPA_DIRECTION_INPUT,
|
||||
SPA_DIRECTION_OUTPUT, SPA_NODE_BUFFERS_FLAG_ALLOC, SPA_PARAM_INFO,
|
||||
SPA_PARAM_INFO_READ, SPA_PARAM_INFO_SERIAL, SPA_PORT_FLAG,
|
||||
SPA_PORT_FLAG_CAN_ALLOC_BUFFERS,
|
||||
},
|
||||
},
|
||||
utils::{
|
||||
bitfield::Bitfield, buf::TypedBuf, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
errorfmt::ErrorFmt, option_ext::OptionExt,
|
||||
},
|
||||
video::dmabuf::DmaBuf,
|
||||
video::{dmabuf::DmaBuf, Modifier},
|
||||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
mem,
|
||||
ops::Deref,
|
||||
rc::Rc,
|
||||
sync::atomic::Ordering::{Relaxed, Release},
|
||||
},
|
||||
|
|
@ -80,7 +80,7 @@ pub trait PwClientNodeOwner {
|
|||
fn port_format_changed(&self, port: &Rc<PwClientNodePort>) {
|
||||
let _ = port;
|
||||
}
|
||||
fn use_buffers(&self, port: &Rc<PwClientNodePort>) {
|
||||
fn use_buffers(self: Rc<Self>, port: &Rc<PwClientNodePort>) {
|
||||
let _ = port;
|
||||
}
|
||||
fn start(self: Rc<Self>) {}
|
||||
|
|
@ -113,14 +113,14 @@ pub struct PwClientNodePort {
|
|||
|
||||
pub _destroyed: Cell<bool>,
|
||||
|
||||
pub effective_format: Cell<PwClientNodePortFormat>,
|
||||
pub supported_formats: RefCell<Option<PwClientNodePortSupportedFormats>>,
|
||||
pub negotiated_format: RefCell<PwClientNodePortFormat>,
|
||||
pub supported_formats: RefCell<PwClientNodePortSupportedFormats>,
|
||||
pub supported_metas: Cell<PwClientNodePortSupportedMetas>,
|
||||
pub can_alloc_buffers: Cell<bool>,
|
||||
|
||||
pub buffers: RefCell<Vec<Rc<PwClientNodeBuffer>>>,
|
||||
|
||||
pub buffer_config: Cell<Option<PwClientNodeBufferConfig>>,
|
||||
pub buffer_config: RefCell<PwClientNodeBufferConfig>,
|
||||
|
||||
pub io_buffers: CloneCell<Option<Rc<PwMemTyped<spa_io_buffers>>>>,
|
||||
|
||||
|
|
@ -129,11 +129,8 @@ pub struct PwClientNodePort {
|
|||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct PwClientNodeBufferConfig {
|
||||
pub num_buffers: usize,
|
||||
pub planes: usize,
|
||||
pub _size: Option<u32>,
|
||||
pub _stride: Option<u32>,
|
||||
pub _align: usize,
|
||||
pub num_buffers: Option<usize>,
|
||||
pub planes: Option<usize>,
|
||||
pub data_type: SpaDataType,
|
||||
}
|
||||
|
||||
|
|
@ -145,21 +142,27 @@ pub struct PwClientNodeBuffer {
|
|||
pub _slices: Vec<Rc<PwMemSlice>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PwClientNodePortSupportedFormat {
|
||||
pub format: &'static Format,
|
||||
pub modifiers: Vec<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PwClientNodePortSupportedFormats {
|
||||
pub media_type: Option<SpaMediaType>,
|
||||
pub media_sub_type: Option<SpaMediaSubtype>,
|
||||
pub video_size: Option<PwPodRectangle>,
|
||||
pub formats: Vec<&'static Format>,
|
||||
pub modifiers: Vec<u64>,
|
||||
pub formats: Vec<PwClientNodePortSupportedFormat>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct PwClientNodePortFormat {
|
||||
pub media_type: Option<SpaMediaType>,
|
||||
pub media_sub_type: Option<SpaMediaSubtype>,
|
||||
pub video_size: Option<PwPodRectangle>,
|
||||
pub format: Option<&'static Format>,
|
||||
pub modifiers: Option<Vec<Modifier>>,
|
||||
pub framerate: Option<PwPodFraction>,
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +246,12 @@ impl PwClientNode {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn create_port(self: &Rc<Self>, output: bool) -> Rc<PwClientNodePort> {
|
||||
pub fn create_port(
|
||||
self: &Rc<Self>,
|
||||
output: bool,
|
||||
supported_formats: PwClientNodePortSupportedFormats,
|
||||
num_buffers: Option<usize>,
|
||||
) -> Rc<PwClientNodePort> {
|
||||
let (ids, direction) = match output {
|
||||
true => (&self.port_out_free, SPA_DIRECTION_OUTPUT),
|
||||
false => (&self.port_in_free, SPA_DIRECTION_INPUT),
|
||||
|
|
@ -253,12 +261,16 @@ impl PwClientNode {
|
|||
direction,
|
||||
id: ids.borrow_mut().acquire(),
|
||||
_destroyed: Cell::new(false),
|
||||
effective_format: Cell::new(Default::default()),
|
||||
supported_formats: RefCell::new(None),
|
||||
negotiated_format: Default::default(),
|
||||
supported_formats: RefCell::new(supported_formats),
|
||||
supported_metas: Cell::new(PwClientNodePortSupportedMetas::none()),
|
||||
can_alloc_buffers: Cell::new(false),
|
||||
buffers: RefCell::new(vec![]),
|
||||
buffer_config: Cell::new(None),
|
||||
buffer_config: RefCell::new(PwClientNodeBufferConfig {
|
||||
num_buffers,
|
||||
planes: None,
|
||||
data_type: SPA_DATA_DmaBuf,
|
||||
}),
|
||||
io_buffers: Default::default(),
|
||||
serial: Cell::new(false),
|
||||
});
|
||||
|
|
@ -297,10 +309,8 @@ impl PwClientNode {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn send_port_update(&self, port: &PwClientNodePort, re_init: bool) {
|
||||
if re_init {
|
||||
port.serial.set(!port.serial.get());
|
||||
}
|
||||
pub fn send_port_update(&self, port: &PwClientNodePort, fixate: bool) {
|
||||
port.serial.set(!port.serial.get());
|
||||
let serial = match port.serial.get() {
|
||||
true => SPA_PARAM_INFO_SERIAL,
|
||||
false => SPA_PARAM_INFO::none(),
|
||||
|
|
@ -324,18 +334,14 @@ impl PwClientNode {
|
|||
if sm.contains(SUPPORTED_META_VIDEO_CROP) {
|
||||
metas.push((SPA_META_VideoCrop, mem::size_of::<spa_meta_region>()));
|
||||
}
|
||||
let sf = port.supported_formats.borrow_mut();
|
||||
let bc = port.buffer_config.get();
|
||||
let mut num_params = metas.len() as u32;
|
||||
if sf.is_some() {
|
||||
num_params += 1;
|
||||
}
|
||||
if bc.is_some() {
|
||||
num_params += 1;
|
||||
}
|
||||
let sf = &*port.supported_formats.borrow();
|
||||
let num_formats = sf.formats.len() as u32;
|
||||
let bc = &*port.buffer_config.borrow();
|
||||
let num_params = metas.len() as u32 + num_formats + 1;
|
||||
|
||||
// num params
|
||||
f.write_uint(num_params);
|
||||
if let Some(sf) = sf.deref() {
|
||||
for format in &sf.formats {
|
||||
f.write_object(PW_OBJECT_Format, SPA_PARAM_EnumFormat.0, |f| {
|
||||
if let Some(mt) = sf.media_type {
|
||||
f.write_property(SPA_FORMAT_mediaType.0, PwPropFlag::none(), |f| {
|
||||
|
|
@ -347,30 +353,28 @@ impl PwClientNode {
|
|||
f.write_id(mst.0);
|
||||
});
|
||||
}
|
||||
if sf.formats.len() > 0 {
|
||||
f.write_property(SPA_FORMAT_VIDEO_format.0, PwPropFlag::none(), |f| {
|
||||
f.write_property(SPA_FORMAT_VIDEO_format.0, PwPropFlag::none(), |f| {
|
||||
f.write_choice(PW_CHOICE_Enum, 0, |f| {
|
||||
f.write_id(format.format.pipewire.0);
|
||||
f.write_id(format.format.pipewire.0);
|
||||
});
|
||||
});
|
||||
f.write_property(
|
||||
SPA_FORMAT_VIDEO_modifier.0,
|
||||
if fixate {
|
||||
PwPropFlag::none()
|
||||
} else {
|
||||
PW_PROP_DONT_FIXATE
|
||||
},
|
||||
|f| {
|
||||
f.write_choice(PW_CHOICE_Enum, 0, |f| {
|
||||
f.write_id(sf.formats[0].pipewire.0);
|
||||
for format in &sf.formats {
|
||||
f.write_id(format.pipewire.0);
|
||||
f.write_ulong(format.modifiers[0]);
|
||||
for modifier in &format.modifiers {
|
||||
f.write_ulong(*modifier);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if sf.modifiers.len() > 0 {
|
||||
f.write_property(
|
||||
SPA_FORMAT_VIDEO_modifier.0,
|
||||
PwPropFlag::none(),
|
||||
|f| {
|
||||
f.write_choice(PW_CHOICE_Enum, 0, |f| {
|
||||
f.write_ulong(sf.modifiers[0]);
|
||||
for modifier in &sf.modifiers {
|
||||
f.write_ulong(*modifier);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
if let Some(vs) = sf.video_size {
|
||||
f.write_property(SPA_FORMAT_VIDEO_size.0, PwPropFlag::none(), |f| {
|
||||
f.write_choice(PW_CHOICE_Enum, 0, |f| {
|
||||
|
|
@ -381,34 +385,23 @@ impl PwClientNode {
|
|||
}
|
||||
});
|
||||
}
|
||||
if let Some(bc) = &bc {
|
||||
f.write_object(PW_OBJECT_ParamBuffers, SPA_PARAM_Buffers.0, |f| {
|
||||
f.write_object(PW_OBJECT_ParamBuffers, SPA_PARAM_Buffers.0, |f| {
|
||||
if let Some(num_buffers) = bc.num_buffers {
|
||||
f.write_property(SPA_PARAM_BUFFERS_buffers.0, PwPropFlag::none(), |f| {
|
||||
f.write_uint(bc.num_buffers as _);
|
||||
f.write_uint(num_buffers as _);
|
||||
});
|
||||
}
|
||||
if let Some(planes) = bc.planes {
|
||||
f.write_property(SPA_PARAM_BUFFERS_blocks.0, PwPropFlag::none(), |f| {
|
||||
f.write_uint(bc.planes as _);
|
||||
f.write_uint(planes as _);
|
||||
});
|
||||
// if let Some(size) = bc.size {
|
||||
// f.write_property(SPA_PARAM_BUFFERS_size.0, PwPropFlag::none(), |f| {
|
||||
// f.write_uint(size as _);
|
||||
// });
|
||||
// }
|
||||
// if let Some(stride) = bc.stride {
|
||||
// f.write_property(SPA_PARAM_BUFFERS_stride.0, PwPropFlag::none(), |f| {
|
||||
// f.write_uint(stride as _);
|
||||
// });
|
||||
// }
|
||||
// f.write_property(SPA_PARAM_BUFFERS_align.0, PwPropFlag::none(), |f| {
|
||||
// f.write_uint(bc.align as _);
|
||||
// });
|
||||
f.write_property(SPA_PARAM_BUFFERS_dataType.0, PwPropFlag::none(), |f| {
|
||||
f.write_choice(PW_CHOICE_Flags, 0, |f| {
|
||||
f.write_uint(1 << bc.data_type.0);
|
||||
});
|
||||
}
|
||||
f.write_property(SPA_PARAM_BUFFERS_dataType.0, PwPropFlag::none(), |f| {
|
||||
f.write_choice(PW_CHOICE_Flags, 0, |f| {
|
||||
f.write_uint(1 << bc.data_type.0);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
for (key, size) in metas {
|
||||
f.write_object(PW_OBJECT_ParamMeta, SPA_PARAM_Meta.0, |f| {
|
||||
f.write_property(SPA_PARAM_META_type.0, PwPropFlag::none(), |f| {
|
||||
|
|
@ -439,23 +432,13 @@ impl PwClientNode {
|
|||
f.write_int(1);
|
||||
// num props
|
||||
f.write_int(0);
|
||||
let mut num_params = 1;
|
||||
if sf.is_some() {
|
||||
num_params += 1;
|
||||
}
|
||||
if bc.is_some() {
|
||||
num_params += 1;
|
||||
}
|
||||
let num_params = 3;
|
||||
// num params
|
||||
f.write_uint(num_params);
|
||||
if sf.is_some() {
|
||||
f.write_id(SPA_PARAM_EnumFormat.0);
|
||||
f.write_uint((SPA_PARAM_INFO_READ | serial).0);
|
||||
}
|
||||
if bc.is_some() {
|
||||
f.write_id(SPA_PARAM_Buffers.0);
|
||||
f.write_uint((SPA_PARAM_INFO_READ | serial).0);
|
||||
}
|
||||
f.write_id(SPA_PARAM_EnumFormat.0);
|
||||
f.write_uint((SPA_PARAM_INFO_READ | serial).0);
|
||||
f.write_id(SPA_PARAM_Buffers.0);
|
||||
f.write_uint((SPA_PARAM_INFO_READ | serial).0);
|
||||
f.write_id(SPA_PARAM_Meta.0);
|
||||
f.write_uint(SPA_PARAM_INFO_READ.0);
|
||||
});
|
||||
|
|
@ -537,7 +520,7 @@ impl PwClientNode {
|
|||
let mut obj = match obj {
|
||||
Some(obj) => obj,
|
||||
_ => {
|
||||
port.effective_format.take();
|
||||
port.negotiated_format.take();
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
|
@ -556,10 +539,25 @@ impl PwClientNode {
|
|||
format.format = Some(*fmt);
|
||||
}
|
||||
}
|
||||
if let Some(mt) = obj.get_param(SPA_FORMAT_VIDEO_modifier.0)? {
|
||||
if let PwPod::Choice(mods) = mt.pod {
|
||||
let mut p1 = mods.elements.elements;
|
||||
p1.read_pod_body_packed(PW_TYPE_Long, 8)?;
|
||||
while p1.len() > 0 {
|
||||
let modifier = p1.read_pod_body_packed(PW_TYPE_Long, 8)?;
|
||||
if let PwPod::Long(modifier) = modifier {
|
||||
format
|
||||
.modifiers
|
||||
.get_or_insert_default_ext()
|
||||
.push(modifier as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(mt) = obj.get_param(SPA_FORMAT_VIDEO_framerate.0)? {
|
||||
format.framerate = Some(mt.pod.get_fraction()?);
|
||||
}
|
||||
port.effective_format.set(format);
|
||||
*port.negotiated_format.borrow_mut() = format;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -712,8 +710,16 @@ impl PwClientNode {
|
|||
if mem_id == !0 {
|
||||
port.io_buffers.take();
|
||||
} else {
|
||||
port.io_buffers
|
||||
.set(Some(self.con.mem.map(mem_id, offset, size)?.typed()));
|
||||
let io_buffers = self
|
||||
.con
|
||||
.mem
|
||||
.map(mem_id, offset, size)?
|
||||
.typed::<spa_io_buffers>();
|
||||
unsafe {
|
||||
io_buffers.read().buffer_id.store(!0, Relaxed);
|
||||
io_buffers.read().status.store(0, Relaxed);
|
||||
}
|
||||
port.io_buffers.set(Some(io_buffers));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
use {
|
||||
crate::{
|
||||
gfx_api::{cross_intersect_formats, GfxFormat},
|
||||
gfx_apis::create_gfx_context,
|
||||
ifs::wl_seat::POINTER,
|
||||
object::Version,
|
||||
portal::{
|
||||
ptl_remote_desktop::RemoteDesktopSession, ptl_render_ctx::PortalRenderCtx,
|
||||
ptl_screencast::ScreencastSession, ptr_gui::WindowData, PortalState,
|
||||
ptl_remote_desktop::RemoteDesktopSession,
|
||||
ptl_render_ctx::{PortalRenderCtx, PortalServerRenderCtx},
|
||||
ptl_screencast::ScreencastSession,
|
||||
ptr_gui::WindowData,
|
||||
PortalState,
|
||||
},
|
||||
utils::{
|
||||
bitflags::BitflagsExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
|
|
@ -67,7 +71,7 @@ pub struct PortalDisplay {
|
|||
pub comp: Rc<UsrWlCompositor>,
|
||||
pub fsm: Rc<UsrWpFractionalScaleManager>,
|
||||
pub vp: Rc<UsrWpViewporter>,
|
||||
pub render_ctx: CloneCell<Option<Rc<PortalRenderCtx>>>,
|
||||
pub render_ctx: CloneCell<Option<Rc<PortalServerRenderCtx>>>,
|
||||
|
||||
pub outputs: CopyHashMap<u32, Rc<PortalOutput>>,
|
||||
pub seats: CopyHashMap<u32, Rc<PortalSeat>>,
|
||||
|
|
@ -156,7 +160,7 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
|||
self.render_ctx.take();
|
||||
}
|
||||
|
||||
fn device(&self, fd: Rc<OwnedFd>) {
|
||||
fn device(&self, fd: Rc<OwnedFd>, server_formats: Option<AHashMap<u32, GfxFormat>>) {
|
||||
self.render_ctx.take();
|
||||
let dev_id = match uapi::fstat(fd.raw()) {
|
||||
Ok(s) => s.st_rdev,
|
||||
|
|
@ -165,12 +169,13 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let mut render_ctx = None;
|
||||
if let Some(ctx) = self.state.render_ctxs.get(&dev_id) {
|
||||
if let Some(ctx) = ctx.upgrade() {
|
||||
self.render_ctx.set(Some(ctx));
|
||||
render_ctx = Some(ctx);
|
||||
}
|
||||
}
|
||||
if self.render_ctx.is_none() {
|
||||
if render_ctx.is_none() {
|
||||
let drm = Drm::open_existing(fd);
|
||||
let ctx =
|
||||
match create_gfx_context(&self.state.eng, &self.state.ring, &drm, GfxApi::OpenGl) {
|
||||
|
|
@ -187,8 +192,22 @@ impl UsrJayRenderCtxOwner for PortalDisplay {
|
|||
_dev_id: dev_id,
|
||||
ctx,
|
||||
});
|
||||
self.render_ctx.set(Some(ctx.clone()));
|
||||
self.state.render_ctxs.set(dev_id, Rc::downgrade(&ctx));
|
||||
render_ctx = Some(ctx);
|
||||
}
|
||||
if let Some(ctx) = render_ctx {
|
||||
let client_formats = ctx.ctx.formats();
|
||||
let usable_formats = match &server_formats {
|
||||
None => client_formats,
|
||||
Some(server_formats) => {
|
||||
Rc::new(cross_intersect_formats(&client_formats, server_formats))
|
||||
}
|
||||
};
|
||||
self.render_ctx.set(Some(Rc::new(PortalServerRenderCtx {
|
||||
ctx,
|
||||
usable_formats,
|
||||
server_formats,
|
||||
})));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -304,7 +323,7 @@ fn finish_display_connect(dpy: Rc<PortalDisplayPrelude>) {
|
|||
con: dpy.con.clone(),
|
||||
owner: Default::default(),
|
||||
caps: Default::default(),
|
||||
version: Version(version.min(5)),
|
||||
version: Version(version.min(7)),
|
||||
});
|
||||
dpy.con.add_object(jc.clone());
|
||||
dpy.registry.request_bind(name, jc.version.0, jc.deref());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,17 @@
|
|||
use {crate::gfx_api::GfxContext, std::rc::Rc, uapi::c};
|
||||
use {
|
||||
crate::gfx_api::{GfxContext, GfxFormat},
|
||||
ahash::AHashMap,
|
||||
std::rc::Rc,
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
pub struct PortalRenderCtx {
|
||||
pub _dev_id: c::dev_t,
|
||||
pub ctx: Rc<dyn GfxContext>,
|
||||
}
|
||||
|
||||
pub struct PortalServerRenderCtx {
|
||||
pub ctx: Rc<PortalRenderCtx>,
|
||||
pub usable_formats: Rc<AHashMap<u32, GfxFormat>>,
|
||||
pub server_formats: Option<AHashMap<u32, GfxFormat>>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,21 @@ mod screencast_gui;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
allocator::{AllocatorError, BufferObject, BO_USE_RENDERING},
|
||||
dbus::{prelude::Variant, DbusObject, DictEntry, DynamicType, PendingReply},
|
||||
format::{Format, XRGB8888},
|
||||
ifs::jay_screencast::CLIENT_BUFFERS_SINCE,
|
||||
pipewire::{
|
||||
pw_con::PwCon,
|
||||
pw_ifs::pw_client_node::{
|
||||
PwClientNode, PwClientNodeBufferConfig, PwClientNodeOwner, PwClientNodePort,
|
||||
PwClientNodePortSupportedFormats, SUPPORTED_META_VIDEO_CROP,
|
||||
PwClientNodePortSupportedFormat, PwClientNodePortSupportedFormats,
|
||||
SUPPORTED_META_VIDEO_CROP,
|
||||
},
|
||||
pw_pod::{
|
||||
spa_point, spa_rectangle, spa_region, PwPodRectangle, SPA_DATA_DmaBuf,
|
||||
SPA_MEDIA_SUBTYPE_raw, SPA_MEDIA_TYPE_video, SpaChunkFlags, SPA_STATUS_HAVE_DATA,
|
||||
SPA_VIDEO_FORMAT_UNKNOWN,
|
||||
},
|
||||
},
|
||||
portal::{
|
||||
|
|
@ -22,9 +27,10 @@ use {
|
|||
utils::{
|
||||
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||
copyhashmap::CopyHashMap,
|
||||
errorfmt::ErrorFmt,
|
||||
hash_map_ext::HashMapExt,
|
||||
},
|
||||
video::dmabuf::{DmaBuf, PlaneVec},
|
||||
video::{dmabuf::DmaBuf, Modifier, LINEAR_MODIFIER},
|
||||
wire::jay_screencast::Ready,
|
||||
wire_dbus::{
|
||||
org,
|
||||
|
|
@ -37,11 +43,15 @@ use {
|
|||
},
|
||||
},
|
||||
wl_usr::usr_ifs::{
|
||||
usr_jay_screencast::{UsrJayScreencast, UsrJayScreencastOwner},
|
||||
usr_jay_screencast::{
|
||||
UsrJayScreencast, UsrJayScreencastOwner, UsrJayScreencastServerConfig,
|
||||
},
|
||||
usr_jay_select_toplevel::UsrJaySelectToplevel,
|
||||
usr_jay_select_workspace::UsrJaySelectWorkspace,
|
||||
usr_jay_toplevel::UsrJayToplevel,
|
||||
usr_jay_workspace::UsrJayWorkspace,
|
||||
usr_linux_buffer_params::{UsrLinuxBufferParams, UsrLinuxBufferParamsOwner},
|
||||
usr_wl_buffer::UsrWlBuffer,
|
||||
},
|
||||
},
|
||||
std::{
|
||||
|
|
@ -51,6 +61,7 @@ use {
|
|||
rc::Rc,
|
||||
sync::atomic::Ordering::{Acquire, Relaxed, Release},
|
||||
},
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
shared_ids!(ScreencastSessionId);
|
||||
|
|
@ -120,10 +131,18 @@ pub struct StartedScreencast {
|
|||
session: Rc<ScreencastSession>,
|
||||
node: Rc<PwClientNode>,
|
||||
port: Rc<PwClientNodePort>,
|
||||
buffers: RefCell<PlaneVec<DmaBuf>>,
|
||||
buffer_objects: RefCell<Vec<Rc<dyn BufferObject>>>,
|
||||
buffers: RefCell<Vec<DmaBuf>>,
|
||||
pending_buffers: RefCell<Vec<Rc<UsrLinuxBufferParams>>>,
|
||||
buffers_valid: Cell<bool>,
|
||||
dpy: Rc<PortalDisplay>,
|
||||
jay_screencast: Rc<UsrJayScreencast>,
|
||||
port_buffer_valid: Cell<bool>,
|
||||
fixated: Cell<bool>,
|
||||
format: Cell<&'static Format>,
|
||||
modifier: Cell<Modifier>,
|
||||
width: Cell<i32>,
|
||||
height: Cell<i32>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
@ -164,7 +183,36 @@ impl PwClientNodeOwner for StartingScreencast {
|
|||
results: Cow::Borrowed(variants),
|
||||
});
|
||||
}
|
||||
let port = self.node.create_port(true);
|
||||
let mut supported_formats = PwClientNodePortSupportedFormats {
|
||||
media_type: Some(SPA_MEDIA_TYPE_video),
|
||||
media_sub_type: Some(SPA_MEDIA_SUBTYPE_raw),
|
||||
video_size: None,
|
||||
formats: vec![PwClientNodePortSupportedFormat {
|
||||
format: XRGB8888,
|
||||
modifiers: vec![LINEAR_MODIFIER],
|
||||
}],
|
||||
};
|
||||
if let Some(ctx) = self.dpy.render_ctx.get() {
|
||||
if let Some(server_formats) = &ctx.server_formats {
|
||||
supported_formats.formats.clear();
|
||||
for format in server_formats.values() {
|
||||
if format.write_modifiers.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if format.format.pipewire == SPA_VIDEO_FORMAT_UNKNOWN {
|
||||
continue;
|
||||
}
|
||||
let ptl_format = PwClientNodePortSupportedFormat {
|
||||
format: format.format,
|
||||
modifiers: format.write_modifiers.iter().copied().collect(),
|
||||
};
|
||||
supported_formats.formats.push(ptl_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
let jsc_version = self.dpy.jc.version;
|
||||
let num_buffers = (jsc_version >= CLIENT_BUFFERS_SINCE).then_some(3);
|
||||
let port = self.node.create_port(true, supported_formats, num_buffers);
|
||||
port.can_alloc_buffers.set(true);
|
||||
port.supported_metas.set(SUPPORTED_META_VIDEO_CROP);
|
||||
let jsc = self.dpy.jc.create_screencast();
|
||||
|
|
@ -194,10 +242,18 @@ impl PwClientNodeOwner for StartingScreencast {
|
|||
session: self.session.clone(),
|
||||
node: self.node.clone(),
|
||||
port,
|
||||
buffer_objects: Default::default(),
|
||||
buffers: Default::default(),
|
||||
pending_buffers: Default::default(),
|
||||
buffers_valid: Cell::new(false),
|
||||
dpy: self.dpy.clone(),
|
||||
jay_screencast: jsc,
|
||||
port_buffer_valid: Cell::new(false),
|
||||
fixated: Cell::new(jsc_version < CLIENT_BUFFERS_SINCE),
|
||||
format: Cell::new(XRGB8888),
|
||||
modifier: Cell::new(LINEAR_MODIFIER),
|
||||
width: Cell::new(1),
|
||||
height: Cell::new(1),
|
||||
});
|
||||
self.session
|
||||
.phase
|
||||
|
|
@ -209,13 +265,84 @@ impl PwClientNodeOwner for StartingScreencast {
|
|||
|
||||
impl PwClientNodeOwner for StartedScreencast {
|
||||
fn port_format_changed(&self, port: &Rc<PwClientNodePort>) {
|
||||
self.node.send_port_update(port, false);
|
||||
let format = &*port.negotiated_format.borrow();
|
||||
if self.fixated.get() {
|
||||
return;
|
||||
}
|
||||
let (Some(fmt), Some(modifiers)) = (format.format, &format.modifiers) else {
|
||||
return;
|
||||
};
|
||||
let modifier;
|
||||
let planes;
|
||||
match self.allocate_buffer(fmt, modifiers, 1, 1) {
|
||||
Ok(bo) => {
|
||||
let dmabuf = bo.dmabuf();
|
||||
modifier = dmabuf.modifier;
|
||||
planes = dmabuf.planes.len();
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not allocate buffer: {}", ErrorFmt(e));
|
||||
self.session.kill();
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.port.supported_formats.borrow_mut().formats = vec![PwClientNodePortSupportedFormat {
|
||||
format: fmt,
|
||||
modifiers: vec![modifier],
|
||||
}];
|
||||
self.port.buffer_config.borrow_mut().planes = Some(planes);
|
||||
self.node.send_port_update(&self.port, true);
|
||||
self.format.set(fmt);
|
||||
self.modifier.set(modifier);
|
||||
self.fixated.set(true);
|
||||
}
|
||||
|
||||
fn use_buffers(&self, port: &Rc<PwClientNodePort>) {
|
||||
fn use_buffers(self: Rc<Self>, port: &Rc<PwClientNodePort>) {
|
||||
if self.jay_screencast.version < CLIENT_BUFFERS_SINCE {
|
||||
self.node
|
||||
.send_port_output_buffers(port, &self.buffers.borrow_mut());
|
||||
self.buffers_valid.set(true);
|
||||
return;
|
||||
}
|
||||
self.buffers_valid.set(false);
|
||||
self.port_buffer_valid.set(false);
|
||||
let Some(dmabuf) = self.dpy.dmabuf.get() else {
|
||||
log::error!("Display does not support dmabuf");
|
||||
self.session.kill();
|
||||
return;
|
||||
};
|
||||
self.jay_screencast.clear_buffers();
|
||||
self.jay_screencast.configure();
|
||||
self.buffer_objects.borrow_mut().clear();
|
||||
self.buffers.borrow_mut().clear();
|
||||
for buffer in self.pending_buffers.borrow_mut().drain(..) {
|
||||
self.dpy.con.remove_obj(&*buffer);
|
||||
}
|
||||
for _ in 0..self.port.buffers.borrow().len() {
|
||||
let res = self.allocate_buffer(
|
||||
self.format.get(),
|
||||
&[self.modifier.get()],
|
||||
self.width.get(),
|
||||
self.height.get(),
|
||||
);
|
||||
match res {
|
||||
Ok(b) => {
|
||||
let params = dmabuf.create_params();
|
||||
params.create(&b.dmabuf());
|
||||
params.owner.set(Some(self.clone()));
|
||||
self.buffers.borrow_mut().push(b.dmabuf().clone());
|
||||
self.buffer_objects.borrow_mut().push(b);
|
||||
self.pending_buffers.borrow_mut().push(params);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not allocate buffer: {}", ErrorFmt(e));
|
||||
self.session.kill();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.node
|
||||
.send_port_output_buffers(port, &self.buffers.borrow_mut());
|
||||
self.buffers_valid.set(true);
|
||||
.send_port_output_buffers(&self.port, &self.buffers.borrow());
|
||||
}
|
||||
|
||||
fn start(self: Rc<Self>) {
|
||||
|
|
@ -234,6 +361,37 @@ impl PwClientNodeOwner for StartedScreencast {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum BufferAllocationError {
|
||||
#[error("Display has no render context")]
|
||||
NoRenderContext,
|
||||
#[error(transparent)]
|
||||
Allocator(#[from] AllocatorError),
|
||||
}
|
||||
|
||||
impl StartedScreencast {
|
||||
fn allocate_buffer(
|
||||
&self,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
width: i32,
|
||||
height: i32,
|
||||
) -> Result<Rc<dyn BufferObject>, BufferAllocationError> {
|
||||
let Some(ctx) = self.dpy.render_ctx.get() else {
|
||||
return Err(BufferAllocationError::NoRenderContext);
|
||||
};
|
||||
let buffer = ctx.ctx.ctx.allocator().create_bo(
|
||||
&self.dpy.state.dma_buf_ids,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
modifiers,
|
||||
BO_USE_RENDERING,
|
||||
)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl SelectingScreencastCore {
|
||||
pub fn starting(&self, dpy: &Rc<PortalDisplay>, target: ScreencastTarget) {
|
||||
let node = self.session.pw_con.create_client_node(&[
|
||||
|
|
@ -300,6 +458,9 @@ impl ScreencastSession {
|
|||
s.jay_screencast.con.remove_obj(s.jay_screencast.deref());
|
||||
s.node.con.destroy_obj(s.node.deref());
|
||||
s.dpy.screencasts.remove(self.session_obj.path());
|
||||
for buffer in s.pending_buffers.borrow_mut().drain(..) {
|
||||
s.dpy.con.remove_obj(&*buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -375,32 +536,31 @@ impl ScreencastSession {
|
|||
}
|
||||
|
||||
impl UsrJayScreencastOwner for StartedScreencast {
|
||||
fn buffers(&self, buffers: PlaneVec<DmaBuf>) {
|
||||
fn buffers(&self, buffers: Vec<DmaBuf>) {
|
||||
if buffers.len() == 0 {
|
||||
return;
|
||||
}
|
||||
let buffer = &buffers[0];
|
||||
*self.port.supported_formats.borrow_mut() = Some(PwClientNodePortSupportedFormats {
|
||||
*self.port.supported_formats.borrow_mut() = PwClientNodePortSupportedFormats {
|
||||
media_type: Some(SPA_MEDIA_TYPE_video),
|
||||
media_sub_type: Some(SPA_MEDIA_SUBTYPE_raw),
|
||||
video_size: Some(PwPodRectangle {
|
||||
width: buffer.width as _,
|
||||
height: buffer.height as _,
|
||||
}),
|
||||
formats: vec![buffer.format],
|
||||
modifiers: vec![buffer.modifier],
|
||||
});
|
||||
let bc = PwClientNodeBufferConfig {
|
||||
num_buffers: buffers.len(),
|
||||
planes: buffer.planes.len(),
|
||||
_stride: Some(buffer.planes[0].stride),
|
||||
_size: Some(buffer.planes[0].stride * buffer.height as u32),
|
||||
_align: 16,
|
||||
formats: vec![PwClientNodePortSupportedFormat {
|
||||
format: buffer.format,
|
||||
modifiers: vec![buffer.modifier],
|
||||
}],
|
||||
};
|
||||
*self.port.buffer_config.borrow_mut() = PwClientNodeBufferConfig {
|
||||
num_buffers: Some(buffers.len()),
|
||||
planes: Some(buffer.planes.len()),
|
||||
data_type: SPA_DATA_DmaBuf,
|
||||
};
|
||||
self.port.buffer_config.set(Some(bc));
|
||||
self.node.send_port_update(&self.port, true);
|
||||
self.node.send_active(true);
|
||||
self.fixated.set(true);
|
||||
*self.buffers.borrow_mut() = buffers;
|
||||
self.buffers_valid.set(false);
|
||||
}
|
||||
|
|
@ -414,7 +574,6 @@ impl UsrJayScreencastOwner for StartedScreencast {
|
|||
self.jay_screencast.release_buffer(idx);
|
||||
};
|
||||
if !self.buffers_valid.get() {
|
||||
discard_buffer();
|
||||
return;
|
||||
}
|
||||
let Some(io) = self.port.io_buffers.get() else {
|
||||
|
|
@ -447,19 +606,47 @@ impl UsrJayScreencastOwner for StartedScreencast {
|
|||
};
|
||||
}
|
||||
let buffer_id = io.buffer_id.load(Relaxed) as usize;
|
||||
if buffer_id != idx {
|
||||
if buffer_id < buffers.len() {
|
||||
self.jay_screencast.release_buffer(buffer_id);
|
||||
if self.port_buffer_valid.get() {
|
||||
if buffer_id != idx {
|
||||
if buffer_id < buffers.len() {
|
||||
self.jay_screencast.release_buffer(buffer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
io.buffer_id.store(ev.idx, Relaxed);
|
||||
io.status.store(SPA_STATUS_HAVE_DATA.0, Release);
|
||||
self.port_buffer_valid.set(true);
|
||||
self.port.node.drive();
|
||||
}
|
||||
|
||||
fn destroyed(&self) {
|
||||
self.session.kill();
|
||||
}
|
||||
|
||||
fn config(&self, config: UsrJayScreencastServerConfig) {
|
||||
self.width.set(config.width.max(1));
|
||||
self.height.set(config.height.max(1));
|
||||
self.port.supported_formats.borrow_mut().video_size = Some(PwPodRectangle {
|
||||
width: self.width.get() as _,
|
||||
height: self.height.get() as _,
|
||||
});
|
||||
self.node.send_port_update(&self.port, self.fixated.get());
|
||||
self.node.send_active(true);
|
||||
}
|
||||
}
|
||||
|
||||
impl UsrLinuxBufferParamsOwner for StartedScreencast {
|
||||
fn created(&self, buffer: Rc<UsrWlBuffer>) {
|
||||
self.buffers_valid.set(true);
|
||||
self.jay_screencast.add_buffer(&buffer);
|
||||
self.jay_screencast.configure();
|
||||
self.dpy.con.remove_obj(&*buffer);
|
||||
}
|
||||
|
||||
fn failed(&self) {
|
||||
log::error!("Buffer import failed");
|
||||
self.session.kill();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn add_screencast_dbus_members(
|
||||
|
|
|
|||
|
|
@ -599,7 +599,8 @@ impl WindowData {
|
|||
Some(c) => c,
|
||||
_ => return,
|
||||
};
|
||||
let (mut width, mut height) = content.layout(&ctx.ctx, scale, f32::INFINITY, f32::INFINITY);
|
||||
let (mut width, mut height) =
|
||||
content.layout(&ctx.ctx.ctx, scale, f32::INFINITY, f32::INFINITY);
|
||||
content.data().width.set(width);
|
||||
content.data().height.set(height);
|
||||
width = width.max(1.0);
|
||||
|
|
@ -710,7 +711,7 @@ impl WindowData {
|
|||
self.frame_missed.set(true);
|
||||
let width = (self.width.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
||||
let height = (self.height.get() as f64 * self.scale.get().to_f64()).round() as i32;
|
||||
let formats = ctx.ctx.formats();
|
||||
let formats = &ctx.usable_formats;
|
||||
let format = match formats.get(&ARGB8888.drm) {
|
||||
None => {
|
||||
log::error!("Render context does not support ARGB8888 format");
|
||||
|
|
@ -724,7 +725,7 @@ impl WindowData {
|
|||
}
|
||||
let modifiers: Vec<_> = format.write_modifiers.iter().copied().collect();
|
||||
for _ in 0..NUM_BUFFERS {
|
||||
let bo = match ctx.ctx.allocator().create_bo(
|
||||
let bo = match ctx.ctx.ctx.allocator().create_bo(
|
||||
&self.dpy.state.dma_buf_ids,
|
||||
width,
|
||||
height,
|
||||
|
|
@ -738,7 +739,7 @@ impl WindowData {
|
|||
return;
|
||||
}
|
||||
};
|
||||
let img = match ctx.ctx.clone().dmabuf_img(bo.dmabuf()) {
|
||||
let img = match ctx.ctx.ctx.clone().dmabuf_img(bo.dmabuf()) {
|
||||
Ok(b) => b,
|
||||
Err(e) => {
|
||||
log::error!("Could not import dmabuf into EGL: {}", ErrorFmt(e));
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ pub struct State {
|
|||
pub pending_float_titles: AsyncQueue<Rc<FloatNode>>,
|
||||
pub pending_input_popup_positioning: AsyncQueue<Rc<ZwpInputPopupSurfaceV2>>,
|
||||
pub pending_toplevel_screencasts: AsyncQueue<Rc<JayScreencast>>,
|
||||
pub pending_toplevel_screencast_reallocs: AsyncQueue<Rc<JayScreencast>>,
|
||||
pub pending_screencast_reallocs_or_reconfigures: AsyncQueue<Rc<JayScreencast>>,
|
||||
pub dbus: Dbus,
|
||||
pub fdcloser: Arc<FdCloser>,
|
||||
pub logger: Option<Arc<Logger>>,
|
||||
|
|
@ -814,7 +814,7 @@ impl State {
|
|||
self.pending_float_titles.clear();
|
||||
self.pending_input_popup_positioning.clear();
|
||||
self.pending_toplevel_screencasts.clear();
|
||||
self.pending_toplevel_screencast_reallocs.clear();
|
||||
self.pending_screencast_reallocs_or_reconfigures.clear();
|
||||
self.render_ctx_watchers.clear();
|
||||
self.workspace_watchers.clear();
|
||||
self.toplevel_lists.clear();
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ impl OutputNode {
|
|||
|
||||
if (old_width, old_height) != (new_width, new_height) {
|
||||
for sc in self.screencasts.lock().values() {
|
||||
sc.schedule_realloc();
|
||||
sc.schedule_realloc_or_reconfigure();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
|
|||
let prev = data.desired_extents.replace(*rect);
|
||||
if prev.size() != rect.size() {
|
||||
for sc in data.jay_screencasts.lock().values() {
|
||||
sc.schedule_realloc();
|
||||
sc.schedule_realloc_or_reconfigure();
|
||||
}
|
||||
}
|
||||
if data.is_floating.get() {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ impl UsrJayCompositor {
|
|||
con: self.con.clone(),
|
||||
owner: Default::default(),
|
||||
version: self.version,
|
||||
formats: Default::default(),
|
||||
});
|
||||
self.con.request(GetRenderCtx {
|
||||
self_id: self.id,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
use {
|
||||
crate::{
|
||||
format::formats,
|
||||
gfx_api::GfxFormat,
|
||||
ifs::jay_render_ctx::FORMATS_SINCE,
|
||||
object::Version,
|
||||
utils::clonecell::CloneCell,
|
||||
wire::{jay_render_ctx::*, JayRenderCtxId},
|
||||
wl_usr::{usr_object::UsrObject, UsrCon},
|
||||
},
|
||||
std::{convert::Infallible, rc::Rc},
|
||||
ahash::AHashMap,
|
||||
std::{cell::RefCell, convert::Infallible, rc::Rc},
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
|
|
@ -14,12 +18,14 @@ pub struct UsrJayRenderCtx {
|
|||
pub con: Rc<UsrCon>,
|
||||
pub owner: CloneCell<Option<Rc<dyn UsrJayRenderCtxOwner>>>,
|
||||
pub version: Version,
|
||||
pub formats: RefCell<AHashMap<u32, GfxFormat>>,
|
||||
}
|
||||
|
||||
pub trait UsrJayRenderCtxOwner {
|
||||
fn no_device(&self) {}
|
||||
fn device(&self, fd: Rc<OwnedFd>) {
|
||||
fn device(&self, fd: Rc<OwnedFd>, server_formats: Option<AHashMap<u32, GfxFormat>>) {
|
||||
let _ = fd;
|
||||
let _ = server_formats;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,6 +33,7 @@ impl JayRenderCtxEventHandler for UsrJayRenderCtx {
|
|||
type Error = Infallible;
|
||||
|
||||
fn no_device(&self, _ev: NoDevice, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.formats.take();
|
||||
if let Some(owner) = self.owner.get() {
|
||||
owner.no_device();
|
||||
}
|
||||
|
|
@ -34,8 +41,38 @@ impl JayRenderCtxEventHandler for UsrJayRenderCtx {
|
|||
}
|
||||
|
||||
fn device(&self, ev: Device, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let formats = self.formats.take();
|
||||
let formats = (self.version >= FORMATS_SINCE).then_some(formats);
|
||||
if let Some(owner) = self.owner.get() {
|
||||
owner.device(ev.fd);
|
||||
owner.device(ev.fd, formats);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_modifier(&self, ev: ReadModifier, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
if let Some(format) = self.formats.borrow_mut().get_mut(&ev.format) {
|
||||
format.read_modifiers.insert(ev.modifier);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_modifier(&self, ev: WriteModifier, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
if let Some(format) = self.formats.borrow_mut().get_mut(&ev.format) {
|
||||
format.write_modifiers.insert(ev.modifier);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn format(&self, ev: Format, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
if let Some(format) = formats().get(&ev.format) {
|
||||
self.formats.borrow_mut().insert(
|
||||
ev.format,
|
||||
GfxFormat {
|
||||
format,
|
||||
read_modifiers: Default::default(),
|
||||
write_modifiers: Default::default(),
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use {
|
|||
wl_usr::{
|
||||
usr_ifs::{
|
||||
usr_jay_output::UsrJayOutput, usr_jay_toplevel::UsrJayToplevel,
|
||||
usr_jay_workspace::UsrJayWorkspace,
|
||||
usr_jay_workspace::UsrJayWorkspace, usr_wl_buffer::UsrWlBuffer,
|
||||
},
|
||||
usr_object::UsrObject,
|
||||
UsrCon,
|
||||
|
|
@ -24,7 +24,7 @@ pub struct UsrJayScreencast {
|
|||
pub owner: CloneCell<Option<Rc<dyn UsrJayScreencastOwner>>>,
|
||||
pub version: Version,
|
||||
|
||||
pub pending_buffers: RefCell<PlaneVec<DmaBuf>>,
|
||||
pub pending_buffers: RefCell<Vec<DmaBuf>>,
|
||||
pub pending_planes: RefCell<PlaneVec<DmaBufPlane>>,
|
||||
|
||||
pub pending_config: RefCell<UsrJayScreencastServerConfig>,
|
||||
|
|
@ -37,10 +37,12 @@ pub struct UsrJayScreencastServerConfig {
|
|||
pub running: bool,
|
||||
pub use_linear_buffers: bool,
|
||||
pub allowed_workspaces: Vec<u32>,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
pub trait UsrJayScreencastOwner {
|
||||
fn buffers(&self, buffers: PlaneVec<DmaBuf>) {
|
||||
fn buffers(&self, buffers: Vec<DmaBuf>) {
|
||||
let _ = buffers;
|
||||
}
|
||||
|
||||
|
|
@ -116,6 +118,17 @@ impl UsrJayScreencast {
|
|||
idx: idx as _,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn clear_buffers(&self) {
|
||||
self.con.request(ClearBuffers { self_id: self.id });
|
||||
}
|
||||
|
||||
pub fn add_buffer(&self, buffer: &UsrWlBuffer) {
|
||||
self.con.request(AddBuffer {
|
||||
self_id: self.id,
|
||||
buffer: buffer.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl JayScreencastEventHandler for UsrJayScreencast {
|
||||
|
|
@ -228,6 +241,12 @@ impl JayScreencastEventHandler for UsrJayScreencast {
|
|||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn config_size(&self, ev: ConfigSize, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.pending_config.borrow_mut().width = ev.width;
|
||||
self.pending_config.borrow_mut().height = ev.height;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
usr_object_base! {
|
||||
|
|
|
|||
|
|
@ -13,3 +13,17 @@ event no_device {
|
|||
event device {
|
||||
fd: fd,
|
||||
}
|
||||
|
||||
event read_modifier (since = 7) {
|
||||
format: u32,
|
||||
modifier: pod(u64),
|
||||
}
|
||||
|
||||
event write_modifier (since = 7) {
|
||||
format: u32,
|
||||
modifier: pod(u64),
|
||||
}
|
||||
|
||||
event format (since = 7) {
|
||||
format: u32,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,13 @@ request set_toplevel {
|
|||
id: id(jay_toplevel),
|
||||
}
|
||||
|
||||
request clear_buffers (since = 7) {
|
||||
}
|
||||
|
||||
request add_buffer (since = 7) {
|
||||
buffer: id(wl_buffer),
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
event plane {
|
||||
|
|
@ -101,3 +108,8 @@ event config_running {
|
|||
event config_done {
|
||||
serial: u32,
|
||||
}
|
||||
|
||||
event config_size (since = 7) {
|
||||
width: i32,
|
||||
height: i32,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue