legacy: fixup rendering loop after tty switch
This commit is contained in:
parent
c7a98cee21
commit
e486f7b87c
|
@ -8,13 +8,14 @@ use drm::Device as BasicDevice;
|
||||||
use nix::libc::dev_t;
|
use nix::libc::dev_t;
|
||||||
use nix::sys::stat;
|
use nix::sys::stat;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use failure::ResultExt;
|
||||||
|
|
||||||
use super::{Dev, LegacyDrmDevice, LegacyDrmSurfaceInternal};
|
use super::{Dev, LegacyDrmDevice, LegacyDrmSurfaceInternal, Error, DevPath};
|
||||||
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
use crate::backend::session::{AsSessionObserver, SessionObserver};
|
||||||
|
|
||||||
/// [`SessionObserver`](SessionObserver)
|
/// [`SessionObserver`](SessionObserver)
|
||||||
|
@ -91,5 +92,77 @@ impl<A: AsRawFd + 'static> SessionObserver for LegacyDrmDeviceObserver<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// okay, the previous session/whatever might left the drm devices in any state...
|
||||||
|
// lets fix that
|
||||||
|
if let Err(err) = self.reset_state() {
|
||||||
|
warn!(self.logger, "Unable to reset state after tty switch: {}", err);
|
||||||
|
// TODO call drm-handler::error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: AsRawFd + 'static> LegacyDrmDeviceObserver<A> {
|
||||||
|
fn reset_state(&mut self) -> Result<(), Error> {
|
||||||
|
// lets enumerate it the current state
|
||||||
|
if let Some(dev) = self.dev.upgrade() {
|
||||||
|
let res_handles = ControlDevice::resource_handles(&*dev)
|
||||||
|
.compat()
|
||||||
|
.map_err(|source| Error::Access {
|
||||||
|
errmsg: "Error loading drm resources",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut used_connectors = HashSet::new();
|
||||||
|
if let Some(backends) = self.backends.upgrade() {
|
||||||
|
for surface in backends.borrow().values().filter_map(Weak::upgrade) {
|
||||||
|
let mut current = surface.state.write().unwrap();
|
||||||
|
let pending = surface.pending.read().unwrap();
|
||||||
|
|
||||||
|
// store (soon to be) used connectors
|
||||||
|
used_connectors.extend(pending.connectors.clone());
|
||||||
|
|
||||||
|
// set current connectors
|
||||||
|
current.connectors.clear();
|
||||||
|
for conn in res_handles.connectors() {
|
||||||
|
let conn_info = dev.get_connector(*conn).compat().map_err(|source| Error::Access {
|
||||||
|
errmsg: "Could not load connector info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
if let Some(enc) = conn_info.current_encoder() {
|
||||||
|
let enc_info = dev.get_encoder(enc).compat().map_err(|source| Error::Access {
|
||||||
|
errmsg: "Could not load encoder info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
if enc_info.crtc().map(|crtc| crtc == surface.crtc).unwrap_or(false) {
|
||||||
|
current.connectors.insert(*conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set current mode
|
||||||
|
let crtc_info = dev.get_crtc(surface.crtc).compat().map_err(|source| Error::Access {
|
||||||
|
errmsg: "Could not load crtc info",
|
||||||
|
dev: dev.dev_path(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below).
|
||||||
|
// A better fix would probably be making mode an `Option`, but that would mean
|
||||||
|
// we need to be sure, we require a mode to always be set without relying on the compiler.
|
||||||
|
// So we cheat, because it works and is easier to handle later.
|
||||||
|
current.mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable unused connectors
|
||||||
|
let all_set = res_handles.connectors().iter().copied().collect::<HashSet<_>>();
|
||||||
|
let unused = used_connectors.difference(&all_set);
|
||||||
|
dev.set_connector_state(unused.copied(), false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use drm::control::{
|
||||||
};
|
};
|
||||||
use drm::Device as BasicDevice;
|
use drm::Device as BasicDevice;
|
||||||
|
|
||||||
use std::cell::Cell;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -31,7 +30,6 @@ pub(super) struct LegacyDrmSurfaceInternal<A: AsRawFd + 'static> {
|
||||||
pub(super) state: RwLock<State>,
|
pub(super) state: RwLock<State>,
|
||||||
pub(super) pending: RwLock<State>,
|
pub(super) pending: RwLock<State>,
|
||||||
pub(super) logger: ::slog::Logger,
|
pub(super) logger: ::slog::Logger,
|
||||||
init_buffer: Cell<Option<(DumbBuffer, framebuffer::Handle)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> {
|
||||||
|
@ -357,7 +355,6 @@ impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
|
||||||
state: RwLock::new(state),
|
state: RwLock::new(state),
|
||||||
pending: RwLock::new(pending),
|
pending: RwLock::new(pending),
|
||||||
logger,
|
logger,
|
||||||
init_buffer: Cell::new(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(surface)
|
Ok(surface)
|
||||||
|
@ -416,10 +413,6 @@ impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
|
||||||
impl<A: AsRawFd + 'static> Drop for LegacyDrmSurfaceInternal<A> {
|
impl<A: AsRawFd + 'static> Drop for LegacyDrmSurfaceInternal<A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// ignore failure at this point
|
// ignore failure at this point
|
||||||
if let Some((db, fb)) = self.init_buffer.take() {
|
|
||||||
let _ = self.destroy_framebuffer(fb);
|
|
||||||
let _ = self.destroy_dumb_buffer(db);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.dev.active.load(Ordering::SeqCst) {
|
if !self.dev.active.load(Ordering::SeqCst) {
|
||||||
// the device is gone or we are on another tty
|
// the device is gone or we are on another tty
|
||||||
|
|
Loading…
Reference in New Issue