autocommit 2022-04-27 18:04:02 CEST
This commit is contained in:
parent
cff35fd7da
commit
57899b3f35
14 changed files with 173 additions and 66 deletions
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -38,4 +38,8 @@ impl Connector for DummyOutput {
|
|||
fn on_change(&self, _cb: Rc<dyn Fn()>) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn damage(&self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
15
src/state.rs
15
src/state.rs
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue