aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-08-16 10:59:34 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-08-16 10:59:34 +0400
commit6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060 (patch)
tree59a772a946a7b50593075e73f2edccf7ebf4d8d0 /src
parentd4d2cefe50b13222a2eb45f59d4b80f8b8d4f634 (diff)
downloadniri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.tar.gz
niri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.tar.bz2
niri-6e36ccb1bd4ca6a5e4374e1fa50e519599d7a060.zip
Implement wp-presentation
Diffstat (limited to 'src')
-rw-r--r--src/handlers/mod.rs4
-rw-r--r--src/layout.rs9
-rw-r--r--src/niri.rs70
-rw-r--r--src/tty.rs48
-rw-r--r--src/winit.rs20
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! {
diff --git a/src/tty.rs b/src/tty.rs
index a69a4887..3fcebe06 100644
--- a/src/tty.rs
+++ b/src/tty.rs
@@ -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();
}
}