autocommit 2022-04-14 19:52:11 CEST
This commit is contained in:
parent
35ddfbcbe3
commit
5f13954dbc
27 changed files with 556 additions and 312 deletions
|
|
@ -1,14 +1,20 @@
|
|||
use std::error::Error;
|
||||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId},
|
||||
video::drm::ConnectorType,
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct DummyBackend {}
|
||||
pub struct DummyBackend;
|
||||
|
||||
impl Backend for DummyBackend {}
|
||||
impl Backend for DummyBackend {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DummyOutput {
|
||||
pub id: ConnectorId,
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ mod video;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncError, AsyncFd, Phase},
|
||||
async_engine::{AsyncError, AsyncFd, SpawnedFuture},
|
||||
backend::{
|
||||
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
|
||||
InputEvent, KeyState,
|
||||
},
|
||||
backends::metal::video::{MetalDrmDevice, PendingDrmDevice},
|
||||
dbus::DbusError,
|
||||
dbus::{DbusError, SignalHandler},
|
||||
libinput::{
|
||||
consts::{
|
||||
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||
|
|
@ -25,7 +25,6 @@ use {
|
|||
logind::{LogindError, Session},
|
||||
render::RenderError,
|
||||
state::State,
|
||||
tasks::idle,
|
||||
udev::{Udev, UdevError, UdevMonitor},
|
||||
utils::{
|
||||
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||
|
|
@ -42,6 +41,7 @@ use {
|
|||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
error::Error,
|
||||
ffi::{CStr, CString},
|
||||
future::pending,
|
||||
mem,
|
||||
|
|
@ -67,8 +67,6 @@ pub enum MetalError {
|
|||
LibInput(#[from] LibInputError),
|
||||
#[error("Dupfd failed")]
|
||||
Dup(#[source] crate::utils::oserror::OsError),
|
||||
#[error("Metal backend terminated unexpectedly")]
|
||||
UnexpectedTermination,
|
||||
#[error("Could not create GBM device")]
|
||||
GbmDevice(#[source] GbmError),
|
||||
#[error("Could not update the drm properties")]
|
||||
|
|
@ -99,20 +97,17 @@ pub enum MetalError {
|
|||
CreateEncoder(#[source] DrmError),
|
||||
#[error(transparent)]
|
||||
DrmError(#[from] DrmError),
|
||||
#[error("Could not create an async fd for the drm fd")]
|
||||
CreateDrmAsyncFd(#[source] AsyncError),
|
||||
}
|
||||
|
||||
pub async fn run(state: Rc<State>) -> MetalError {
|
||||
match run_(state).await {
|
||||
Err(e) => e,
|
||||
_ => MetalError::UnexpectedTermination,
|
||||
}
|
||||
#[error("Could not create an async fd")]
|
||||
CreateAsyncFd(#[source] AsyncError),
|
||||
#[error("Could not create device-paused signal handler")]
|
||||
DevicePauseSignalHandler(#[source] DbusError),
|
||||
#[error("Could not create device-resumed signal handler")]
|
||||
DeviceResumeSignalHandler(#[source] DbusError),
|
||||
}
|
||||
|
||||
linear_ids!(DrmIds, DrmId);
|
||||
|
||||
struct MetalBackend {
|
||||
pub struct MetalBackend {
|
||||
state: Rc<State>,
|
||||
udev: Rc<Udev>,
|
||||
monitor: Rc<UdevMonitor>,
|
||||
|
|
@ -122,9 +117,30 @@ struct MetalBackend {
|
|||
device_holder: Rc<DeviceHolder>,
|
||||
session: Session,
|
||||
drm_ids: DrmIds,
|
||||
pause_handler: Cell<Option<SignalHandler>>,
|
||||
resume_handler: Cell<Option<SignalHandler>>,
|
||||
}
|
||||
|
||||
impl MetalBackend {
|
||||
async fn run(self: Rc<Self>) -> Result<(), MetalError> {
|
||||
let _monitor = self.state.eng.spawn(self.clone().monitor_devices());
|
||||
let _events = self.state.eng.spawn(self.clone().handle_libinput_events());
|
||||
if let Err(e) = self.enumerate_devices() {
|
||||
return Err(MetalError::Enumerate(Box::new(e)));
|
||||
}
|
||||
pending().await
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend for MetalBackend {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
|
||||
let slf = self.clone();
|
||||
self.state.eng.spawn(async move {
|
||||
slf.run().await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn switch_to(&self, vtnr: u32) {
|
||||
self.session.switch_to(vtnr, move |res| {
|
||||
if let Err(e) = res {
|
||||
|
|
@ -160,9 +176,27 @@ impl Backend for MetalBackend {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn supports_idle(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn is_freestanding(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
||||
fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {
|
||||
match uapi::fcntl_dupfd_cloexec(fd, 0) {
|
||||
Ok(m) => match state.eng.fd(&Rc::new(m)) {
|
||||
Ok(fd) => Ok(fd),
|
||||
Err(e) => Err(MetalError::CreateAsyncFd(e)),
|
||||
},
|
||||
Err(e) => Err(MetalError::Dup(e.into())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create(state: &Rc<State>) -> Result<Rc<MetalBackend>, MetalError> {
|
||||
let socket = match state.dbus.system() {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(MetalError::DbusSystemSocket(e)),
|
||||
|
|
@ -186,14 +220,8 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
|||
monitor.add_match_subsystem_devtype(Some("drm"), None)?;
|
||||
monitor.enable_receiving()?;
|
||||
let libinput = Rc::new(LibInput::new(device_holder.clone())?);
|
||||
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
|
||||
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
|
||||
Err(e) => return Err(MetalError::Dup(e.into())),
|
||||
};
|
||||
let libinput_fd = match uapi::fcntl_dupfd_cloexec(libinput.fd(), 0) {
|
||||
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
|
||||
Err(e) => return Err(MetalError::Dup(e.into())),
|
||||
};
|
||||
let monitor_fd = dup_async_fd(&state, monitor.fd())?;
|
||||
let libinput_fd = dup_async_fd(&state, libinput.fd())?;
|
||||
let metal = Rc::new(MetalBackend {
|
||||
state: state.clone(),
|
||||
udev,
|
||||
|
|
@ -204,31 +232,28 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
|||
device_holder,
|
||||
session,
|
||||
drm_ids: Default::default(),
|
||||
pause_handler: Default::default(),
|
||||
resume_handler: Default::default(),
|
||||
});
|
||||
let _pause_handler = {
|
||||
metal.pause_handler.set(Some({
|
||||
let mtl = metal.clone();
|
||||
metal
|
||||
.session
|
||||
.on_pause(move |p| mtl.handle_device_pause(p))
|
||||
.unwrap()
|
||||
};
|
||||
let _resume_handler = {
|
||||
let sh = metal.session.on_pause(move |p| mtl.handle_device_pause(p));
|
||||
match sh {
|
||||
Ok(sh) => sh,
|
||||
Err(e) => return Err(MetalError::DevicePauseSignalHandler(e)),
|
||||
}
|
||||
}));
|
||||
metal.resume_handler.set(Some({
|
||||
let mtl = metal.clone();
|
||||
metal
|
||||
let sh = metal
|
||||
.session
|
||||
.on_resume(move |p| mtl.handle_device_resume(p))
|
||||
.unwrap()
|
||||
};
|
||||
let _monitor = state.eng.spawn(metal.clone().monitor_devices());
|
||||
let _events = state.eng.spawn(metal.clone().handle_libinput_events());
|
||||
if let Err(e) = metal.enumerate_devices() {
|
||||
return Err(MetalError::Enumerate(Box::new(e)));
|
||||
}
|
||||
state.backend.set(Some(metal.clone()));
|
||||
let _idle = state
|
||||
.eng
|
||||
.spawn2(Phase::PostLayout, idle(state.clone(), metal.clone()));
|
||||
pending().await
|
||||
.on_resume(move |p| mtl.handle_device_resume(p));
|
||||
match sh {
|
||||
Ok(sh) => sh,
|
||||
Err(e) => return Err(MetalError::DeviceResumeSignalHandler(e)),
|
||||
}
|
||||
}));
|
||||
Ok(metal)
|
||||
}
|
||||
|
||||
struct MetalInputDevice {
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ impl MetalBackend {
|
|||
};
|
||||
let async_fd = match self.state.eng.fd(master.fd()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(MetalError::CreateDrmAsyncFd(e)),
|
||||
Err(e) => return Err(MetalError::CreateAsyncFd(e)),
|
||||
};
|
||||
|
||||
let dev = Rc::new(MetalDrmDeviceStatic {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::error::Error;
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{Phase, SpawnedFuture},
|
||||
|
|
@ -51,6 +52,7 @@ use {
|
|||
borrow::Cow,
|
||||
cell::{Cell, RefCell},
|
||||
collections::VecDeque,
|
||||
future::pending,
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
|
|
@ -106,16 +108,137 @@ pub enum XBackendError {
|
|||
QueryDevice(#[source] XconError),
|
||||
}
|
||||
|
||||
pub struct XBackend {
|
||||
_data: Rc<XBackendData>,
|
||||
_events: SpawnedFuture<()>,
|
||||
_present: SpawnedFuture<()>,
|
||||
_grab: SpawnedFuture<()>,
|
||||
pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
||||
let c = match Xcon::connect(state.eng.clone()).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(XBackendError::CannotConnect(e)),
|
||||
};
|
||||
if let Err(e) = c
|
||||
.call(&XiQueryVersion {
|
||||
major_version: 2,
|
||||
minor_version: 2,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableXinput(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&Dri3QueryVersion {
|
||||
major_version: 1,
|
||||
minor_version: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableDri3(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&PresentQueryVersion {
|
||||
major_version: 1,
|
||||
minor_version: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnablePresent(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&XkbUseExtension {
|
||||
wanted_major: 1,
|
||||
wanted_minor: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableXkb(e));
|
||||
}
|
||||
let root = c.setup().screens[0].root;
|
||||
let drm = {
|
||||
let res = c
|
||||
.call(&Dri3Open {
|
||||
drawable: root,
|
||||
provider: 0,
|
||||
})
|
||||
.await;
|
||||
match res {
|
||||
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
|
||||
Err(e) => return Err(XBackendError::DriOpen(e)),
|
||||
}
|
||||
};
|
||||
let gbm = GbmDevice::new(&drm)?;
|
||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
||||
Ok(r) => Rc::new(r),
|
||||
Err(e) => return Err(XBackendError::CreateEgl(e)),
|
||||
};
|
||||
let cursor = {
|
||||
let cp = CreatePixmap {
|
||||
depth: 1,
|
||||
pid: c.generate_id()?,
|
||||
drawable: root,
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
if let Err(e) = c.call(&cp).await {
|
||||
return Err(XBackendError::CreatePixmap(e));
|
||||
}
|
||||
let cc = CreateCursor {
|
||||
cid: c.generate_id()?,
|
||||
source: cp.pid,
|
||||
mask: cp.pid,
|
||||
fore_red: 0,
|
||||
fore_green: 0,
|
||||
fore_blue: 0,
|
||||
back_red: 0,
|
||||
back_green: 0,
|
||||
back_blue: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
if let Err(e) = c.call(&cc).await {
|
||||
return Err(XBackendError::CreateCursor(e));
|
||||
}
|
||||
c.call(&FreePixmap { pixmap: cp.pid });
|
||||
cc.cid
|
||||
};
|
||||
{
|
||||
let se = XiSelectEvents {
|
||||
window: c.setup().screens[0].root,
|
||||
masks: Cow::Borrowed(&[XiEventMask {
|
||||
deviceid: INPUT_DEVICE_ALL,
|
||||
mask: &[XI_EVENT_MASK_HIERARCHY],
|
||||
}]),
|
||||
};
|
||||
if let Err(e) = c.call(&se).await {
|
||||
return Err(XBackendError::SelectHierarchyEvents(e));
|
||||
}
|
||||
}
|
||||
|
||||
let data = Rc::new(XBackend {
|
||||
state: state.clone(),
|
||||
c,
|
||||
outputs: Default::default(),
|
||||
seats: Default::default(),
|
||||
mouse_seats: Default::default(),
|
||||
ctx: ctx.clone(),
|
||||
gbm,
|
||||
cursor,
|
||||
root,
|
||||
scheduled_present: Default::default(),
|
||||
grab_requests: Default::default(),
|
||||
});
|
||||
data.add_output().await?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
impl Backend for XBackend {}
|
||||
impl Backend for XBackend {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
|
||||
let slf = self.clone();
|
||||
self.state.eng.spawn(async move {
|
||||
slf.run().await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct XBackendData {
|
||||
pub struct XBackend {
|
||||
state: Rc<State>,
|
||||
c: Rc<Xcon>,
|
||||
outputs: CopyHashMap<u32, Rc<XOutput>>,
|
||||
|
|
@ -130,141 +253,21 @@ struct XBackendData {
|
|||
}
|
||||
|
||||
impl XBackend {
|
||||
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XBackendError> {
|
||||
let c = match Xcon::connect(state.eng.clone()).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(XBackendError::CannotConnect(e)),
|
||||
};
|
||||
if let Err(e) = c
|
||||
.call(&XiQueryVersion {
|
||||
major_version: 2,
|
||||
minor_version: 2,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableXinput(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&Dri3QueryVersion {
|
||||
major_version: 1,
|
||||
minor_version: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableDri3(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&PresentQueryVersion {
|
||||
major_version: 1,
|
||||
minor_version: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnablePresent(e));
|
||||
}
|
||||
if let Err(e) = c
|
||||
.call(&XkbUseExtension {
|
||||
wanted_major: 1,
|
||||
wanted_minor: 0,
|
||||
})
|
||||
.await
|
||||
{
|
||||
return Err(XBackendError::EnableXkb(e));
|
||||
}
|
||||
let root = c.setup().screens[0].root;
|
||||
let drm = {
|
||||
let res = c
|
||||
.call(&Dri3Open {
|
||||
drawable: root,
|
||||
provider: 0,
|
||||
})
|
||||
.await;
|
||||
match res {
|
||||
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
|
||||
Err(e) => return Err(XBackendError::DriOpen(e)),
|
||||
}
|
||||
};
|
||||
let gbm = GbmDevice::new(&drm)?;
|
||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
||||
Ok(r) => Rc::new(r),
|
||||
Err(e) => return Err(XBackendError::CreateEgl(e)),
|
||||
};
|
||||
let cursor = {
|
||||
let cp = CreatePixmap {
|
||||
depth: 1,
|
||||
pid: c.generate_id()?,
|
||||
drawable: root,
|
||||
width: 1,
|
||||
height: 1,
|
||||
};
|
||||
if let Err(e) = c.call(&cp).await {
|
||||
return Err(XBackendError::CreatePixmap(e));
|
||||
}
|
||||
let cc = CreateCursor {
|
||||
cid: c.generate_id()?,
|
||||
source: cp.pid,
|
||||
mask: cp.pid,
|
||||
fore_red: 0,
|
||||
fore_green: 0,
|
||||
fore_blue: 0,
|
||||
back_red: 0,
|
||||
back_green: 0,
|
||||
back_blue: 0,
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
if let Err(e) = c.call(&cc).await {
|
||||
return Err(XBackendError::CreateCursor(e));
|
||||
}
|
||||
c.call(&FreePixmap { pixmap: cp.pid });
|
||||
cc.cid
|
||||
};
|
||||
{
|
||||
let se = XiSelectEvents {
|
||||
window: c.setup().screens[0].root,
|
||||
masks: Cow::Borrowed(&[XiEventMask {
|
||||
deviceid: INPUT_DEVICE_ALL,
|
||||
mask: &[XI_EVENT_MASK_HIERARCHY],
|
||||
}]),
|
||||
};
|
||||
if let Err(e) = c.call(&se).await {
|
||||
return Err(XBackendError::SelectHierarchyEvents(e));
|
||||
}
|
||||
}
|
||||
async fn run(self: Rc<Self>) -> Result<(), XBackendError> {
|
||||
self.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
|
||||
|
||||
let data = Rc::new(XBackendData {
|
||||
state: state.clone(),
|
||||
c,
|
||||
outputs: Default::default(),
|
||||
seats: Default::default(),
|
||||
mouse_seats: Default::default(),
|
||||
ctx: ctx.clone(),
|
||||
gbm,
|
||||
cursor,
|
||||
root,
|
||||
scheduled_present: Default::default(),
|
||||
grab_requests: Default::default(),
|
||||
});
|
||||
data.add_output().await?;
|
||||
data.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
|
||||
let _events = self.state.eng.spawn(self.clone().event_handler());
|
||||
let _grab = self.state.eng.spawn(self.clone().grab_handler());
|
||||
let _present = self
|
||||
.state
|
||||
.eng
|
||||
.spawn2(Phase::Present, self.clone().present_handler());
|
||||
|
||||
let slf = Rc::new(Self {
|
||||
_events: state.eng.spawn(data.clone().event_handler()),
|
||||
_grab: state.eng.spawn(data.clone().grab_handler()),
|
||||
_present: state
|
||||
.eng
|
||||
.spawn2(Phase::Present, data.clone().present_handler()),
|
||||
_data: data,
|
||||
});
|
||||
self.state.set_render_ctx(&self.ctx);
|
||||
|
||||
state.set_render_ctx(&ctx);
|
||||
state.backend.set(Some(slf.clone()));
|
||||
|
||||
Ok(slf)
|
||||
pending().await
|
||||
}
|
||||
}
|
||||
|
||||
impl XBackendData {
|
||||
async fn event_handler(self: Rc<Self>) {
|
||||
loop {
|
||||
let event = self.c.event().await;
|
||||
|
|
@ -856,7 +859,7 @@ impl XBackendData {
|
|||
|
||||
struct XOutput {
|
||||
id: ConnectorId,
|
||||
_backend: Rc<XBackendData>,
|
||||
_backend: Rc<XBackend>,
|
||||
window: u32,
|
||||
events: SyncQueue<ConnectorEvent>,
|
||||
width: Cell<i32>,
|
||||
|
|
@ -908,7 +911,7 @@ impl Connector for XOutput {
|
|||
struct XSeat {
|
||||
kb_id: InputDeviceId,
|
||||
mouse_id: InputDeviceId,
|
||||
backend: Rc<XBackendData>,
|
||||
backend: Rc<XBackend>,
|
||||
kb: u16,
|
||||
mouse: u16,
|
||||
removed: Cell<bool>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue