1
0
Fork 0
forked from wry/wry

autocommit 2022-04-04 00:28:58 CEST

This commit is contained in:
Julian Orth 2022-04-04 00:28:58 +02:00
parent 9ec1c5c995
commit 1f71290dab
21 changed files with 1217 additions and 132 deletions

View file

@ -9,14 +9,25 @@ pub trait Backend {
fn switch_to(&self, vtnr: u32);
}
pub trait Output {
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Mode {
pub width: i32,
pub height: i32,
pub refresh_rate: u32,
}
pub trait Connector {
fn id(&self) -> OutputId;
fn removed(&self) -> bool;
fn width(&self) -> i32;
fn height(&self) -> i32;
fn event(&self) -> Option<ConnectorEvent>;
fn on_change(&self, cb: Rc<dyn Fn()>);
}
#[derive(Debug)]
pub enum ConnectorEvent {
Removed,
ModeChanged(Mode),
}
pub trait InputDevice {
fn id(&self) -> InputDeviceId;
fn removed(&self) -> bool;
@ -49,7 +60,7 @@ pub enum InputDeviceAccelProfile {
}
pub enum BackendEvent {
NewOutput(Rc<dyn Output>),
NewConnector(Rc<dyn Connector>),
NewInputDevice(Rc<dyn InputDevice>),
}

View file

@ -1,4 +1,4 @@
use crate::backend::{Backend, Output, OutputId};
use crate::backend::{Backend, Connector, ConnectorEvent, OutputId};
use std::rc::Rc;
pub struct DummyBackend {}
@ -13,21 +13,13 @@ pub struct DummyOutput {
pub id: OutputId,
}
impl Output for DummyOutput {
impl Connector for DummyOutput {
fn id(&self) -> OutputId {
self.id
}
fn removed(&self) -> bool {
false
}
fn width(&self) -> i32 {
100
}
fn height(&self) -> i32 {
100
fn event(&self) -> Option<ConnectorEvent> {
None
}
fn on_change(&self, _cb: Rc<dyn Fn()>) {

View file

@ -232,6 +232,7 @@ impl MetalBackend {
}
fn handle_drm_change(self: &Rc<Self>, _dev: UdevDevice) -> Option<()> {
// TODO: Handle monitor connections and connector hotplug
None
}

View file

@ -1,5 +1,5 @@
use crate::async_engine::{AsyncFd, SpawnedFuture};
use crate::backend::{BackendEvent, Output, OutputId};
use crate::backend::{BackendEvent, Connector, ConnectorEvent, Mode, OutputId};
use crate::backends::metal::{DrmId, MetalBackend, MetalError};
use crate::drm::drm::{
drm_mode_modeinfo, Change, ConnectorStatus, ConnectorType, DrmBlob, DrmConnector, DrmCrtc,
@ -24,6 +24,7 @@ use std::ffi::CString;
use std::fmt::{Debug, Formatter};
use std::rc::Rc;
use uapi::c;
use crate::utils::syncqueue::SyncQueue;
pub struct PendingDrmDevice {
pub id: DrmId,
@ -77,6 +78,8 @@ pub struct MetalConnector {
pub modes: Vec<DrmModeInfo>,
pub mode: CloneCell<Option<Rc<DrmModeInfo>>>,
pub events: SyncQueue<ConnectorEvent>,
pub buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
pub next_buffer: NumCell<usize>,
@ -110,27 +113,13 @@ impl Debug for OnChange {
}
}
impl Output for MetalConnector {
impl Connector for MetalConnector {
fn id(&self) -> OutputId {
self.output_id
}
fn removed(&self) -> bool {
false
}
fn width(&self) -> i32 {
match self.mode.get() {
Some(m) => m.hdisplay as _,
_ => 0,
}
}
fn height(&self) -> i32 {
match self.mode.get() {
Some(m) => m.vdisplay as _,
_ => 0,
}
fn event(&self) -> Option<ConnectorEvent> {
self.events.pop()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {
@ -223,12 +212,22 @@ fn create_connector(
}
}
let props = collect_properties(&dev.master, connector)?;
let mode = info.modes.first().cloned().map(Rc::new);
let events = SyncQueue::default();
if let Some(mode) = &mode {
events.push(ConnectorEvent::ModeChanged(Mode {
width: mode.hdisplay as _,
height: mode.vdisplay as _,
refresh_rate: mode.refresh_rate(),
}));
}
Ok(MetalConnector {
id: connector,
master: dev.master.clone(),
output_id: state.output_ids.next(),
crtcs,
mode: CloneCell::new(info.modes.first().cloned().map(Rc::new)),
mode: CloneCell::new(mode),
events,
modes: info.modes,
buffers: Default::default(),
next_buffer: Default::default(),
@ -486,6 +485,9 @@ impl MetalBackend {
self.init_drm_device(&slf)?;
for connector in slf.connectors.values() {
self.state
.backend_events
.push(BackendEvent::NewConnector(connector.clone()));
if connector.primary_plane.get().is_some() {
self.start_connector(connector);
}
@ -880,9 +882,6 @@ impl MetalBackend {
fn start_connector(&self, connector: &Rc<MetalConnector>) {
let mode = connector.mode.get().unwrap();
self.state
.backend_events
.push(BackendEvent::NewOutput(connector.clone()));
log::info!(
"Initialized connector {}-{} with mode {:?}",
connector.connector_type,
@ -905,7 +904,7 @@ impl MetalBackend {
if let Some(node) = self.state.root.outputs.get(&connector.output_id) {
buffer
.egl
.render(&*node, &self.state, Some(node.position.get()));
.render(&*node, &self.state, Some(node.global.pos.get()));
}
let mut changes = connector.master.change();
changes.change_object(plane.id, |c| {

View file

@ -1,8 +1,5 @@
use crate::async_engine::{Phase, SpawnedFuture};
use crate::backend::{
Backend, BackendEvent, InputDevice, InputDeviceAccelProfile, InputDeviceCapability,
InputDeviceId, InputEvent, KeyState, Output, OutputId, ScrollAxis,
};
use crate::backend::{Backend, BackendEvent, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent, KeyState, Connector, OutputId, ScrollAxis, Mode, ConnectorEvent};
use crate::drm::drm::{Drm, DrmError};
use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING};
use crate::drm::{ModifiedFormat, INVALID_MODIFIER};
@ -42,6 +39,7 @@ use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::Rc;
use thiserror::Error;
use crate::utils::syncqueue::SyncQueue;
#[derive(Debug, Error)]
pub enum XBackendError {
@ -396,7 +394,7 @@ impl XBackendData {
id: self.state.output_ids.next(),
_backend: self.clone(),
window: window_id,
removed: Cell::new(false),
events: Default::default(),
width: Cell::new(0),
height: Cell::new(0),
serial: Default::default(),
@ -479,7 +477,7 @@ impl XBackendData {
self.outputs.set(window_id, output.clone());
self.state
.backend_events
.push(BackendEvent::NewOutput(output.clone()));
.push(BackendEvent::NewConnector(output.clone()));
self.present(&output).await;
Ok(())
}
@ -636,10 +634,6 @@ impl XBackendData {
}
async fn present(&self, output: &Rc<XOutput>) {
if output.removed.get() {
return;
}
let serial = output.serial.fetch_add(1);
let image = &output.images[output.next_image.fetch_add(1) % output.images.len()];
@ -648,7 +642,7 @@ impl XBackendData {
if let Some(node) = self.state.root.outputs.get(&output.id) {
let fb = image.fb.get();
fb.render(&*node, &self.state, Some(node.position.get()));
fb.render(&*node, &self.state, Some(node.global.pos.get()));
}
let pp = PresentPixmap {
@ -795,7 +789,7 @@ impl XBackendData {
Some(o) => o,
_ => return Ok(()),
};
output.removed.set(true);
output.events.push(ConnectorEvent::Removed);
output.changed();
Ok(())
}
@ -820,6 +814,11 @@ impl XBackendData {
old.fb.set(new.fb.get());
old.pixmap.set(new.pixmap.get());
}
output.events.push(ConnectorEvent::ModeChanged(Mode {
width,
height,
refresh_rate: 60, // TODO
}));
output.changed();
}
Ok(())
@ -830,7 +829,7 @@ struct XOutput {
id: OutputId,
_backend: Rc<XBackendData>,
window: u32,
removed: Cell<bool>,
events: SyncQueue<ConnectorEvent>,
width: Cell<i32>,
height: Cell<i32>,
serial: NumCell<u32>,
@ -856,21 +855,13 @@ impl XOutput {
}
}
impl Output for XOutput {
impl Connector for XOutput {
fn id(&self) -> OutputId {
self.id
}
fn removed(&self) -> bool {
self.removed.get()
}
fn width(&self) -> i32 {
self.width.get()
}
fn height(&self) -> i32 {
self.height.get()
fn event(&self) -> Option<ConnectorEvent> {
self.events.pop()
}
fn on_change(&self, cb: Rc<dyn Fn()>) {

View file

@ -120,12 +120,12 @@ fn main_(logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
{
let dummy_output = Rc::new(OutputNode {
id: state.node_ids.next(),
position: Default::default(),
global: Rc::new(WlOutputGlobal::new(
state.globals.name(),
Rc::new(DummyOutput {
id: state.output_ids.next(),
}),
0,
)),
workspaces: Default::default(),
workspace: Default::default(),

View file

@ -32,6 +32,7 @@ pub use sys::{
drm_mode_modeinfo, DRM_CLIENT_CAP_ATOMIC, DRM_MODE_ATOMIC_ALLOW_MODESET,
DRM_MODE_ATOMIC_NONBLOCK, DRM_MODE_PAGE_FLIP_EVENT,
};
use crate::utils::vec_ext::VecExt;
#[derive(Debug, Error)]
pub enum DrmError {
@ -63,6 +64,8 @@ pub enum DrmError {
GetPropBlob(#[source] OsError),
#[error("Property has an invalid size")]
InvalidProbSize,
#[error("Property has a size that is not a multiple of the vector type")]
UnalignedPropSize,
#[error("Could not perform drm properties ioctl")]
GetProperties(#[source] OsError),
#[error("Could not perform drm atomic ioctl")]
@ -316,6 +319,25 @@ impl DrmMaster {
}
}
pub fn getblob_vec<T: Pod>(&self, blob: DrmBlob) -> Result<Vec<T>, DrmError> {
assert_ne!(mem::size_of::<T>(), 0);
let mut vec = vec![];
loop {
let (_, bytes) = vec.split_at_spare_mut_bytes_ext();
match mode_getprobblob(self.raw(), blob.0, bytes) {
Err(e) => return Err(DrmError::GetPropBlob(e)),
Ok(n) if n % mem::size_of::<T>() != 0 => return Err(DrmError::UnalignedPropSize),
Ok(n) if n <= bytes.len() => {
unsafe {
vec.set_len(n / mem::size_of::<T>());
}
return Ok(vec);
}
Ok(n) => vec.reserve_exact(n / mem::size_of::<T>()),
}
}
}
pub fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
if self.events.is_empty() {
let mut buf = self.buf.borrow_mut();
@ -570,6 +592,16 @@ impl DrmModeInfo {
name,
}
}
pub fn refresh_rate(&self) -> u32 {
let clock_mhz = self.clock as u64 * 1_000_000;
let htotal = self.htotal as u64;
let vtotal = self.vtotal as u64;
(((clock_mhz / htotal) + (vtotal / 2)) / vtotal) as u32
// simplifies to
// clock_mhz / (htotal * vtotal) + 1/2
// why round up (+1/2) instead of down?
}
}
#[derive(Debug)]

1059
src/edid.rs Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
use crate::backend::Output;
use crate::backend::Connector;
use crate::client::{Client, ClientError, ClientId};
use crate::globals::{Global, GlobalName};
use crate::ifs::zxdg_output_v1::ZxdgOutputV1;
@ -17,6 +17,7 @@ use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::rc::Rc;
use thiserror::Error;
use crate::backend;
const SP_UNKNOWN: i32 = 0;
#[allow(dead_code)]
@ -52,18 +53,20 @@ const MODE_PREFERRED: u32 = 2;
pub struct WlOutputGlobal {
name: GlobalName,
output: Rc<dyn Output>,
pos: Cell<Rect>,
pub connector: Rc<dyn Connector>,
pub pos: Cell<Rect>,
pub mode: Cell<backend::Mode>,
pub node: CloneCell<Option<Rc<OutputNode>>>,
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
}
impl WlOutputGlobal {
pub fn new(name: GlobalName, output: Rc<dyn Output>) -> Self {
pub fn new(name: GlobalName, connector: Rc<dyn Connector>, x1: i32) -> Self {
Self {
name,
output: output.clone(),
pos: Cell::new(Rect::new_sized(0, 0, output.width(), output.height()).unwrap()),
connector: connector.clone(),
pos: Cell::new(Rect::new_empty(x1, 0)),
mode: Default::default(),
node: Default::default(),
bindings: Default::default(),
}
@ -73,30 +76,18 @@ impl WlOutputGlobal {
self.pos.get()
}
pub fn update_properties(&self) {
let width = self.output.width();
let height = self.output.height();
let pos = self.pos.get();
let old_width = pos.width();
let old_height = pos.height();
let changed = old_width != width || old_height != height;
if changed {
self.pos
.set(Rect::new_sized(pos.x1(), pos.y1(), width, height).unwrap());
let bindings = self.bindings.borrow_mut();
for binding in bindings.values() {
for binding in binding.values() {
binding.send_geometry();
binding.send_mode();
binding.send_scale();
binding.send_done();
binding.client.flush();
let xdg = binding.xdg_outputs.lock();
for xdg in xdg.values() {
xdg.send_updates();
}
pub fn send_mode(&self) {
let bindings = self.bindings.borrow_mut();
for binding in bindings.values() {
for binding in binding.values() {
binding.send_geometry();
binding.send_mode();
binding.send_scale();
binding.send_done();
binding.client.flush();
let xdg = binding.xdg_outputs.lock();
for xdg in xdg.values() {
xdg.send_updates();
}
}
}

View file

@ -102,7 +102,7 @@ impl XdgPopup {
let mut rel_pos = positioner.get_position(false, false);
let mut abs_pos = rel_pos.move_(parent_abs.x1(), parent_abs.y1());
if let Some(ws) = parent.workspace.get() {
let output_pos = ws.output.get().position.get();
let output_pos = ws.output.get().global.pos.get();
let mut overflow = output_pos.get_overflow(&abs_pos);
if !overflow.is_contained() {
let mut flip_x = positioner.ca.contains(CA::FLIP_X) && overflow.x_overflow();

View file

@ -262,7 +262,7 @@ impl ZwlrLayerSurfaceV1 {
if anchor == 0 {
anchor = LEFT | RIGHT | TOP | BOTTOM;
}
let opos = self.output.position.get();
let opos = self.output.global.pos.get();
let mut x1 = opos.x1();
let mut y1 = opos.y1();
if anchor.contains(LEFT) {

View file

@ -82,7 +82,7 @@ impl ZwlrLayerShellV1 {
}
}
};
log::info!("output = {:?}", output.position.get());
log::info!("output = {:?}", output.global.pos.get());
if req.layer > OVERLAY {
return Err(GetLayerSurfaceError::UnknownLayer(req.layer));
}

View file

@ -78,6 +78,7 @@ mod wire_xcon;
mod xcon;
mod xkbcommon;
mod xwayland;
mod edid;
fn main() {
cli::main();

View file

@ -29,7 +29,7 @@ pub struct Renderer<'a> {
impl Renderer<'_> {
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
let opos = output.position.get();
let opos = output.global.pos.get();
macro_rules! render_layer {
($layer:expr) => {
for ls in $layer.iter() {

View file

@ -184,7 +184,7 @@ impl State {
width += 2 * self.theme.border_width.get();
height += 2 * self.theme.border_width.get() + self.theme.title_height.get();
let output = workspace.output.get();
let output_rect = output.position.get();
let output_rect = output.global.pos.get();
let position = {
let mut x1 = output_rect.x1();
let mut y1 = output_rect.y1();

View file

@ -1,4 +1,4 @@
use crate::backend::{BackendEvent, Output};
use crate::backend::{BackendEvent, Connector};
use crate::state::State;
use crate::tasks::input_device;
use crate::tasks::output::OutputHandler;
@ -18,12 +18,12 @@ impl BackendEventHandler {
fn handle_event(&mut self, event: BackendEvent) {
match event {
BackendEvent::NewOutput(output) => self.handle_new_output(output),
BackendEvent::NewConnector(output) => self.handle_new_output(output),
BackendEvent::NewInputDevice(s) => input_device::handle(&self.state, s),
}
}
fn handle_new_output(&mut self, output: Rc<dyn Output>) {
fn handle_new_output(&mut self, output: Rc<dyn Connector>) {
let id = output.id();
let oh = OutputHandler {
state: self.state.clone(),

View file

@ -1,16 +1,16 @@
use crate::backend::Output;
use crate::backend::{Connector, ConnectorEvent};
use crate::ifs::wl_output::WlOutputGlobal;
use crate::rect::Rect;
use crate::state::State;
use crate::tree::{OutputNode, OutputRenderData, WorkspaceNode};
use crate::utils::asyncevent::AsyncEvent;
use crate::utils::clonecell::CloneCell;
use std::cell::{Cell, RefCell};
use std::cell::{RefCell};
use std::rc::Rc;
pub struct OutputHandler {
pub state: Rc<State>,
pub output: Rc<dyn Output>,
pub output: Rc<dyn Connector>,
}
impl OutputHandler {
@ -21,12 +21,11 @@ impl OutputHandler {
self.output.on_change(Rc::new(move || ae.trigger()));
}
let name = self.state.globals.name();
let global = Rc::new(WlOutputGlobal::new(name, self.output.clone()));
let x1 = self.state.root.outputs.lock().values().map(|o| o.position.get().x2()).max().unwrap_or(0);
let x1 = self.state.root.outputs.lock().values().map(|o| o.global.pos.get().x2()).max().unwrap_or(0);
let global = Rc::new(WlOutputGlobal::new(name, self.output.clone(), x1));
let on = Rc::new(OutputNode {
id: self.state.node_ids.next(),
workspaces: Default::default(),
position: Cell::new(Rect::new_empty(x1, 0)),
workspace: CloneCell::new(None),
seat_state: Default::default(),
global: global.clone(),
@ -68,20 +67,15 @@ impl OutputHandler {
self.state.root.outputs.set(self.output.id(), on.clone());
self.state.add_global(&global);
self.state.outputs.set(self.output.id(), global.clone());
let mut width = 0;
let mut height = 0;
loop {
if self.output.removed() {
break;
'outer: loop {
while let Some(event) = self.output.event() {
match event {
ConnectorEvent::Removed => break 'outer,
ConnectorEvent::ModeChanged(mode) => {
on.update_mode(mode);
}
}
}
let new_width = self.output.width();
let new_height = self.output.height();
if new_width != width || new_height != height {
width = new_width;
height = new_height;
on.change_size(new_width, new_height);
}
global.update_properties();
ae.triggered().await;
}
global.node.set(None);

View file

@ -434,7 +434,7 @@ impl Node for DisplayNode {
}
let outputs = self.outputs.lock();
for output in outputs.values() {
let pos = output.position.get();
let pos = output.global.pos.get();
if pos.contains(x, y) {
let (x, y) = pos.translate(x, y);
tree.push(FoundNode {

View file

@ -13,15 +13,15 @@ use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
use crate::utils::clonecell::CloneCell;
use crate::utils::errorfmt::ErrorFmt;
use crate::utils::linkedlist::LinkedList;
use std::cell::{Cell, RefCell};
use std::cell::{RefCell};
use std::fmt::{Debug, Formatter};
use std::ops::{Deref, Sub};
use std::rc::Rc;
use crate::backend::Mode;
tree_id!(OutputNodeId);
pub struct OutputNode {
pub id: OutputNodeId,
pub position: Cell<Rect>,
pub global: Rc<WlOutputGlobal>,
pub workspaces: LinkedList<Rc<WorkspaceNode>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
@ -84,7 +84,7 @@ impl OutputNode {
}
fn workspace_rect(&self) -> Rect {
let rect = self.position.get();
let rect = self.global.pos.get();
let th = self.state.theme.title_height.get();
Rect::new_sized(
rect.x1(),
@ -95,10 +95,13 @@ impl OutputNode {
.unwrap()
}
pub fn change_size(&self, width: i32, height: i32) {
let pos = self.position.get();
let rect = Rect::new_sized(pos.x1(), pos.y1(), width, height).unwrap();
self.position.set(rect);
pub fn update_mode(&self, mode: Mode) {
if self.global.mode.get() == mode {
return;
}
let pos = self.global.pos.get();
let rect = Rect::new_sized(pos.x1(), pos.y1(), mode.width, mode.height).unwrap();
self.global.pos.set(rect);
if let Some(c) = self.workspace.get() {
c.change_extents(&self.workspace_rect());
}
@ -107,6 +110,7 @@ impl OutputNode {
surface.deref().clone().change_extents(&rect);
}
}
self.global.send_mode();
}
}
@ -166,7 +170,7 @@ impl Node for OutputNode {
}
fn absolute_position(&self) -> Rect {
self.position.get()
self.global.pos.get()
}
fn find_tree_at(&self, x: i32, mut y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {

View file

@ -1,4 +1,4 @@
use crate::utils::ptr_ext::MutPtrExt;
use crate::utils::ptr_ext::{MutPtrExt, PtrExt};
use std::cell::UnsafeCell;
pub struct Stack<T> {
@ -23,4 +23,13 @@ impl<T> Stack<T> {
pub fn pop(&self) -> Option<T> {
unsafe { self.vec.get().deref_mut().pop() }
}
pub fn to_vec(&self) -> Vec<T>
where T: Clone,
{
unsafe {
let v = self.vec.get().deref();
(*v).clone()
}
}
}

View file

@ -3,6 +3,7 @@ use std::cell::UnsafeCell;
use std::collections::VecDeque;
use std::mem;
#[derive(Debug)]
pub struct SyncQueue<T> {
el: UnsafeCell<VecDeque<T>>,
}