From 7572523cfce652d972286e4dc905a6e81b9ea56f Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sun, 15 Oct 2023 03:13:21 -0500 Subject: [PATCH] Fix winit rendering --- src/backend/udev.rs | 70 ++------------------------------------------ src/backend/winit.rs | 70 +++++++++++--------------------------------- src/render.rs | 6 ++-- 3 files changed, 22 insertions(+), 124 deletions(-) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 9815b95..e75e2d4 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -680,7 +680,7 @@ impl State { let then = udev.last_vblank_time; let now = Instant::now(); let diff = now.duration_since(then); - tracing::debug!(time = diff.as_secs_f64(), "Time since last vblank"); + // tracing::debug!(time = diff.as_secs_f64(), "Time since last vblank"); udev.last_vblank_time = now; } data.state.on_vblank(node, crtc, metadata); @@ -1160,19 +1160,10 @@ impl State { }); } } - - // if schedule_render { - // // Anvil had some stuff here about delaying a render to reduce latency, - // // but it introduces visible hitching when scrolling, so I'm removing it here. - // // - // // If latency is a problem then future me can deal with it :) - // self.loop_handle.insert_idle(move |data| { - // data.state.render_surface(&output); - // }); - // } } /// Render to the [`RenderSurface`] associated with the given `output`. + #[tracing::instrument(level = "debug", skip(self), fields(output = output.name()))] fn render_surface(&mut self, output: &Output) { let udev = self.backend.udev_mut(); @@ -1267,63 +1258,6 @@ impl State { Ok(true) => surface.render_state = RenderState::WaitingForVblank { dirty: false }, Ok(false) | Err(_) => surface.render_state = RenderState::Idle, } - - // let reschedule = match &result { - // Ok(has_rendered) => !has_rendered, - // Err(err) => { - // tracing::warn!("Error during rendering: {:?}", err); - // match err { - // SwapBuffersError::AlreadySwapped => false, - // SwapBuffersError::TemporaryFailure(err) => !matches!( - // err.downcast_ref::(), - // Some(&DrmError::DeviceInactive) - // | Some(&DrmError::Access { - // source: drm::SystemError::PermissionDenied, - // .. - // }) - // ), - // SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), - // } - // } - // }; - // - // if reschedule { - // tracing::debug!("rescheduling due to no dmg or error"); - // let Some(data) = output.user_data().get::() else { - // unreachable!() - // }; - // - // // Literally no idea if this refresh time calculation is doing anything, but we're - // // gonna keep it here because I already added the stuff for it - // let refresh_time = if let Some(mode) = data.mode { - // self::utils::refresh_time(mode) - // } else { - // let output_refresh = match output.current_mode() { - // Some(mode) => mode.refresh, - // None => { - // return; - // } - // }; - // Duration::from_millis((1_000_000f32 / output_refresh as f32) as u64) - // }; - // - // // If reschedule is true we either hit a temporary failure or more likely rendering - // // did not cause any damage on the output. In this case we just re-schedule a repaint - // // after approx. one frame to re-test for damage. - // tracing::trace!( - // "reschedule repaint timer with delay {:?} on {}", - // refresh_time, - // output.name(), - // ); - // let timer = Timer::from_duration(refresh_time); - // let output = output.clone(); - // self.loop_handle - // .insert_source(timer, move |_, _, data| { - // data.state.render_surface(&output); - // TimeoutAction::Drop - // }) - // .expect("failed to schedule frame timer"); - // } } } diff --git a/src/backend/winit.rs b/src/backend/winit.rs index f211701..ce360e6 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -24,7 +24,10 @@ use smithay::{ timer::{TimeoutAction, Timer}, EventLoop, }, - wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, + wayland_protocols::{ + wp::presentation_time::server::wp_presentation_feedback, + xdg::shell::server::xdg_toplevel, + }, wayland_server::{protocol::wl_surface::WlSurface, Display}, }, utils::{IsAlive, Transform}, @@ -44,7 +47,6 @@ pub struct Winit { pub damage_tracker: OutputDamageTracker, pub dmabuf_state: (DmabufState, DmabufGlobal, Option), pub full_redraw: u8, - render_state: RenderState, } impl BackendData for Winit { @@ -60,11 +62,6 @@ impl BackendData for Winit { } impl Backend { - fn winit(&self) -> &Winit { - let Backend::Winit(winit) = self else { unreachable!() }; - winit - } - fn winit_mut(&mut self) -> &mut Winit { let Backend::Winit(winit) = self else { unreachable!() }; winit @@ -169,7 +166,6 @@ pub fn run_winit() -> anyhow::Result<()> { damage_tracker: OutputDamageTracker::from_output(&output), dmabuf_state, full_redraw: 0, - render_state: RenderState::Idle, }), display, event_loop.get_signal(), @@ -227,7 +223,7 @@ pub fn run_winit() -> anyhow::Result<()> { state.process_input_event(input_evt); } WinitEvent::Refresh => { - state.schedule_render(&output); + state.render_window(&output); } }); @@ -238,33 +234,14 @@ pub fn run_winit() -> anyhow::Result<()> { } }; + state.render_window(&output); + TimeoutAction::ToDuration(Duration::from_micros(((1.0 / 144.0) * 1000000.0) as u64)) }); if let Err(err) = insert_ret { anyhow::bail!("Failed to insert winit events into event loop: {err}"); } - let frame_time = Duration::from_micros(((1.0 / 144.0) * 1000000.0) as u64); - let refresh_timer = Timer::from_duration(frame_time); - state - .loop_handle - .insert_source(refresh_timer, move |instant, _, data| { - let winit = data.state.backend.winit(); - - winit.backend.window().request_redraw(); - - let frame_time = winit - .backend - .window() - .current_monitor() - .and_then(|monitor| monitor.refresh_rate_millihertz()) - .map(|rate| Duration::from_secs_f64(1000.0 / rate as f64)) - .unwrap_or(frame_time); - - TimeoutAction::ToInstant(instant + frame_time) - }) - .expect("failed to insert render timer into event loop"); - event_loop.run( Some(Duration::from_micros(((1.0 / 144.0) * 1000000.0) as u64)), &mut CalloopData { @@ -283,31 +260,10 @@ pub fn run_winit() -> anyhow::Result<()> { Ok(()) } -enum RenderState { - Idle, - Scheduled, -} - -impl Winit { - pub fn schedule_render(&mut self, loop_handle: &LoopHandle, output: &Output) { - match &self.render_state { - RenderState::Idle => { - let output = output.clone(); - loop_handle.insert_idle(move |data| data.state.render_window(&output)); - - self.render_state = RenderState::Scheduled; - } - RenderState::Scheduled => (), - } - } -} - impl State { fn render_window(&mut self, output: &Output) { let winit = self.backend.winit_mut(); - assert!(matches!(winit.render_state, RenderState::Scheduled)); - let pending_wins = self .windows .iter() @@ -322,6 +278,16 @@ impl State { }; pending_size || win.with_state(|state| !state.loc_request_state.is_idle()) }) + .filter(|win| { + if let WindowElement::Wayland(win) = win { + !win.toplevel() + .current_state() + .states + .contains(xdg_toplevel::State::Resizing) + } else { + true + } + }) .map(|win| { ( win.class().unwrap_or("None".to_string()), @@ -347,7 +313,6 @@ impl State { // TODO: still draw the cursor here - winit.render_state = RenderState::Idle; return; } let full_redraw = &mut winit.full_redraw; @@ -448,6 +413,5 @@ impl State { tracing::warn!("{}", err); } } - winit.render_state = RenderState::Idle; } } diff --git a/src/render.rs b/src/render.rs index 5508800..b4de8c6 100644 --- a/src/render.rs +++ b/src/render.rs @@ -407,9 +407,9 @@ pub fn take_presentation_feedback( impl State { pub fn schedule_render(&mut self, output: &Output) { - match &mut self.backend { - Backend::Winit(winit) => winit.schedule_render(&self.loop_handle, output), - Backend::Udev(udev) => udev.schedule_render(&self.loop_handle, output), + // I'm relegating winit to render every frame because it's not my priority right now + if let Backend::Udev(udev) = &mut self.backend { + udev.schedule_render(&self.loop_handle, output); } } }