diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-16 10:59:34 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-16 10:59:34 +0400 |
| commit | 6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060 (patch) | |
| tree | 59a772a946a7b50593075e73f2edccf7ebf4d8d0 /src | |
| parent | d4d2cefe50b13222a2eb45f59d4b80f8b8d4f634 (diff) | |
| download | niri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.tar.gz niri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.tar.bz2 niri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.zip | |
Implement wp-presentation
Diffstat (limited to 'src')
| -rw-r--r-- | src/handlers/mod.rs | 4 | ||||
| -rw-r--r-- | src/layout.rs | 9 | ||||
| -rw-r--r-- | src/niri.rs | 70 | ||||
| -rw-r--r-- | src/tty.rs | 48 | ||||
| -rw-r--r-- | src/winit.rs | 20 |
5 files changed, 131 insertions, 20 deletions
diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index b327a9e4..fecc3b32 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -11,7 +11,7 @@ use smithay::wayland::data_device::{ set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler, }; -use smithay::{delegate_data_device, delegate_output, delegate_seat}; +use smithay::{delegate_data_device, delegate_output, delegate_presentation, delegate_seat}; use crate::Niri; @@ -68,3 +68,5 @@ impl ServerDndGrabHandler for Niri {} delegate_data_device!(Niri); delegate_output!(Niri); + +delegate_presentation!(Niri); diff --git a/src/layout.rs b/src/layout.rs index 8a090c07..d47ff1be 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -560,6 +560,15 @@ impl<W: LayoutElement> MonitorSet<W> { }) } + pub fn windows_for_output(&self, output: &Output) -> impl Iterator<Item = &W> + '_ { + let MonitorSet::Normal { monitors, .. } = self else { + panic!() + }; + + let mon = monitors.iter().find(|mon| &mon.output == output).unwrap(); + mon.workspaces.iter().flat_map(|ws| ws.windows()) + } + fn active_monitor(&mut self) -> Option<&mut Monitor<W>> { let MonitorSet::Normal { monitors, diff --git a/src/niri.rs b/src/niri.rs index 32a5d319..587a0f9b 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -7,10 +7,13 @@ use smithay::backend::renderer::element::surface::{ render_elements_from_surface_tree, WaylandSurfaceRenderElement, }; use smithay::backend::renderer::element::texture::{TextureBuffer, TextureRenderElement}; -use smithay::backend::renderer::element::{render_elements, AsRenderElements}; +use smithay::backend::renderer::element::{render_elements, AsRenderElements, RenderElementStates}; use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture}; use smithay::backend::renderer::{ImportAll, Renderer}; -use smithay::desktop::utils::send_frames_surface_tree; +use smithay::desktop::utils::{ + 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, }; @@ -20,6 +23,7 @@ use smithay::input::{Seat, SeatState}; use smithay::output::Output; use smithay::reexports::calloop::generic::Generic; use smithay::reexports::calloop::{Idle, Interest, LoopHandle, LoopSignal, Mode, PostAction}; +use smithay::reexports::nix::libc::CLOCK_MONOTONIC; use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::WmCapabilities; use smithay::reexports::wayland_server::backend::{ ClientData, ClientId, DisconnectReason, GlobalId, @@ -30,6 +34,7 @@ use smithay::utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, SERIAL use smithay::wayland::compositor::{with_states, CompositorClientState, CompositorState}; use smithay::wayland::data_device::DataDeviceState; use smithay::wayland::output::OutputManagerState; +use smithay::wayland::presentation::PresentationState; use smithay::wayland::shell::wlr_layer::{Layer, WlrLayerShellState}; use smithay::wayland::shell::xdg::XdgShellState; use smithay::wayland::shm::ShmState; @@ -69,6 +74,7 @@ pub struct Niri { pub seat_state: SeatState<Self>, pub data_device_state: DataDeviceState, pub popups: PopupManager, + pub presentation_state: PresentationState, pub seat: Seat<Self>, @@ -109,6 +115,8 @@ impl Niri { let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle); let mut seat_state = SeatState::new(); let data_device_state = DataDeviceState::new::<Self>(&display_handle); + let presentation_state = + PresentationState::new::<Self>(&display_handle, CLOCK_MONOTONIC as u32); let mut seat: Seat<Self> = seat_state.new_wl_seat(&display_handle, seat_name); // FIXME: get Xkb and repeat interval from GNOME dconf. @@ -169,6 +177,7 @@ impl Niri { seat_state, data_device_state, popups: PopupManager::default(), + presentation_state, seat, pointer_buffer: None, @@ -544,6 +553,9 @@ impl Niri { }), ); + // backend.render() uses this. + drop(layer_map); + // Hand it over to the backend. backend.render(self, output, &elements); @@ -551,7 +563,7 @@ impl Niri { let frame_callback_time = self.start_time.elapsed(); self.monitor_set.send_frame(output, frame_callback_time); - for surface in layer_map.layers() { + for surface in layer_map_for_output(output).layers() { surface.send_frame(output, frame_callback_time, None, |_, _| { Some(output.clone()) }); @@ -569,6 +581,58 @@ impl Niri { }); } } + + pub fn take_presentation_feedbacks( + &mut self, + output: &Output, + render_element_states: &RenderElementStates, + ) -> OutputPresentationFeedback { + let mut feedback = OutputPresentationFeedback::new(output); + + if let CursorImageStatus::Surface(surface) = &self.cursor_image { + take_presentation_feedback_surface_tree( + surface, + &mut feedback, + |_, _| Some(output.clone()), + |surface, _| { + surface_presentation_feedback_flags_from_states(surface, render_element_states) + }, + ); + } + + if let Some(surface) = &self.dnd_icon { + take_presentation_feedback_surface_tree( + surface, + &mut feedback, + |_, _| Some(output.clone()), + |surface, _| { + surface_presentation_feedback_flags_from_states(surface, render_element_states) + }, + ); + } + + for win in self.monitor_set.windows_for_output(output) { + win.take_presentation_feedback( + &mut feedback, + |_, _| Some(output.clone()), + |surface, _| { + surface_presentation_feedback_flags_from_states(surface, render_element_states) + }, + ) + } + + for surface in layer_map_for_output(output).layers() { + surface.take_presentation_feedback( + &mut feedback, + |_, _| Some(output.clone()), + |surface, _| { + surface_presentation_feedback_flags_from_states(surface, render_element_states) + }, + ); + } + + feedback + } } render_elements! { @@ -16,6 +16,7 @@ use smithay::backend::renderer::{Bind, ImportEgl}; use smithay::backend::session::libseat::LibSeatSession; use smithay::backend::session::{Event as SessionEvent, Session}; use smithay::backend::udev::{self, UdevBackend, UdevEvent}; +use smithay::desktop::utils::OutputPresentationFeedback; use smithay::output::{Mode, Output, OutputModeSource, PhysicalProperties, Subpixel}; use smithay::reexports::calloop::{LoopHandle, RegistrationToken}; use smithay::reexports::drm::control::{ @@ -24,6 +25,7 @@ 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::presentation_time::server::wp_presentation_feedback; use smithay::utils::DeviceFd; use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner}; use smithay_drm_extras::edid::EdidInfo; @@ -42,8 +44,12 @@ pub struct Tty { output_device: Option<OutputDevice>, } -type GbmDrmCompositor = - DrmCompositor<GbmAllocator<DrmDeviceFd>, GbmDevice<DrmDeviceFd>, (), DrmDeviceFd>; +type GbmDrmCompositor = DrmCompositor< + GbmAllocator<DrmDeviceFd>, + GbmDevice<DrmDeviceFd>, + OutputPresentationFeedback, + DrmDeviceFd, +>; struct OutputDevice { id: dev_t, @@ -91,7 +97,10 @@ impl Backend for Tty { Ok(res) => { assert!(!res.needs_sync()); if res.damage.is_some() { - match drm_compositor.queue_frame(()) { + let presentation_feedbacks = + niri.take_presentation_feedbacks(output, &res.states); + + match drm_compositor.queue_frame(presentation_feedbacks) { Ok(()) => { niri.output_state .get_mut(output) @@ -246,11 +255,6 @@ impl Tty { let device = tty.output_device.as_mut().unwrap(); let drm_compositor = device.surfaces.get_mut(&crtc).unwrap(); - // Mark the last frame as submitted. - if let Err(err) = drm_compositor.frame_submitted() { - error!("error marking frame as submitted: {err}"); - } - let presentation_time = match metadata.as_mut().unwrap().time { DrmEventTime::Monotonic(time) => time, DrmEventTime::Realtime(_) => { @@ -261,10 +265,30 @@ impl Tty { } }; - // Send presentation time feedback. - // catacomb - // .windows - // .mark_presented(&output_device.last_render_states, metadata); + // Mark the last frame as submitted. + match drm_compositor.frame_submitted() { + Ok(Some(mut feedback)) => { + let refresh = + feedback.output().unwrap().current_mode().unwrap().refresh + as u32; + // FIXME: ideally should be monotonically increasing for a surface. + let seq = metadata.as_ref().unwrap().sequence as u64; + let flags = wp_presentation_feedback::Kind::Vsync + | wp_presentation_feedback::Kind::HwClock + | wp_presentation_feedback::Kind::HwCompletion; + + feedback.presented::<_, smithay::utils::Monotonic>( + presentation_time, + refresh, + seq, + flags, + ); + } + Ok(None) => (), + Err(err) => { + error!("error marking frame as submitted: {err}"); + } + } let output = data .niri diff --git a/src/winit.rs b/src/winit.rs index 69b92670..c8b29203 100644 --- a/src/winit.rs +++ b/src/winit.rs @@ -6,6 +6,7 @@ use smithay::backend::winit::{self, WinitError, WinitEvent, WinitEventLoop, Wini use smithay::output::{Mode, Output, PhysicalProperties, Subpixel}; use smithay::reexports::calloop::timer::{TimeoutAction, Timer}; use smithay::reexports::calloop::LoopHandle; +use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback; use smithay::reexports::winit::dpi::LogicalSize; use smithay::reexports::winit::window::WindowBuilder; use smithay::utils::Transform; @@ -13,6 +14,7 @@ use smithay::utils::Transform; use crate::backend::Backend; use crate::input::CompositorMod; use crate::niri::OutputRenderElements; +use crate::utils::get_monotonic_time; use crate::{LoopData, Niri}; pub struct Winit { @@ -33,20 +35,30 @@ impl Backend for Winit { fn render( &mut self, - _niri: &mut Niri, - _output: &Output, + niri: &mut Niri, + output: &Output, elements: &[OutputRenderElements<GlesRenderer>], ) { let _span = tracy_client::span!("Winit::render"); self.backend.bind().unwrap(); let age = self.backend.buffer_age().unwrap(); - let result = self + let res = self .damage_tracker .render_output(self.backend.renderer(), age, elements, [0.1, 0.1, 0.1, 1.0]) .unwrap(); - if let Some(damage) = result.damage { + if let Some(damage) = res.damage { self.backend.submit(Some(&damage)).unwrap(); + + let mut presentation_feedbacks = niri.take_presentation_feedbacks(output, &res.states); + let refresh = output.current_mode().unwrap().refresh as u32; + presentation_feedbacks.presented::<_, smithay::utils::Monotonic>( + get_monotonic_time(), + refresh, + 0, + wp_presentation_feedback::Kind::empty(), + ); + self.backend.window().request_redraw(); } } |
