Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Nov 29, 2024
1 parent a14d075 commit e12f7a4
Show file tree
Hide file tree
Showing 13 changed files with 313 additions and 222 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,5 @@ 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" }
79 changes: 58 additions & 21 deletions src/backend/kms/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,31 @@ use crate::{
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::{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, DevPath, DeviceFd, Point, Rectangle, Transform},
wayland::drm_lease::{DrmLease, DrmLeaseState},
};
use tracing::{error, info, warn};
Expand All @@ -32,7 +38,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 +50,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 +88,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 +205,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 +296,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 +397,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 +451,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 +470,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 +522,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 +565,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
102 changes: 82 additions & 20 deletions src/backend/kms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ use smithay::{
output::Output,
reexports::{
calloop::{Dispatcher, EventLoop, LoopHandle},
drm::control::{crtc, Device as _},
drm::{
control::{crtc, Device as _},
Device as _,
},
input::{self, Libinput},
wayland_server::{Client, DisplayHandle},
},
utils::{DevPath, Size},
utils::{Clock, DevPath, Monotonic, Size},
wayland::{dmabuf::DmabufGlobal, relative_pointer::RelativePointerManagerState},
};
use surface::GbmDrmOutput;
use tracing::{error, info, trace, warn};

use std::{
Expand All @@ -53,7 +57,9 @@ pub(crate) use surface::Surface;
use device::*;
pub use surface::Timings;

use super::render::init_shaders;
use super::render::{
element::CosmicElement, init_shaders, output_elements, CursorMode, CLEAR_COLOR,
};

#[derive(Debug)]
pub struct KmsState {
Expand Down Expand Up @@ -321,6 +327,7 @@ impl State {
&mut state.common.workspace_state.update(),
&state.common.xdg_activation_state,
state.common.startup_done.clone(),
&state.common.clock,
);
state.common.refresh();
});
Expand Down Expand Up @@ -528,6 +535,7 @@ impl KmsState {
loop_handle: &LoopHandle<'static, State>,
shell: Arc<RwLock<Shell>>,
startup_done: Arc<AtomicBool>,
clock: &Clock<Monotonic>,
) -> Result<Vec<Output>, anyhow::Error> {
if !self.session.is_active() {
return Ok(Vec::new());
Expand All @@ -554,7 +562,7 @@ impl KmsState {
// TODO: Right now we always keep crtcs of already enabled outputs,
// even if another configuration could potentially enable more outputs

let res_handles = device.drm.resource_handles()?;
let res_handles = device.drm.device().resource_handles()?;
let free_crtcs = res_handles
.crtcs()
.iter()
Expand All @@ -579,16 +587,20 @@ impl KmsState {
});

for conn in open_conns {
let conn_info = device.drm.get_connector(conn, false).with_context(|| {
format!(
"Failed to query drm device: {:?}",
device.drm.dev_path().as_deref().map(Path::display),
)
})?;
let conn_info = device
.drm
.device()
.get_connector(conn, false)
.with_context(|| {
format!(
"Failed to query drm device: {:?}",
device.drm.device().dev_path().as_deref().map(Path::display),
)
})?;
'outer: for encoder_info in conn_info
.encoders()
.iter()
.flat_map(|encoder_handle| device.drm.get_encoder(*encoder_handle))
.flat_map(|encoder_handle| device.drm.device().get_encoder(*encoder_handle))
{
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
if free_crtcs.contains(&crtc) {
Expand Down Expand Up @@ -638,13 +650,20 @@ impl KmsState {

let mut all_outputs = Vec::new();
for device in self.drm_devices.values_mut() {
// reconfigure
// reconfigure existing
let now = clock.now();
let output_map = device
.surfaces
.iter()
.map(|(crtc, surface)| (*crtc, surface.output.clone()))
.collect::<HashMap<_, _>>();

for (crtc, surface) in device.surfaces.iter_mut() {
let output_config = surface.output.config();

let drm = &mut device.drm;
let conn = surface.connector;
let conn_info = drm.get_connector(conn, false)?;
let conn_info = drm.device().get_connector(conn, false)?;
let mode = conn_info
.modes()
.iter()
Expand All @@ -662,14 +681,57 @@ impl KmsState {

if !test_only {
if !surface.is_active() {
let drm_surface = drm
.create_surface(*crtc, *mode, &[conn])
.with_context(|| "Failed to create drm surface")?;
let gbm = device.gbm.clone();
let cursor_size = drm.cursor_size();
let compositor: GbmDrmOutput = {
let mut planes = drm
.device()
.planes(crtc)
.with_context(|| "Failed to enumerate planes")?;
let driver = drm.device().get_driver().ok();

// QUIRK: Using an overlay plane on a nvidia card breaks the display controller (wtf...)
if driver.is_some_and(|driver| {
driver
.name()
.to_string_lossy()
.to_lowercase()
.contains("nvidia")
}) {
planes.overlay = vec![];
}

let mut builder = drm.initialize_output::<_, CosmicElement<_>>(*crtc);

let mut renderer = self
.api
.single_renderer(&device.render_node)
.with_context(|| "Failed to create renderer")?;

for (crtc, output) in output_map.iter() {
let elements = output_elements(
Some(&device.render_node),
&mut renderer,
&shell,
now,
&output,
CursorMode::All,
None,
)
.with_context(|| "Failed to render outputs")?;

builder.add_render_contents(crtc, CLEAR_COLOR, elements);
}

let compositor = builder
.build(&mut renderer, *mode, &[conn], &surface.output, Some(planes))
.with_context(|| "Failed to create drm surface")?;

let _ = renderer;

compositor
};

if let Some(bpc) = output_config.max_bpc {
if let Err(err) = drm_helpers::set_max_bpc(drm, conn, bpc) {
if let Err(err) = drm_helpers::set_max_bpc(drm.device(), conn, bpc) {
warn!(
?bpc,
?err,
Expand All @@ -682,7 +744,7 @@ impl KmsState {
let vrr = output_config.vrr;
std::mem::drop(output_config);

match surface.resume(drm_surface, gbm, cursor_size) {
match surface.resume(compositor) {
Ok(_) => {
surface.output.set_adaptive_sync_support(
surface.adaptive_sync_support().ok(),
Expand Down
Loading

0 comments on commit e12f7a4

Please sign in to comment.