1
0
Fork 0
forked from wry/wry

autocommit 2022-04-14 19:52:11 CEST

This commit is contained in:
Julian Orth 2022-04-14 19:52:11 +02:00
parent 35ddfbcbe3
commit 5f13954dbc
27 changed files with 556 additions and 312 deletions

View file

@ -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,

View file

@ -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 {

View file

@ -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 {

View file

@ -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>,