Explain runtime invariants and avoid redundant unwraps

This commit is contained in:
Samuel Onoja committed 2026-10-22 01:28:03 +01:00
1 parent 34f2f07301
commit 1b51ba83b4
116 files changed
+1643 -515

No files matched your search

+116 -31
View File
@@ -387,7 +387,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.topology
.observe_devices(&[(
primary_path.clone(),
@@ -640,25 +640,43 @@ pub(crate) fn set_output_profile(state: &mut Ferese, name: &str) -> Result<(), S
return Err("profile does not match the connected monitors/lid".into());
}
if let Err(error) = validate_live_outputs(state, &state.output_profiles) {
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err(error);
}
reconcile_outputs(state, false);
if let Some(error) = state.direct_backend.as_ref().unwrap().output_error.clone() {
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
if let Some(error) = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.output_error
.clone()
{
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err(error);
}
if name != "auto"
&& state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.desired_outputs
.profile
.as_deref()
!= Some(name)
{
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err("profile does not match the connected monitors/lid".into());
}
arm_output_confirmation(state, known_good, previous);
@@ -698,12 +716,26 @@ pub(crate) fn set_output_layout(
backend.manual_outputs.internal = None;
backend.manual_outputs.layout = Some(layout);
if let Err(error) = validate_live_outputs(state, &state.output_profiles) {
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err(error);
}
reconcile_outputs(state, false);
if let Some(error) = state.direct_backend.as_ref().unwrap().output_error.clone() {
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
if let Some(error) = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.output_error
.clone()
{
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err(error);
}
arm_output_confirmation(state, known_good, previous);
@@ -732,8 +764,18 @@ pub(crate) fn set_internal_output(state: &mut Ferese, enabled: bool) -> Result<(
backend.manual_outputs.internal = Some(enabled);
backend.manual_outputs.layout = None;
reconcile_outputs(state, false);
if let Some(error) = state.direct_backend.as_ref().unwrap().output_error.clone() {
state.direct_backend.as_mut().unwrap().manual_outputs = previous;
if let Some(error) = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.output_error
.clone()
{
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.manual_outputs = previous;
return Err(error);
}
arm_output_confirmation(state, known_good, previous);
@@ -750,7 +792,10 @@ fn arm_output_confirmation(
previous: DesiredOutputConfiguration,
manual: ManualOverride,
) {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
if let Some(token) = backend.confirmation_timer.take() {
state.loop_handle.remove(token);
}
@@ -781,7 +826,13 @@ fn arm_output_confirmation(
TimeoutAction::Drop
},
) {
Ok(token) => state.direct_backend.as_mut().unwrap().confirmation_timer = Some(token),
Ok(token) => {
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.confirmation_timer = Some(token)
}
Err(error) => {
tracing::warn!(%error, "could not arm monitor confirmation; reverting");
let _ = confirm_output_configuration(state, false);
@@ -809,7 +860,13 @@ pub(crate) fn confirm_output_configuration(
));
backend.manual_outputs = manual;
reconcile_outputs(state, false);
if let Some(error) = state.direct_backend.as_ref().unwrap().output_error.clone() {
if let Some(error) = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.output_error
.clone()
{
return Err(error);
}
}
@@ -1256,7 +1313,7 @@ fn redraw(
let outputs = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.iter()
.flat_map(|(node, device)| {
@@ -1274,7 +1331,7 @@ fn redraw(
let scene = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.scene_output(state, output);
selected.is_none_or(|selected| selected.contains(output) || selected.contains(&scene))
|| state.output_has_animations(&scene)
@@ -1293,7 +1350,7 @@ fn redraw(
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.scheduling_metrics
.redraw(source, selected.is_none(), requested, outputs.len());
arm_animation_timer(state);
@@ -1517,7 +1574,11 @@ fn render_output(
let damage = damage.map_or_else(
|| {
vec![smithay::utils::Rectangle::from_size(
output.output.current_mode().unwrap().size,
output
.output
.current_mode()
.expect("a rendered output must have a current mode")
.size,
)]
},
|damage| {
@@ -1641,7 +1702,13 @@ fn render_output(
restore_device(state, node, device);
if !submitted
&& scene_output
== state.direct_backend.as_ref().unwrap().devices[&node].outputs[&crtc].output
== state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.devices[&node]
.outputs[&crtc]
.output
{
schedule_frame_callbacks(state, node, crtc, plan.present_at);
}
@@ -1687,7 +1754,11 @@ fn rescan_device(state: &mut Ferese, node: DrmNode) -> Result<bool, ()> {
.and_then(|scan| transaction::apply_device(state, node, &mut device, scan));
if let Err(error) = &result {
tracing::warn!(?node, %error, "output transaction failed; restored known-good outputs where possible");
state.direct_backend.as_mut().unwrap().output_error = Some(error.clone());
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.output_error = Some(error.clone());
transaction::update_applied_info(&mut device);
}
restore_device(state, node, device);
@@ -1695,7 +1766,10 @@ fn rescan_device(state: &mut Ferese, node: DrmNode) -> Result<bool, ()> {
}
fn refresh_connected_info(state: &mut Ferese) {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
for device in backend.devices.values_mut() {
if let Ok(scan) = select_outputs(
device,
@@ -1739,7 +1813,10 @@ fn refresh_connected_info(state: &mut Ferese) {
}
fn remember_applied_configuration(state: &mut Ferese) {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
if backend.topology.reconciling {
// Applied positions are read only after the coherent logical publish.
backend.topology.remember_applied = true;
@@ -1913,17 +1990,20 @@ fn animation_fallbacks(state: &mut Ferese) -> Vec<(DrmNode, crtc::Handle, Instan
let scene = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.scene_output(state, &identity);
let animating = enabled && state.output_has_animations(&scene);
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
let output = backend
.devices
.get_mut(&node)
.unwrap()
.expect("the selected DRM device remains registered during this operation")
.outputs
.get_mut(&crtc)
.unwrap();
.expect("the selected DRM device remains registered during this operation");
// Preserve recovery of a requested final frame if another output
// advances this animation to rest before the watchdog is dispatched.
let active = enabled
@@ -2032,19 +2112,21 @@ fn arm_animation_timer(state: &mut Ferese) {
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.scheduling_metrics
.fallback_recoveries += 1;
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.get_mut(&node)
.unwrap()
.expect(
"the selected DRM device must remain registered during this operation",
)
.outputs
.get_mut(&crtc)
.unwrap()
.expect("the selected CRTC must remain registered during this operation")
.animation_fallback = AnimationFallback::default();
request_frame(state, node, crtc);
}
@@ -2054,7 +2136,10 @@ fn arm_animation_timer(state: &mut Ferese) {
TimeoutAction::Drop
}) {
Ok(token) => {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
backend.animation_timer = Some(token);
backend.animation_deadline = Some(deadline);
backend.scheduling_metrics.fallback_arms += 1;
+5 -1
View File
@@ -102,7 +102,11 @@ pub(super) fn capture_mirror(
continue;
};
let element = super::mirror::fitted_texture(
output.mirror_capture_texture.as_ref().unwrap().clone(),
output
.mirror_capture_texture
.as_ref()
.expect("successful mirror composition populated its capture texture")
.clone(),
&output.output,
smithay::backend::renderer::element::Id::new(),
Default::default(),
+46 -12
View File
@@ -148,7 +148,11 @@ fn read_acpi() -> Option<bool> {
impl Reader {
pub fn set_active(&mut self, active: bool) {
let generation = self.lease.lock().unwrap().activate(active);
let generation = self
.lease
.lock()
.expect("lid policy lease must remain consistent across workers")
.activate(active);
self.suspend_requested = false;
if active {
let _ = self.suspend.send(PolicyRequest::Activate(generation));
@@ -167,7 +171,9 @@ impl Reader {
let Ok(connection) = connection else { return };
while let Ok(request) = suspend_requests.recv() {
if let PolicyRequest::Activate(generation) = request {
let current = worker_lease.lock().unwrap();
let current = worker_lease
.lock()
.expect("lid policy lease must remain consistent across workers");
if !current.active || current.generation != generation {
continue;
}
@@ -189,14 +195,17 @@ impl Reader {
reply.body().deserialize::<zbus::zvariant::OwnedFd>()
});
match inhibitor {
Ok(descriptor) => {
worker_lease.lock().unwrap().accept(generation, descriptor)
}
Ok(descriptor) => worker_lease
.lock()
.expect("lid policy lease must remain consistent across workers")
.accept(generation, descriptor),
Err(error) => tracing::warn!(%error, "could not own logind lid policy"),
}
continue;
}
let current = worker_lease.lock().unwrap();
let current = worker_lease
.lock()
.expect("lid policy lease must remain consistent across workers");
if !current.active || !current.suspend {
continue;
}
@@ -221,7 +230,9 @@ impl Reader {
tracing::debug!("lid suspend prevented by sleep inhibitor");
continue;
}
let current = worker_lease.lock().unwrap();
let current = worker_lease
.lock()
.expect("lid policy lease must remain consistent across workers");
let requested = current.active && current.suspend;
drop(current);
if !requested {
@@ -237,7 +248,10 @@ impl Reader {
tracing::warn!(%error, "logind rejected lid suspend");
}
}
worker_lease.lock().unwrap().activate(false);
worker_lease
.lock()
.expect("lid policy lease must remain consistent across workers")
.activate(false);
})?;
let (requests, receiver) = mpsc::channel::<Probe>();
let (replies, events) = smithay::reexports::calloop::channel::channel();
@@ -306,7 +320,12 @@ fn request(state: &mut Ferese, reactivate: bool, wake: bool) {
}
}
backend.lid_reader.suspend_requested = false;
backend.lid_reader.lease.lock().unwrap().suspend = false;
backend
.lid_reader
.lease
.lock()
.expect("lid policy lease must remain consistent across workers")
.suspend = false;
let probe = backend.lid.begin(reactivate, wake);
let sent = backend.lid_reader.requests.send(probe).is_ok();
let timer = state.loop_handle.insert_source(
@@ -322,7 +341,12 @@ fn request(state: &mut Ferese, reactivate: bool, wake: bool) {
);
if sent && let Ok(token) = timer {
state.direct_backend.as_mut().unwrap().lid_reader.deadline = Some(token);
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.lid_reader
.deadline = Some(token);
} else {
if let Ok(token) = timer {
state.loop_handle.remove(token);
@@ -352,7 +376,12 @@ fn complete_refresh(state: &mut Ferese, probe: Probe, value: Option<bool>) {
backend.topology.reconciling = true;
state.reset_animation_clock();
state.lock_input_activity();
state.direct_backend.as_mut().unwrap().topology.reconciling = false;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.topology
.reconciling = false;
}
reconcile_outputs(state, reactivate);
@@ -364,7 +393,12 @@ pub(super) fn apply_suspend_policy(state: &mut Ferese) {
return;
};
let requested = backend.active && backend.desired_outputs.suspend && backend.lid.closed();
backend.lid_reader.lease.lock().unwrap().suspend = requested;
backend
.lid_reader
.lease
.lock()
.expect("lid policy lease must remain consistent across workers")
.suspend = requested;
if backend.lid_reader.suspend_requested != requested {
backend.lid_reader.suspend_requested = requested;
let _ = backend.lid_reader.suspend.send(PolicyRequest::Suspend);
+8 -1
View File
@@ -131,7 +131,14 @@ pub(super) fn cursor_on_output(state: &crate::Ferese, output: &smithay::output::
states
.data_map
.get::<CursorImageSurfaceData>()
.map(|attributes| attributes.lock().unwrap().hotspot)
.map(|attributes| {
attributes
.lock()
.expect(
"cursor surface attributes must remain consistent across callbacks",
)
.hotspot
})
.unwrap_or_default()
});
smithay::desktop::utils::bbox_from_surface_tree(
@@ -23,13 +23,21 @@ impl<S: Session> SessionDevice<S> {
}
pub fn device_fd(&self) -> io::Result<DeviceFd> {
self.fd.as_ref().unwrap().try_clone().map(DeviceFd::from)
self.fd
.as_ref()
.expect("the session device retains its descriptor until Drop")
.try_clone()
.map(DeviceFd::from)
}
}
impl<S: Session> Drop for SessionDevice<S> {
fn drop(&mut self) {
if let Err(error) = self.session.close(self.fd.take().unwrap()) {
if let Err(error) = self.session.close(
self.fd
.take()
.expect("the session device retains its descriptor until Drop"),
) {
tracing::warn!(
?error,
"could not release DRM device through the session manager"
+76 -24
View File
@@ -176,11 +176,11 @@ fn slot_mut<'a>(state: &'a mut Ferese, path: &Path) -> &'a mut DeviceState {
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.topology
.devices
.get_mut(path)
.unwrap()
.expect("the discovery path must have a topology slot")
}
/// The only entry point for applying the current output configuration to DRM.
@@ -250,7 +250,12 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
}
for path in paths {
let slot = &state.direct_backend.as_ref().unwrap().topology.devices[&path];
let slot = &state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend")
.topology
.devices[&path];
let current_path = observed
.as_ref()
.ok()
@@ -261,7 +266,7 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.contains_key(node)
});
@@ -291,7 +296,10 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
}
let node = match existing {
Some(node) => node,
None => match open_device(state, current_path.unwrap()) {
None => match open_device(
state,
current_path.expect("device discovery found a path before attempting to open it"),
) {
Ok(node) => node,
Err(error) => {
tracing::warn!(%error, ?path, device_path = ?current_path, "DRM device unavailable; will retry");
@@ -306,10 +314,10 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
let device = state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.get_mut(&node)
.unwrap();
.expect("the selected DRM device must remain registered during this operation");
device.drm.activate(true).map(|()| {
for (crtc, output) in &mut device.outputs {
cancel_output_timers(&state.loop_handle, output);
@@ -325,7 +333,7 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
state
.desktop_transition
.as_mut()
.unwrap()
.expect("desktop transition must be started before publication or retirement")
.redraw
.insert(output.output.clone());
@@ -350,13 +358,13 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
let mut output = state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.get_mut(&node)
.unwrap()
.expect("the selected DRM device must remain registered during this operation")
.outputs
.remove(&crtc)
.unwrap();
.expect("the selected CRTC must remain registered during this operation");
cancel_output_timers(&state.loop_handle, &mut output);
if let Some(global) = output.global.take() {
state.display_handle.disable_global::<Ferese>(global);
@@ -365,7 +373,7 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.presentation
.remove(&(node, crtc));
}
@@ -376,7 +384,7 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
let known_good = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.applied_outputs
.clone();
if let Err(error) = refresh_monitor_policy(state).and_then(|()| {
@@ -384,14 +392,21 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
validate_desired_outputs(state)
}) {
tracing::warn!(%error, "monitor policy validation failed; retaining applied outputs");
state.direct_backend.as_mut().unwrap().output_error = Some(error);
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.output_error = Some(error);
for (path, node) in &ready {
slot_mut(state, path).degraded(*node, Instant::now());
}
} else {
// Activate destinations before disabling former owners, including across GPUs.
ready.sort_by_key(|(_, node)| {
let backend = state.direct_backend.as_ref().unwrap();
let backend = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend");
let prefix = format!("{}/", drm_device_key(&backend.devices[node].drm));
let desired = backend
.desired_outputs
@@ -416,14 +431,21 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
// Device boundaries are not cross-GPU atomic. Compensate already
// applied devices using their last actual hardware settings.
if !known_good.outputs.is_empty() {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
let requested = backend.desired_outputs.clone();
backend.desired_outputs =
crate::output_policy::restore_configuration(&known_good, &backend.monitors);
for previous in succeeded {
let _ = rescan_device(state, previous);
}
state.direct_backend.as_mut().unwrap().desired_outputs = requested;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.desired_outputs = requested;
}
break;
}
@@ -431,7 +453,7 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
if state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.output_error
.is_none()
{
@@ -441,14 +463,24 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
transaction::recover_last_output(state);
let mut desktop_changes = publish_runtime_desktop(state);
if std::mem::take(&mut state.direct_backend.as_mut().unwrap().topology.layout_dirty) {
if std::mem::take(
&mut state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.topology
.layout_dirty,
) {
desktop_changes.layout = true;
desktop_changes.shell = true;
desktop_changes
.outputs
.extend(state.space.outputs().cloned());
}
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
backend.topology.reconciling = false;
let retry = backend.topology.retry_deadline(backend.active);
if std::mem::take(&mut backend.topology.remember_applied) {
@@ -465,7 +497,14 @@ pub(super) fn reconcile_outputs(state: &mut Ferese, reactivate: bool) {
reconcile_outputs(state, false);
TimeoutAction::Drop
}) {
Ok(token) => state.direct_backend.as_mut().unwrap().topology.retry_timer = Some(token),
Ok(token) => {
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.topology
.retry_timer = Some(token)
}
Err(error) => tracing::warn!(%error, "could not arm DRM recovery deadline"),
}
}
@@ -481,7 +520,7 @@ fn publish_runtime_desktop(state: &mut Ferese) -> crate::state::DesktopChanges {
let mut outputs = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.values()
.flat_map(|device| device.outputs.values())
@@ -525,7 +564,13 @@ fn publish_runtime_desktop(state: &mut Ferese) -> crate::state::DesktopChanges {
let changes = state
.publish_desktop(runtime)
.expect("validated usable output inventory");
for device in state.direct_backend.as_mut().unwrap().devices.values_mut() {
for device in state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.devices
.values_mut()
{
for output in device.outputs.values_mut() {
if output.mirror_source.is_none() {
if output.global.is_none() {
@@ -579,7 +624,14 @@ pub(super) fn hotplug(state: &mut Ferese) {
reconcile_outputs(state, false);
TimeoutAction::Drop
}) {
Ok(token) => state.direct_backend.as_mut().unwrap().topology.settle_timer = Some(token),
Ok(token) => {
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.topology
.settle_timer = Some(token)
}
Err(error) => {
tracing::warn!(%error, "could not debounce output events");
reconcile_outputs(state, false);
+47 -20
View File
@@ -257,7 +257,7 @@ fn retire(state: &mut Ferese, output: &mut DirectOutput, node: DrmNode, crtc: cr
state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.presentation
.remove(&(node, crtc));
}
@@ -296,7 +296,7 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
.staged
.get_mut(&crtc)
.or_else(|| self.device.outputs.get_mut(&crtc))
.unwrap();
.expect("the selected CRTC has a live or staged output in this transaction");
output
.surface
.set_connectors(&[selection.connector.handle()])
@@ -317,8 +317,15 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
// set_connectors: each tests against the other's old value. Stage a
// replacement surface, retire the old one *before* its first commit
// (Smithay clears the CRTC on surface drop), then publish metadata.
let replacement = self.staged.remove(&crtc).unwrap();
let previous = self.device.outputs.get_mut(&crtc).unwrap();
let replacement = self
.staged
.remove(&crtc)
.expect("the selected CRTC has a live or staged output in this transaction");
let previous = self
.device
.outputs
.get_mut(&crtc)
.expect("the selected CRTC has a live or staged output in this transaction");
previous.surface = replacement.surface;
previous.dmabuf_feedback = replacement.dmabuf_feedback;
self.replaced.insert(crtc);
@@ -326,7 +333,7 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
self.staged
.get_mut(&crtc)
.or_else(|| self.device.outputs.get_mut(&crtc))
.unwrap()
.expect("the selected CRTC has a live or staged output in this transaction")
.surface
.commit_frame()
.map_err(|error| error.to_string())
@@ -336,7 +343,7 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
self.device
.outputs
.get_mut(&crtc)
.unwrap()
.expect("the selected CRTC has a live or staged output in this transaction")
.surface
.clear()
.map_err(|error| error.to_string())
@@ -384,7 +391,11 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
&replacement.settings,
)
.map_err(|error| error.to_string())?;
let previous = self.device.outputs.get_mut(&crtc).unwrap();
let previous = self
.device
.outputs
.get_mut(&crtc)
.expect("the selected CRTC has a live or staged output in this transaction");
previous.surface = replacement.surface;
previous.dmabuf_feedback = replacement.dmabuf_feedback;
previous
@@ -426,7 +437,7 @@ impl crate::output_transaction::HardwareTransaction for DeviceTransaction<'_> {
self.state
.desktop_transition
.as_mut()
.unwrap()
.expect("desktop transition must be started before publication or retirement")
.redraw
.insert(output.output.clone());
output.lock_frame_pending = false;
@@ -504,7 +515,7 @@ pub(super) fn apply_device(
let mut output = staged
.remove(crtc)
.or_else(|| device.outputs.remove(crtc))
.unwrap();
.expect("the selected CRTC has a live or staged output in this transaction");
if output.connector != selection.connector.handle() || output.identity != selection.identity
{
retire(state, &mut output, node, *crtc);
@@ -551,7 +562,7 @@ pub(super) fn apply_device(
let clock = state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.presentation
.entry((node, *crtc))
.or_default();
@@ -561,7 +572,10 @@ pub(super) fn apply_device(
}
// Retire resources now; the final inventory determines evacuation once.
for crtc in removals {
let mut output = device.outputs.remove(&crtc).unwrap();
let mut output = device
.outputs
.remove(&crtc)
.expect("the selected CRTC has a live or staged output in this transaction");
retire(state, &mut output, node, crtc);
}
device.connected_outputs = scan.connected_outputs;
@@ -592,7 +606,7 @@ pub(super) fn retire_disconnected(state: &mut Ferese) {
let missing = state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.iter()
.flat_map(|(node, device)| {
@@ -610,10 +624,10 @@ pub(super) fn retire_disconnected(state: &mut Ferese) {
if let Some(mut output) = state
.direct_backend
.as_mut()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.get_mut(&node)
.unwrap()
.expect("the selected DRM device must remain registered during this operation")
.outputs
.remove(&crtc)
{
@@ -629,7 +643,7 @@ pub(super) fn recover_last_output(state: &mut Ferese) {
if state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.values()
.any(|device| {
@@ -641,7 +655,10 @@ pub(super) fn recover_last_output(state: &mut Ferese) {
{
return;
}
let backend = state.direct_backend.as_ref().unwrap();
let backend = state
.direct_backend
.as_ref()
.expect("DRM callbacks require an installed direct backend");
let requested = backend.desired_outputs.clone();
let original_error = backend.output_error.clone();
let mut candidates = backend
@@ -652,7 +669,10 @@ pub(super) fn recover_last_output(state: &mut Ferese) {
.collect::<Vec<_>>();
candidates.sort_by_key(|monitor| (!monitor.internal, monitor.key.clone()));
for candidate in candidates {
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
backend.desired_outputs = DesiredOutputConfiguration {
profile: None,
suspend: requested.suspend,
@@ -687,7 +707,7 @@ pub(super) fn recover_last_output(state: &mut Ferese) {
if state
.direct_backend
.as_ref()
.unwrap()
.expect("DRM callbacks require an installed direct backend")
.devices
.values()
.any(|device| {
@@ -698,13 +718,20 @@ pub(super) fn recover_last_output(state: &mut Ferese) {
})
{
remember_applied_configuration(state);
state.direct_backend.as_mut().unwrap().output_error = original_error;
state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend")
.output_error = original_error;
tracing::warn!(identity = %candidate.identity, "recovered last usable output with preferred mode");
return;
}
}
}
let backend = state.direct_backend.as_mut().unwrap();
let backend = state
.direct_backend
.as_mut()
.expect("DRM callbacks require an installed direct backend");
backend.desired_outputs = requested;
backend.output_error = original_error;
}