diff options
| -rw-r--r-- | src/backend/mod.rs | 3 | ||||
| -rw-r--r-- | src/backend/tty.rs | 40 | ||||
| -rw-r--r-- | src/backend/winit.rs | 5 | ||||
| -rw-r--r-- | src/handlers/mod.rs | 2 | ||||
| -rw-r--r-- | src/layout.rs | 38 | ||||
| -rw-r--r-- | src/niri.rs | 43 |
6 files changed, 116 insertions, 15 deletions
diff --git a/src/backend/mod.rs b/src/backend/mod.rs index d70ee2aa..8a59e6f3 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,5 +1,6 @@ use smithay::backend::renderer::gles::GlesRenderer; use smithay::output::Output; +use smithay::wayland::dmabuf::DmabufFeedback; use crate::input::CompositorMod; use crate::niri::OutputRenderElements; @@ -43,7 +44,7 @@ impl Backend { niri: &mut Niri, output: &Output, elements: &[OutputRenderElements<GlesRenderer>], - ) { + ) -> Option<&DmabufFeedback> { match self { Backend::Tty(tty) => tty.render(niri, output, elements), Backend::Winit(winit) => winit.render(niri, output, elements), diff --git a/src/backend/tty.rs b/src/backend/tty.rs index 2db762fc..e5555984 100644 --- a/src/backend/tty.rs +++ b/src/backend/tty.rs @@ -25,9 +25,10 @@ use smithay::reexports::drm::control::{ use smithay::reexports::input::Libinput; use smithay::reexports::nix::fcntl::OFlag; use smithay::reexports::nix::libc::dev_t; +use smithay::reexports::wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags; use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback; use smithay::utils::DeviceFd; -use smithay::wayland::dmabuf::{DmabufFeedbackBuilder, DmabufGlobal, DmabufState}; +use smithay::wayland::dmabuf::{DmabufFeedbackBuilder, DmabufGlobal, DmabufState, DmabufFeedback}; use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner}; use smithay_drm_extras::edid::EdidInfo; @@ -59,7 +60,7 @@ struct OutputDevice { gles: GlesRenderer, formats: HashSet<DrmFormat>, drm_scanner: DrmScanner, - surfaces: HashMap<crtc::Handle, GbmDrmCompositor>, + surfaces: HashMap<crtc::Handle, (GbmDrmCompositor, DmabufFeedback)>, dmabuf_state: DmabufState, dmabuf_global: DmabufGlobal, } @@ -274,7 +275,7 @@ impl Tty { trace!("vblank {metadata:?}"); let device = tty.output_device.as_mut().unwrap(); - let drm_compositor = device.surfaces.get_mut(&crtc).unwrap(); + let drm_compositor = &mut device.surfaces.get_mut(&crtc).unwrap().0; let presentation_time = match metadata.as_mut().unwrap().time { DrmEventTime::Monotonic(time) => time, @@ -479,6 +480,20 @@ impl Tty { crtc, }); + let planes = surface.planes().unwrap(); + let scanout_formats = surface + .supported_formats(planes.primary.handle) + .unwrap() + .into_iter() + .chain( + planes + .overlay + .into_iter() + .flat_map(|p| surface.supported_formats(p.handle).unwrap()), + ) + .collect::<HashSet<_>>(); + let scanout_formats = scanout_formats.intersection(&device.formats).copied(); + // Create the compositor. let compositor = DrmCompositor::new( OutputModeSource::Auto(output.clone()), @@ -492,7 +507,12 @@ impl Tty { Some(device.gbm.clone()), )?; - let res = device.surfaces.insert(crtc, compositor); + let dmabuf_feedback = DmabufFeedbackBuilder::new(device.id, device.formats.clone()) + .add_preference_tranche(device.id, Some(TrancheFlags::Scanout), scanout_formats) + .build() + .unwrap(); + + let res = device.surfaces.insert(crtc, (compositor, dmabuf_feedback)); assert!(res.is_none(), "crtc must not have already existed"); niri.add_output(output.clone(), Some(refresh_interval(*mode))); @@ -541,12 +561,12 @@ impl Tty { niri: &mut Niri, output: &Output, elements: &[OutputRenderElements<GlesRenderer>], - ) { + ) -> Option<&DmabufFeedback> { let _span = tracy_client::span!("Tty::render"); let device = self.output_device.as_mut().unwrap(); let tty_state: &TtyOutputState = output.user_data().get().unwrap(); - let drm_compositor = device.surfaces.get_mut(&tty_state.crtc).unwrap(); + let (drm_compositor, dmabuf_feedback) = device.surfaces.get_mut(&tty_state.crtc).unwrap(); match drm_compositor.render_frame::<_, _, GlesTexture>( &mut device.gles, @@ -564,7 +584,9 @@ impl Tty { niri.output_state .get_mut(output) .unwrap() - .waiting_for_vblank = true + .waiting_for_vblank = true; + + return Some(dmabuf_feedback); } Err(err) => { error!("error queueing frame: {err}"); @@ -577,6 +599,8 @@ impl Tty { error!("error rendering frame: {err}"); } } + + None } pub fn change_vt(&mut self, vt: i32) { @@ -593,7 +617,7 @@ impl Tty { pub fn toggle_debug_tint(&mut self) { if let Some(device) = self.output_device.as_mut() { - for (_, compositor) in &mut device.surfaces { + for (_, (compositor, _)) in &mut device.surfaces { compositor.set_debug_flags(compositor.debug_flags() ^ DebugFlags::TINT); } } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 767bf7f4..dc2e8bc6 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -11,6 +11,7 @@ use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_pre use smithay::reexports::winit::dpi::LogicalSize; use smithay::reexports::winit::window::WindowBuilder; use smithay::utils::Transform; +use smithay::wayland::dmabuf::DmabufFeedback; use crate::niri::OutputRenderElements; use crate::utils::get_monotonic_time; @@ -129,7 +130,7 @@ impl Winit { niri: &mut Niri, output: &Output, elements: &[OutputRenderElements<GlesRenderer>], - ) { + ) -> Option<&DmabufFeedback> { let _span = tracy_client::span!("Winit::render"); self.backend.bind().unwrap(); @@ -152,6 +153,8 @@ impl Winit { self.backend.window().request_redraw(); } + + None } pub fn toggle_debug_tint(&mut self) { diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 0e330322..95fc3fa9 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -92,7 +92,7 @@ impl DmabufHandler for State { match self.backend.renderer().import_dmabuf(&dmabuf, None) { Ok(_texture) => Ok(()), Err(err) => { - warn!("error importing dmabuf: {err:?}"); + debug!("error importing dmabuf: {err:?}"); Err(ImportError::Failed) } } diff --git a/src/layout.rs b/src/layout.rs index 24a51b42..06608466 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -46,6 +46,7 @@ use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{Logical, Point, Rectangle, Scale, Size}; use smithay::wayland::compositor::{with_states, SurfaceData}; +use smithay::wayland::dmabuf::DmabufFeedback; use smithay::wayland::shell::xdg::SurfaceCachedState; use crate::animation::Animation; @@ -79,6 +80,14 @@ pub trait LayoutElement: SpaceElement + PartialEq + Clone { ) where T: Into<Duration>, F: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy; + fn send_dmabuf_feedback<'a, P, F>( + &self, + output: &Output, + primary_scan_out_output: P, + select_dmabuf_feedback: F, + ) where + P: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy, + F: Fn(&WlSurface, &SurfaceData) -> &'a DmabufFeedback + Copy; } #[derive(Debug)] @@ -220,6 +229,18 @@ impl LayoutElement for Window { { self.send_frame(output, time, throttle, primary_scan_out_output); } + + fn send_dmabuf_feedback<'a, P, F>( + &self, + output: &Output, + primary_scan_out_output: P, + select_dmabuf_feedback: F, + ) where + P: FnMut(&WlSurface, &SurfaceData) -> Option<Output> + Copy, + F: Fn(&WlSurface, &SurfaceData) -> &'a DmabufFeedback + Copy, + { + self.send_dmabuf_feedback(output, primary_scan_out_output, select_dmabuf_feedback); + } } impl ColumnWidth { @@ -464,6 +485,16 @@ impl<W: LayoutElement> MonitorSet<W> { } } + pub fn send_dmabuf_feedback(&self, output: &Output, feedback: &DmabufFeedback) { + if let MonitorSet::Normal { monitors, .. } = self { + for mon in monitors { + if &mon.output == output { + mon.workspaces[mon.active_workspace_idx].send_dmabuf_feedback(feedback); + } + } + } + } + pub fn find_window_and_output(&mut self, wl_surface: &WlSurface) -> Option<(W, Output)> { if let MonitorSet::Normal { monitors, .. } = self { for mon in monitors { @@ -1506,6 +1537,13 @@ impl<W: LayoutElement> Workspace<W> { } } + fn send_dmabuf_feedback(&self, feedback: &DmabufFeedback) { + let output = self.output.as_ref().unwrap(); + for win in self.windows() { + win.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback); + } + } + fn view_pos(&self) -> i32 { self.column_x(self.active_column_idx) + self.view_offset - PADDING } diff --git a/src/niri.rs b/src/niri.rs index 364acf1d..12dad95b 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -19,8 +19,9 @@ use smithay::backend::renderer::element::{ use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::backend::renderer::{Bind, ExportMem, Frame, ImportAll, Offscreen, Renderer}; use smithay::desktop::utils::{ - send_frames_surface_tree, surface_presentation_feedback_flags_from_states, - take_presentation_feedback_surface_tree, OutputPresentationFeedback, + send_dmabuf_feedback_surface_tree, send_frames_surface_tree, + surface_presentation_feedback_flags_from_states, take_presentation_feedback_surface_tree, + OutputPresentationFeedback, }; use smithay::desktop::{ layer_map_for_output, LayerSurface, PopupManager, Space, Window, WindowSurfaceType, @@ -43,6 +44,7 @@ use smithay::utils::{ }; use smithay::wayland::compositor::{with_states, CompositorClientState, CompositorState}; use smithay::wayland::data_device::DataDeviceState; +use smithay::wayland::dmabuf::DmabufFeedback; use smithay::wayland::output::OutputManagerState; use smithay::wayland::pointer_gestures::PointerGesturesState; use smithay::wayland::presentation::PresentationState; @@ -378,7 +380,7 @@ impl Niri { pub fn remove_output(&mut self, output: &Output) { let mut state = self.output_state.remove(output).unwrap(); - self.display_handle.remove_global::<Niri>(state.global); + self.display_handle.remove_global::<State>(state.global); if let Some(idle) = state.queued_redraw.take() { idle.cancel(); @@ -698,12 +700,45 @@ impl Niri { let elements = self.render(backend.renderer(), output); // Hand it over to the backend. - backend.render(self, output, &elements); + let dmabuf_feedback = backend.render(self, output, &elements); + + // Send the dmabuf feedbacks. + if let Some(feedback) = dmabuf_feedback { + self.send_dmabuf_feedbacks(output, feedback); + } // Send the frame callbacks. self.send_frame_callbacks(output); } + fn send_dmabuf_feedbacks(&self, output: &Output, feedback: &DmabufFeedback) { + let _span = tracy_client::span!("Niri::send_dmabuf_feedbacks"); + + self.monitor_set.send_dmabuf_feedback(output, feedback); + + for surface in layer_map_for_output(output).layers() { + surface.send_dmabuf_feedback(output, |_, _| Some(output.clone()), |_, _| feedback); + } + + if let Some(surface) = &self.dnd_icon { + send_dmabuf_feedback_surface_tree( + surface, + output, + |_, _| Some(output.clone()), + |_, _| feedback, + ); + } + + if let CursorImageStatus::Surface(surface) = &self.cursor_image { + send_dmabuf_feedback_surface_tree( + surface, + output, + |_, _| Some(output.clone()), + |_, _| feedback, + ); + } + } + fn send_frame_callbacks(&self, output: &Output) { let _span = tracy_client::span!("Niri::send_frame_callbacks"); |
