mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-30 20:34:49 +01:00
Fix panic when powering off outputs
This commit is contained in:
parent
d924c44611
commit
9b25372048
8 changed files with 64 additions and 77 deletions
|
@ -1343,7 +1343,9 @@ impl output_service_server::OutputService for OutputService {
|
|||
return;
|
||||
};
|
||||
|
||||
state.backend.set_output_powered(&output, powered);
|
||||
state
|
||||
.backend
|
||||
.set_output_powered(&output, &state.pinnacle.loop_handle, powered);
|
||||
|
||||
if powered {
|
||||
state.schedule_render(&output);
|
||||
|
|
|
@ -7,7 +7,7 @@ use smithay::{
|
|||
},
|
||||
delegate_dmabuf,
|
||||
output::Output,
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
reexports::{calloop::LoopHandle, wayland_server::protocol::wl_surface::WlSurface},
|
||||
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
||||
};
|
||||
use tracing::error;
|
||||
|
@ -98,10 +98,15 @@ impl Backend {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_output_powered(&mut self, output: &Output, powered: bool) {
|
||||
pub fn set_output_powered(
|
||||
&mut self,
|
||||
output: &Output,
|
||||
loop_handle: &LoopHandle<'static, State>,
|
||||
powered: bool,
|
||||
) {
|
||||
match self {
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Udev(udev) => udev.set_output_powered(output, powered),
|
||||
Backend::Udev(udev) => udev.set_output_powered(output, loop_handle, powered),
|
||||
#[cfg(feature = "testing")]
|
||||
Backend::Dummy(dummy) => dummy.set_output_powered(output, powered),
|
||||
}
|
||||
|
@ -122,7 +127,7 @@ impl Backend {
|
|||
}
|
||||
}
|
||||
#[cfg(feature = "testing")]
|
||||
Backend::Dummy(_) => todo!(),
|
||||
Backend::Dummy(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ use crate::{
|
|||
|
||||
use self::drm::util::EdidInfo;
|
||||
|
||||
use super::{BackendData, RenderResult, UninitBackend};
|
||||
use super::{BackendData, UninitBackend};
|
||||
|
||||
const SUPPORTED_FORMATS: &[Fourcc] = &[
|
||||
Fourcc::Abgr2101010,
|
||||
|
@ -463,49 +463,37 @@ impl Udev {
|
|||
return;
|
||||
};
|
||||
|
||||
// tracing::info!(state = ?surface.render_state, name = output.name());
|
||||
|
||||
let old_state = mem::take(&mut surface.render_state);
|
||||
|
||||
surface.render_state = match old_state {
|
||||
RenderState::Idle => {
|
||||
// let output = output.clone();
|
||||
// let token = loop_handle.insert_idle(move |state| {
|
||||
// state
|
||||
// .backend
|
||||
// .udev_mut()
|
||||
// .render_surface(&mut state.pinnacle, &output);
|
||||
// });
|
||||
// tracing::info!(
|
||||
// ?old_state,
|
||||
// op = output.name(),
|
||||
// powered = output.with_state(|state| state.powered),
|
||||
// "scheduled render"
|
||||
// );
|
||||
|
||||
surface.render_state = match old_state {
|
||||
RenderState::Idle => RenderState::Scheduled,
|
||||
|
||||
RenderState::Scheduled
|
||||
}
|
||||
value @ (RenderState::Scheduled
|
||||
| RenderState::WaitingForEstimatedVblankAndScheduled(_)) => value,
|
||||
|
||||
RenderState::WaitingForVblank { render_needed: _ } => RenderState::WaitingForVblank {
|
||||
render_needed: true,
|
||||
},
|
||||
|
||||
RenderState::WaitingForEstimatedVblank(token) => {
|
||||
RenderState::WaitingForEstimatedVblankAndScheduled(token)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// pub fn render_scheduled_outputs(&mut self, pinnacle: &mut Pinnacle) {
|
||||
// for output in pinnacle.outputs.keys().cloned().collect::<Vec<_>>() {
|
||||
// let Some(surface) = render_surface_for_output(&output, &mut self.backends) else {
|
||||
// continue;
|
||||
// };
|
||||
//
|
||||
// if matches!(
|
||||
// surface.render_state,
|
||||
// RenderState::Scheduled | RenderState::WaitingForEstimatedVblankAndScheduled(_)
|
||||
// ) {
|
||||
// self.render_surface(pinnacle, &output);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
pub(super) fn set_output_powered(&mut self, output: &Output, powered: bool) {
|
||||
pub(super) fn set_output_powered(
|
||||
&mut self,
|
||||
output: &Output,
|
||||
loop_handle: &LoopHandle<'static, State>,
|
||||
powered: bool,
|
||||
) {
|
||||
let UdevOutputData { device_id, crtc } =
|
||||
output.user_data().get::<UdevOutputData>().unwrap();
|
||||
|
||||
|
@ -535,11 +523,12 @@ impl Udev {
|
|||
}
|
||||
|
||||
if let Some(surface) = render_surface_for_output(output, &mut self.backends) {
|
||||
// TODO: test
|
||||
surface.render_state = RenderState::Idle;
|
||||
// if let RenderState::Scheduled(idle) = std::mem::take(&mut surface.render_state) {
|
||||
// idle.cancel();
|
||||
// }
|
||||
if let RenderState::WaitingForEstimatedVblankAndScheduled(token)
|
||||
| RenderState::WaitingForEstimatedVblank(token) =
|
||||
mem::take(&mut surface.render_state)
|
||||
{
|
||||
loop_handle.remove(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1222,11 +1211,6 @@ impl Udev {
|
|||
return;
|
||||
};
|
||||
|
||||
if matches!(surface.render_state, RenderState::Idle) {
|
||||
warn!(output = output.name(), "Got vblank for an idle output");
|
||||
return;
|
||||
}
|
||||
|
||||
match surface
|
||||
.compositor
|
||||
.frame_submitted()
|
||||
|
@ -1284,7 +1268,6 @@ impl Udev {
|
|||
RenderState::WaitingForVblank { render_needed } => render_needed,
|
||||
state => {
|
||||
debug!("vblank happened but render state was {state:?}",);
|
||||
// TODO: unreachable
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
@ -1317,21 +1300,21 @@ impl Udev {
|
|||
|
||||
/// Render to the [`RenderSurface`] associated with the given `output`.
|
||||
#[tracing::instrument(level = "debug", skip(self, pinnacle), fields(output = output.name()))]
|
||||
fn render_surface(&mut self, pinnacle: &mut Pinnacle, output: &Output) -> RenderResult {
|
||||
fn render_surface(&mut self, pinnacle: &mut Pinnacle, output: &Output) {
|
||||
let Some(surface) = render_surface_for_output(output, &mut self.backends) else {
|
||||
return RenderResult::Skipped;
|
||||
return;
|
||||
};
|
||||
|
||||
if !pinnacle.outputs.contains_key(output) {
|
||||
surface.render_state = RenderState::Idle;
|
||||
return RenderResult::Skipped;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: possibly lift this out and make it so that scheduling a render
|
||||
// does nothing on powered off outputs
|
||||
if output.with_state(|state| !state.powered) {
|
||||
surface.render_state = RenderState::Idle;
|
||||
return RenderResult::Skipped;
|
||||
return;
|
||||
}
|
||||
|
||||
assert_matches!(
|
||||
|
@ -1503,7 +1486,7 @@ impl Udev {
|
|||
Ok(rendered)
|
||||
})();
|
||||
|
||||
let render_result = match result {
|
||||
match result {
|
||||
Ok(true) => {
|
||||
let new_state = RenderState::WaitingForVblank {
|
||||
render_needed: false,
|
||||
|
@ -1527,9 +1510,9 @@ impl Udev {
|
|||
pinnacle.send_frame_callbacks(output, Some(surface.frame_callback_sequence));
|
||||
|
||||
// Return here to not queue the estimated vblank timer on a submitted frame
|
||||
return RenderResult::Submitted;
|
||||
return;
|
||||
}
|
||||
Ok(false) => RenderResult::NoDamage,
|
||||
Ok(false) => (),
|
||||
Err(err) => {
|
||||
warn!(output = output.name(), "Render failed for surface: {err}");
|
||||
|
||||
|
@ -1542,18 +1525,14 @@ impl Udev {
|
|||
} else {
|
||||
RenderState::Idle
|
||||
};
|
||||
|
||||
RenderResult::Skipped
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
self.queue_estimated_vblank_timer(pinnacle, output, time_to_next_presentation);
|
||||
|
||||
// if render_after_transaction_finish {
|
||||
// self.schedule_render(output);
|
||||
// }
|
||||
|
||||
render_result
|
||||
}
|
||||
|
||||
fn queue_estimated_vblank_timer(
|
||||
|
|
|
@ -44,7 +44,7 @@ use crate::{
|
|||
state::{Pinnacle, State, WithState},
|
||||
};
|
||||
|
||||
use super::{Backend, BackendData, RenderResult, UninitBackend};
|
||||
use super::{Backend, BackendData, UninitBackend};
|
||||
|
||||
const LOGO_BYTES: &[u8] = include_bytes!("../../resources/pinnacle_logo_icon.rgba");
|
||||
|
||||
|
@ -244,7 +244,6 @@ impl Winit {
|
|||
|
||||
/// Schedule a render on the winit window.
|
||||
pub fn schedule_render(&mut self) {
|
||||
trace!("Scheduling winit render");
|
||||
self.output_render_scheduled = true;
|
||||
}
|
||||
|
||||
|
@ -255,7 +254,7 @@ impl Winit {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn render_winit_window(&mut self, pinnacle: &mut Pinnacle) -> RenderResult {
|
||||
pub(super) fn render_winit_window(&mut self, pinnacle: &mut Pinnacle) {
|
||||
let full_redraw = &mut self.full_redraw;
|
||||
*full_redraw = full_redraw.saturating_sub(1);
|
||||
|
||||
|
@ -377,7 +376,7 @@ impl Winit {
|
|||
})
|
||||
});
|
||||
|
||||
let render_result = match render_res {
|
||||
match render_res {
|
||||
Ok(render_output_result) => {
|
||||
if pinnacle.lock_state.is_unlocked() {
|
||||
Winit::handle_pending_screencopy(
|
||||
|
@ -425,14 +424,10 @@ impl Winit {
|
|||
0,
|
||||
wp_presentation_feedback::Kind::Vsync,
|
||||
);
|
||||
RenderResult::Submitted
|
||||
} else {
|
||||
RenderResult::NoDamage
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("{}", err);
|
||||
RenderResult::Skipped
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -445,8 +440,6 @@ impl Winit {
|
|||
if render_after_transaction_finish {
|
||||
self.schedule_render();
|
||||
}
|
||||
|
||||
render_result
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,10 @@ impl OutputFocusStack {
|
|||
self.stack.retain(|op| op != &output);
|
||||
self.stack.push(output);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, output: &Output) {
|
||||
self.stack.retain(|op| op != output);
|
||||
}
|
||||
}
|
||||
|
||||
/// A stack of windows, with the top one being the one in focus.
|
||||
|
|
|
@ -928,7 +928,8 @@ impl OutputManagementHandler for State {
|
|||
OutputConfiguration::Disabled => {
|
||||
self.pinnacle.set_output_enabled(&output, false);
|
||||
// TODO: split
|
||||
self.backend.set_output_powered(&output, false);
|
||||
self.backend
|
||||
.set_output_powered(&output, &self.pinnacle.loop_handle, false);
|
||||
}
|
||||
OutputConfiguration::Enabled {
|
||||
mode,
|
||||
|
@ -939,7 +940,8 @@ impl OutputManagementHandler for State {
|
|||
} => {
|
||||
self.pinnacle.set_output_enabled(&output, true);
|
||||
// TODO: split
|
||||
self.backend.set_output_powered(&output, true);
|
||||
self.backend
|
||||
.set_output_powered(&output, &self.pinnacle.loop_handle, true);
|
||||
|
||||
self.capture_snapshots_on_output(&output, []);
|
||||
|
||||
|
@ -1001,7 +1003,8 @@ impl OutputPowerManagementHandler for State {
|
|||
}
|
||||
|
||||
fn set_mode(&mut self, output: &Output, powered: bool) {
|
||||
self.backend.set_output_powered(output, powered);
|
||||
self.backend
|
||||
.set_output_powered(output, &self.pinnacle.loop_handle, powered);
|
||||
|
||||
if powered {
|
||||
self.schedule_render(output);
|
||||
|
|
|
@ -349,6 +349,8 @@ impl Pinnacle {
|
|||
|
||||
self.space.unmap_output(output);
|
||||
|
||||
self.output_focus_stack.remove(output);
|
||||
|
||||
self.gamma_control_manager_state.output_removed(output);
|
||||
|
||||
self.output_power_management_state.output_removed(output);
|
||||
|
|
11
src/state.rs
11
src/state.rs
|
@ -243,15 +243,14 @@ impl State {
|
|||
|
||||
// FIXME: Don't poll this every cycle
|
||||
for output in self.pinnacle.space.outputs().cloned().collect::<Vec<_>>() {
|
||||
output.with_state_mut(|state| {
|
||||
if state
|
||||
if output.with_state_mut(|state| {
|
||||
state
|
||||
.layout_transaction
|
||||
.as_ref()
|
||||
.is_some_and(|ts| ts.ready())
|
||||
{
|
||||
self.schedule_render(&output);
|
||||
}
|
||||
});
|
||||
}) {
|
||||
self.schedule_render(&output);
|
||||
}
|
||||
}
|
||||
|
||||
self.pinnacle
|
||||
|
|
Loading…
Add table
Reference in a new issue