Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use DrmOutputManager/DrmOutput #1020

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ inherits = "release"
lto = "fat"

[patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/smithay//smithay", rev = "bc1d732" }
#smithay = { git = "https://github.com/smithay//smithay", rev = "bc1d732" }
smithay = { git = "https://github.com/cmeissl/smithay", branch = "feature/drm_auto_select" }

[patch.crates-io]
pixman = { git = "https://github.com/ids1024/pixman-rs", branch = "send" }
138 changes: 117 additions & 21 deletions src/backend/kms/device.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
// SPDX-License-Identifier: GPL-3.0-only

use crate::{
backend::render::{output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR},
config::{AdaptiveSync, OutputConfig, OutputState},
shell::Shell,
utils::prelude::*,
wayland::protocols::screencopy::Frame as ScreencopyFrame,
};

use anyhow::{Context, Result};
use libc::dev_t;
use smithay::{
backend::{
allocator::gbm::GbmDevice,
drm::{DrmDevice, DrmDeviceFd, DrmEvent, DrmNode},
allocator::{
gbm::{GbmAllocator, GbmDevice},
Fourcc,
},
drm::{
compositor::FrameMode, output::DrmOutputManager, DrmDevice, DrmDeviceFd, DrmEvent,
DrmNode,
},
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
session::Session,
},
desktop::utils::OutputPresentationFeedback,
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
reexports::{
calloop::{LoopHandle, RegistrationToken},
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
gbm::BufferObjectFlags as GbmBufferFlags,
rustix::fs::OFlags,
wayland_server::{protocol::wl_buffer::WlBuffer, DisplayHandle, Weak},
},
utils::{DevPath, DeviceFd, Point, Transform},
utils::{
Buffer as BufferCoords, Clock, DevPath, DeviceFd, Monotonic, Point, Rectangle, Transform,
},
wayland::drm_lease::{DrmLease, DrmLeaseState},
};
use tracing::{error, info, warn};
Expand All @@ -32,7 +44,7 @@ use std::{
collections::{HashMap, HashSet},
fmt,
path::{Path, PathBuf},
sync::{atomic::AtomicBool, Arc, RwLock},
sync::{atomic::AtomicBool, mpsc::Receiver, Arc, RwLock},
};

use super::{drm_helpers, socket::Socket, surface::Surface};
Expand All @@ -44,15 +56,25 @@ pub struct EGLInternals {
pub context: EGLContext,
}

pub type GbmDrmOutputManager = DrmOutputManager<
GbmAllocator<DrmDeviceFd>,
GbmDevice<DrmDeviceFd>,
Option<(
OutputPresentationFeedback,
Receiver<(ScreencopyFrame, Vec<Rectangle<i32, BufferCoords>>)>,
)>,
DrmDeviceFd,
>;

pub struct Device {
pub dev_node: DrmNode,
pub render_node: DrmNode,
pub egl: Option<EGLInternals>,

pub outputs: HashMap<connector::Handle, Output>,
pub surfaces: HashMap<crtc::Handle, Surface>,
pub drm: GbmDrmOutputManager,
pub gbm: GbmDevice<DrmDeviceFd>,
pub drm: DrmDevice,

supports_atomic: bool,

Expand All @@ -72,8 +94,7 @@ impl fmt::Debug for Device {
.field("render_node", &self.render_node)
.field("outputs", &self.outputs)
.field("surfaces", &self.surfaces)
.field("drm", &self.drm)
.field("gbm", &self.gbm)
.field("drm", &"..")
.field("egl", &self.egl)
.field("supports_atomic", &self.supports_atomic)
.field("leased_connectors", &self.leased_connectors)
Expand Down Expand Up @@ -190,15 +211,32 @@ impl State {
}
};

let drm = GbmDrmOutputManager::new(
drm,
GbmAllocator::new(
gbm.clone(),
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
),
gbm.clone(),
Some(gbm.clone()),
[
Fourcc::Abgr2101010,
Fourcc::Argb2101010,
Fourcc::Abgr8888,
Fourcc::Argb8888,
],
render_formats,
);

let mut device = Device {
dev_node: drm_node,
render_node,
egl: None,

outputs: HashMap::new(),
surfaces: HashMap::new(),
gbm: gbm.clone(),
drm,
gbm,

supports_atomic,

Expand Down Expand Up @@ -264,6 +302,7 @@ impl State {
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
self.common.startup_done.clone(),
&self.common.clock,
);

self.backend.kms().refresh_used_devices()?;
Expand Down Expand Up @@ -364,6 +403,7 @@ impl State {
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
self.common.startup_done.clone(),
&self.common.clock,
);
// Don't remove the outputs, before potentially new ones have been initialized.
// reading a new config means outputs might become enabled, that were previously disabled.
Expand Down Expand Up @@ -417,6 +457,7 @@ impl State {
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
self.common.startup_done.clone(),
&self.common.clock,
);
self.common.refresh();
} else {
Expand All @@ -435,7 +476,8 @@ pub struct OutputChanges {
impl Device {
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
// enumerate our outputs
let config = drm_helpers::display_configuration(&mut self.drm, self.supports_atomic)?;
let config =
drm_helpers::display_configuration(self.drm.device_mut(), self.supports_atomic)?;

let surfaces = self
.surfaces
Expand Down Expand Up @@ -486,19 +528,20 @@ impl Device {
.get(&conn)
.cloned()
.map(|output| Ok(output))
.unwrap_or_else(|| create_output_for_conn(&mut self.drm, conn))
.unwrap_or_else(|| create_output_for_conn(self.drm.device_mut(), conn))
.context("Failed to create `Output`")?;

let non_desktop = match drm_helpers::get_property_val(&self.drm, conn, "non-desktop") {
Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(),
Err(err) => {
warn!(
?err,
"Failed to determine if connector is meant desktop usage, assuming so."
);
false
}
};
let non_desktop =
match drm_helpers::get_property_val(self.drm.device_mut(), conn, "non-desktop") {
Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(),
Err(err) => {
warn!(
?err,
"Failed to determine if connector is meant desktop usage, assuming so."
);
false
}
};

if non_desktop {
if let Some(crtc) = maybe_crtc {
Expand Down Expand Up @@ -528,7 +571,7 @@ impl Device {
.user_data()
.insert_if_missing(|| RefCell::new(OutputConfig::default()));

populate_modes(&mut self.drm, &output, conn, position)
populate_modes(self.drm.device_mut(), &output, conn, position)
.with_context(|| "Failed to enumerate connector modes")?;

let has_surface = if let Some(crtc) = maybe_crtc {
Expand Down Expand Up @@ -569,6 +612,59 @@ impl Device {
}
}

pub fn allow_direct_scanout(
&mut self,
flag: bool,
renderer: &mut GlMultiRenderer,
clock: &Clock<Monotonic>,
shell: &Arc<RwLock<Shell>>,
) -> Result<()> {
for surface in self.surfaces.values_mut() {
surface.allow_direct_scanout(flag);
}

if !flag {
let now = clock.now();

let output_map = self
.surfaces
.iter()
.map(|(crtc, surface)| (*crtc, surface.output.clone()))
.collect::<HashMap<_, _>>();

self.drm.with_compositors::<Result<()>>(|map| {
for (crtc, compositor) in map.iter() {
let elements = match output_map.get(crtc) {
Some(output) => output_elements(
Some(&self.render_node),
renderer,
shell,
now,
&output,
CursorMode::All,
None,
)
.with_context(|| "Failed to render outputs")?,
None => Vec::new(),
};

let mut compositor = compositor.lock().unwrap();
compositor.render_frame(
renderer,
&elements,
CLEAR_COLOR,
FrameMode::COMPOSITE,
)?;
compositor.commit_frame()?;
}

Ok(())
})?;
}

Ok(())
}

pub fn in_use(&self, primary: Option<&DrmNode>) -> bool {
Some(&self.render_node) == primary
|| !self.surfaces.is_empty()
Expand Down
Loading
Loading