diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index 62ba9511..a4223e62 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -511,6 +511,10 @@ impl Client { self.send(&ClientMessage::SetGfxApi { device, api }); } + pub fn set_direct_scanout_enabled(&self, device: Option, enabled: bool) { + self.send(&ClientMessage::SetDirectScanoutEnabled { device, enabled }); + } + pub fn connector_connected(&self, connector: Connector) -> bool { let res = self.send_with_response(&ClientMessage::ConnectorConnected { connector }); get_response!(res, false, ConnectorConnected { connected }); diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index dfa05d82..fd32e7a7 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -338,6 +338,10 @@ pub enum ClientMessage<'a> { device: Option, api: GfxApi, }, + SetDirectScanoutEnabled { + device: Option, + enabled: bool, + }, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/video.rs b/jay-config/src/video.rs index 0936a836..9152cd5d 100644 --- a/jay-config/src/video.rs +++ b/jay-config/src/video.rs @@ -369,6 +369,11 @@ impl DrmDevice { pub fn set_gfx_api(self, gfx_api: GfxApi) { get!().set_gfx_api(Some(self), gfx_api); } + + /// Enables or disables direct scanout of client surfaces for this device. + pub fn set_direct_scanout_enabled(self, enabled: bool) { + get!().set_direct_scanout_enabled(Some(self), enabled); + } } /// A graphics API. @@ -389,3 +394,12 @@ pub enum GfxApi { pub fn set_gfx_api(gfx_api: GfxApi) { get!().set_gfx_api(None, gfx_api); } + +/// Enables or disables direct scanout of client surfaces. +/// +/// The default is `true`. +/// +/// This setting can be overwritten per-device with [DrmDevice::set_direct_scanout_enabled]. +pub fn set_direct_scanout_enabled(enabled: bool) { + get!().set_direct_scanout_enabled(None, enabled); +} diff --git a/src/backend.rs b/src/backend.rs index 53cf4b0e..cdeed98e 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -230,4 +230,5 @@ pub trait BackendDrmDevice { fn set_gfx_api(&self, api: GfxApi); fn gtx_api(&self) -> GfxApi; fn version(&self) -> Result; + fn set_direct_scanout_enabled(&self, enabled: bool); } diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index b0ff64be..71f938dc 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -81,6 +81,7 @@ pub struct MetalDrmDevice { pub handle_events: HandleEvents, pub ctx: CloneCell>, pub on_change: OnChange, + pub direct_scanout_enabled: Cell>, } impl BackendDrmDevice for MetalDrmDevice { @@ -115,6 +116,10 @@ impl BackendDrmDevice for MetalDrmDevice { fn version(&self) -> Result { self.gbm.drm.version() } + + fn set_direct_scanout_enabled(&self, enabled: bool) { + self.direct_scanout_enabled.set(Some(enabled)); + } } pub struct HandleEvents { @@ -466,6 +471,13 @@ impl MetalConnector { data } + fn direct_scanout_enabled(&self) -> bool { + self.dev + .direct_scanout_enabled + .get() + .unwrap_or(self.state.direct_scanout_enabled.get()) + } + fn prepare_present_fb( &self, rr: &mut RenderResult, @@ -485,7 +497,9 @@ impl MetalConnector { output.global.preferred_scale.get(), render_hw_cursor, ); - let try_direct_scanout = try_direct_scanout && !output.global.have_shm_screencopies(); + let try_direct_scanout = try_direct_scanout + && !output.global.have_shm_screencopies() + && self.direct_scanout_enabled(); let mut direct_scanout_data = None; if try_direct_scanout { if let Some(dsd) = self.prepare_direct_scanout(&pass, plane) { @@ -1394,6 +1408,7 @@ impl MetalBackend { }, ctx: CloneCell::new(ctx), on_change: Default::default(), + direct_scanout_enabled: Default::default(), }); let (connectors, futures) = get_connectors(self, &dev, &resources.connectors)?; diff --git a/src/backends/x.rs b/src/backends/x.rs index f6131a79..e44d4d6d 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -989,6 +989,10 @@ impl BackendDrmDevice for XDrmDevice { fn version(&self) -> Result { self.backend.gbm.drm.version() } + + fn set_direct_scanout_enabled(&self, enabled: bool) { + let _ = enabled; + } } struct XOutput { diff --git a/src/compositor.rs b/src/compositor.rs index 291b64d8..65249213 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -203,6 +203,7 @@ fn start_compositor2( toplevel_lists: Default::default(), dma_buf_ids: Default::default(), drm_feedback_ids: Default::default(), + direct_scanout_enabled: Cell::new(true), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); diff --git a/src/config/handler.rs b/src/config/handler.rs index e9445e09..9ba8708a 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -590,6 +590,21 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_set_direct_scanout_enabled( + &self, + device: Option, + enabled: bool, + ) -> Result<(), CphError> { + match device { + Some(dev) => self + .get_drm_device(dev)? + .dev + .set_direct_scanout_enabled(enabled), + _ => self.state.direct_scanout_enabled.set(enabled), + } + Ok(()) + } + fn handle_get_default_workspace_capture(&self) { self.respond(Response::GetDefaultWorkspaceCapture { capture: self.state.default_workspace_capture.get(), @@ -1320,6 +1335,9 @@ impl ConfigProxyHandler { ClientMessage::SetGfxApi { device, api } => { self.handle_set_gfx_api(device, api).wrn("set_gfx_api")? } + ClientMessage::SetDirectScanoutEnabled { device, enabled } => self + .handle_set_direct_scanout_enabled(device, enabled) + .wrn("set_direct_scanout_enabled")?, } Ok(()) } diff --git a/src/state.rs b/src/state.rs index c3cca7cf..f7bf0faa 100644 --- a/src/state.rs +++ b/src/state.rs @@ -144,6 +144,7 @@ pub struct State { CopyHashMap<(ClientId, ExtForeignToplevelListV1Id), Rc>, pub dma_buf_ids: DmaBufIds, pub drm_feedback_ids: DrmFeedbackIds, + pub direct_scanout_enabled: Cell, } // impl Drop for State {