1
0
Fork 0
forked from wry/wry

autocommit 2022-04-27 18:04:02 CEST

This commit is contained in:
Julian Orth 2022-04-27 18:04:02 +02:00
parent cff35fd7da
commit 57899b3f35
14 changed files with 173 additions and 66 deletions

View file

@ -69,6 +69,7 @@ pub trait Connector {
fn kernel_id(&self) -> ConnectorKernelId;
fn event(&self) -> Option<ConnectorEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
fn damage(&self);
}
#[derive(Debug)]

View file

@ -38,4 +38,8 @@ impl Connector for DummyOutput {
fn on_change(&self, _cb: Rc<dyn Fn()>) {
// nothing
}
fn damage(&self) {
// nothing
}
}

View file

@ -174,7 +174,7 @@ impl Backend for MetalBackend {
if !idle {
for device in devices.values() {
for connector in device.connectors.values() {
self.present(connector);
connector.schedule_present();
}
}
}

View file

@ -35,6 +35,8 @@ use {
},
uapi::c,
};
use crate::async_engine::Phase;
use crate::utils::asyncevent::AsyncEvent;
pub struct PendingDrmDevice {
pub id: DrmId,
@ -75,12 +77,14 @@ impl Debug for HandleEvents {
pub struct MetalDrmDevice {
pub dev: Rc<MetalDrmDeviceStatic>,
pub connectors: AHashMap<DrmConnector, Rc<MetalConnector>>,
pub futures: Vec<ConnectorFutures>,
}
#[derive(Debug)]
pub struct MetalConnector {
pub id: DrmConnector,
pub master: Rc<DrmMaster>,
pub state: Rc<State>,
pub connector_id: ConnectorId,
@ -97,6 +101,9 @@ pub struct MetalConnector {
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
pub next_buffer: NumCell<usize>,
pub can_present: Cell<bool>,
pub has_damage: Cell<bool>,
pub connector_type: ConnectorType,
pub connector_type_id: u32,
@ -111,6 +118,18 @@ pub struct MetalConnector {
pub crtc: CloneCell<Option<Rc<MetalCrtc>>>,
pub on_change: OnChange,
pub present_trigger: AsyncEvent,
}
pub struct ConnectorFutures {
pub present: SpawnedFuture<()>,
}
impl Debug for ConnectorFutures {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ConnectorFutures").finish_non_exhaustive()
}
}
#[derive(Default)]
@ -127,6 +146,60 @@ impl Debug for OnChange {
}
}
impl MetalConnector {
async fn present_loop(self: Rc<Self>) {
loop {
self.present_trigger.triggered().await;
self.present();
}
}
pub fn schedule_present(&self) {
self.present_trigger.trigger();
}
pub fn present(&self) {
let crtc = match self.crtc.get() {
Some(crtc) => crtc,
_ => return,
};
if !self.has_damage.get() || !self.can_present.get() {
return;
}
if !crtc.active.value.get() {
return;
}
let buffers = match self.buffers.get() {
None => return,
Some(b) => b,
};
let plane = match self.primary_plane.get() {
Some(p) => p,
_ => return,
};
let buffer = &buffers[self.next_buffer.fetch_add(1) % buffers.len()];
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
buffer
.egl
.render(&*node, &self.state, Some(node.global.pos.get()));
}
let mut changes = self.master.change();
changes.change_object(plane.id, |c| {
c.change(plane.fb_id, buffer.drm.id().0 as _);
});
if let Err(e) = changes.commit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, 0) {
match e {
DrmError::Atomic(OsError(c::EACCES)) => {
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
}
_ => log::error!("Could not set plane framebuffer: {}", ErrorFmt(e)),
}
}
self.can_present.set(false);
self.has_damage.set(false);
}
}
impl Connector for MetalConnector {
fn id(&self) -> ConnectorId {
self.connector_id
@ -146,6 +219,13 @@ impl Connector for MetalConnector {
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.on_change.on_change.set(Some(cb));
}
fn damage(&self) {
self.has_damage.set(true);
if self.can_present.get() {
self.schedule_present();
}
}
}
#[derive(Debug)]
@ -202,27 +282,29 @@ pub struct MetalPlane {
}
fn get_connectors(
state: &State,
dev: &MetalDrmDeviceStatic,
state: &Rc<State>,
dev: &Rc<MetalDrmDeviceStatic>,
ids: &[DrmConnector],
) -> Result<AHashMap<DrmConnector, Rc<MetalConnector>>, DrmError> {
) -> Result<(AHashMap<DrmConnector, Rc<MetalConnector>>, Vec<ConnectorFutures>), DrmError> {
let mut connectors = AHashMap::new();
let mut futures = vec![];
for connector in ids {
match create_connector(state, *connector, dev) {
Ok(e) => {
connectors.insert(e.id, Rc::new(e));
Ok((con, fut)) => {
connectors.insert(con.id, con);
futures.push(fut);
}
Err(e) => return Err(DrmError::CreateConnector(Box::new(e))),
}
}
Ok(connectors)
Ok((connectors, futures))
}
fn create_connector(
state: &State,
state: &Rc<State>,
connector: DrmConnector,
dev: &MetalDrmDeviceStatic,
) -> Result<MetalConnector, DrmError> {
dev: &Rc<MetalDrmDeviceStatic>,
) -> Result<(Rc<MetalConnector>, ConnectorFutures), DrmError> {
let info = dev.master.get_connector_info(connector, true)?;
let mut crtcs = AHashMap::new();
for encoder in info.encoders {
@ -303,9 +385,10 @@ fn create_connector(
serial_number = edid.base_block.id_serial_number.to_string();
}
}
Ok(MetalConnector {
let slf = Rc::new(MetalConnector {
id: connector,
master: dev.master.clone(),
state: state.clone(),
connector_id: state.connector_ids.next(),
crtcs,
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
@ -316,6 +399,8 @@ fn create_connector(
modes: info.modes,
buffers: Default::default(),
next_buffer: Default::default(),
can_present: Cell::new(true),
has_damage: Cell::new(true),
connector_type,
connector_type_id: info.connector_type_id,
connection,
@ -326,7 +411,12 @@ fn create_connector(
crtc_id: props.get("CRTC_ID")?.map(|v| DrmCrtc(v as _)),
crtc: Default::default(),
on_change: Default::default(),
})
present_trigger: Default::default()
});
let futures = ConnectorFutures {
present: state.eng.spawn2(Phase::Present, slf.clone().present_loop()),
};
Ok((slf, futures))
}
fn create_encoder(
@ -563,9 +653,9 @@ impl MetalBackend {
},
});
let connectors = get_connectors(&self.state, &dev, &resources.connectors)?;
let (connectors, futures) = get_connectors(&self.state, &dev, &resources.connectors)?;
let slf = Rc::new(MetalDrmDevice { dev, connectors });
let slf = Rc::new(MetalDrmDevice { dev, connectors, futures });
self.init_drm_device(&slf)?;
@ -604,11 +694,11 @@ impl MetalBackend {
}
}
let handler = self
let drm_handler = self
.state
.eng
.spawn(self.clone().handle_drm_events(slf.clone()));
slf.dev.handle_events.handle_events.set(Some(handler));
slf.dev.handle_events.handle_events.set(Some(drm_handler));
self.state.set_render_ctx(&egl);
@ -650,7 +740,9 @@ impl MetalBackend {
self.init_drm_device(dev)?;
for connector in dev.connectors.values() {
if connector.primary_plane.get().is_some() {
self.present(connector);
connector.can_present.set(true);
connector.has_damage.set(true);
connector.schedule_present();
}
}
Ok(())
@ -702,7 +794,10 @@ impl MetalBackend {
Some(c) => c,
_ => return,
};
self.present(&connector);
connector.can_present.set(true);
if connector.has_damage.get() {
connector.schedule_present();
}
}
fn reset_planes(&self, dev: &MetalDrmDevice, changes: &mut Change) {
@ -999,43 +1094,7 @@ impl MetalBackend {
connector.connector_type_id,
mode
);
self.present(connector);
}
pub fn present(&self, connector: &Rc<MetalConnector>) {
let crtc = match connector.crtc.get() {
Some(crtc) => crtc,
_ => return,
};
if !crtc.active.value.get() {
return;
}
let buffers = match connector.buffers.get() {
None => return,
Some(b) => b,
};
let plane = match connector.primary_plane.get() {
Some(p) => p,
_ => return,
};
let buffer = &buffers[connector.next_buffer.fetch_add(1) % buffers.len()];
if let Some(node) = self.state.root.outputs.get(&connector.connector_id) {
buffer
.egl
.render(&*node, &self.state, Some(node.global.pos.get()));
}
let mut changes = connector.master.change();
changes.change_object(plane.id, |c| {
c.change(plane.fb_id, buffer.drm.id().0 as _);
});
if let Err(e) = changes.commit(DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT, 0) {
match e {
DrmError::Atomic(OsError(c::EACCES)) => {
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
}
_ => log::error!("Could not set plane framebuffer: {}", ErrorFmt(e)),
}
}
connector.schedule_present();
}
}

View file

@ -910,6 +910,10 @@ impl Connector for XOutput {
fn on_change(&self, cb: Rc<dyn Fn()>) {
self.cb.set(Some(cb));
}
fn damage(&self) {
// nothing
}
}
struct XSeat {

View file

@ -9,8 +9,8 @@ use {
state::{ConnectorData, DeviceHandlerData, OutputData, State},
tree::{ContainerNode, ContainerSplit, FloatNode, Node, NodeVisitorBase},
utils::{
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt,
numcell::NumCell, stack::Stack,
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
stack::Stack,
},
xkbcommon::{XkbCommonError, XkbKeymap},
},

View file

@ -214,7 +214,12 @@ impl WlSeatGlobal {
if old_ws.id == ws.id {
return;
}
let cn = match tl.tl_data().parent.get().and_then(|p| p.node_into_containing_node()) {
let cn = match tl
.tl_data()
.parent
.get()
.and_then(|p| p.node_into_containing_node())
{
Some(cn) => cn,
_ => return,
};
@ -226,7 +231,12 @@ impl WlSeatGlobal {
}
}
if tl.tl_data().is_floating.get() {
self.state.map_floating(tl.clone(), tl.tl_data().float_width.get(), tl.tl_data().float_height.get(), ws);
self.state.map_floating(
tl.clone(),
tl.tl_data().float_width.get(),
tl.tl_data().float_height.get(),
ws,
);
} else {
self.state.map_tiled_on(tl, ws);
}

View file

@ -426,6 +426,7 @@ impl WlSeatGlobal {
}
pub(super) fn apply_changes(self: &Rc<Self>) {
self.state.damage();
self.pointer_owner.apply_changes(self);
self.changes.set(0);
}

View file

@ -180,6 +180,7 @@ struct PendingState {
opaque_region: Cell<Option<Option<Rc<Region>>>>,
input_region: Cell<Option<Option<Rc<Region>>>>,
frame_request: RefCell<Vec<Rc<WlCallback>>>,
damage: Cell<bool>,
}
#[derive(Default)]
@ -403,6 +404,7 @@ impl WlSurface {
fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> {
let _req: Damage = self.parse(parser)?;
self.pending.damage.set(true);
Ok(())
}
@ -507,6 +509,7 @@ impl WlSurface {
self.calculate_extents();
}
ext.post_commit();
self.client.state.damage();
Ok(())
}
@ -531,6 +534,7 @@ impl WlSurface {
fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> {
let _req: DamageBuffer = self.parse(parser)?;
self.pending.damage.set(true);
Ok(())
}

View file

@ -1,3 +1,4 @@
use std::fmt::{Debug, Formatter};
use {
crate::{
async_engine::{AsyncEngine, SpawnedFuture},
@ -94,6 +95,12 @@ pub struct State {
pub run_toplevel: Rc<RunToplevel>,
}
impl Debug for State {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("State").finish_non_exhaustive()
}
}
pub struct XWaylandState {
pub enabled: Cell<bool>,
pub handler: RefCell<Option<SpawnedFuture<()>>>,
@ -379,4 +386,12 @@ impl State {
}
serial as _
}
pub fn damage(&self) {
for connector in self.connectors.lock().values() {
if connector.connected.get() {
connector.connector.damage();
}
}
}
}

View file

@ -823,7 +823,9 @@ impl ContainerNode {
// CASE 1: This is the only child of the container. Replace the container by the child.
if self.num_children.get() == 1 {
let parent = self.parent.get();
if !self.toplevel_data.is_fullscreen.get() && parent.cnode_accepts_child(child.tl_as_node()) {
if !self.toplevel_data.is_fullscreen.get()
&& parent.cnode_accepts_child(child.tl_as_node())
{
parent.cnode_replace_child(self.deref(), child.clone());
}
return;

View file

@ -29,7 +29,11 @@ impl PlaceholderNode {
pub fn new_for(state: &Rc<State>, node: Rc<dyn ToplevelNode>) -> Self {
Self {
id: state.node_ids.next(),
toplevel: ToplevelData::new(state, node.tl_data().title.borrow_mut().clone(), node.node_client()),
toplevel: ToplevelData::new(
state,
node.tl_data().title.borrow_mut().clone(),
node.node_client(),
),
destroyed: Default::default(),
texture: Default::default(),
}

View file

@ -60,11 +60,7 @@ pub trait ToplevelNode: Node {
let data = self.tl_data();
if fullscreen {
if let Some(ws) = data.workspace.get() {
data.set_fullscreen2(
&data.state,
self.clone().tl_into_dyn(),
&ws,
);
data.set_fullscreen2(&data.state, self.clone().tl_into_dyn(), &ws);
}
} else {
data.unset_fullscreen(&data.state, self.clone().tl_into_dyn());

View file

@ -1,3 +1,4 @@
use std::fmt::{Debug, Formatter};
use {
crate::utils::numcell::NumCell,
std::{
@ -14,6 +15,12 @@ pub struct AsyncEvent {
waker: Cell<Option<Waker>>,
}
impl Debug for AsyncEvent {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AsyncEvent").field("triggers", &self.triggers.get()).finish_non_exhaustive()
}
}
impl AsyncEvent {
pub fn clear(&self) {
self.waker.take();