mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-27 01:13:09 +00:00
feat(compositor): implement DRM/KMS rendering path
Add full DRM/KMS backend with libseat session, GBM allocation, EGL display initialisation, and a GpuManager-driven rendering loop. - drm_device.rs: type aliases and per-device/per-output state structs (WeftDrmDevice, WeftOutputSurface, WeftDrmData) - drm.rs: replace skeleton with complete backend libseat session, udev device enumeration, libinput event source, connector scanning via smithay-drm-extras DrmScanner, DrmOutputManager initialisation per CRTC, VBlank-driven render_output, sd_notify(READY=1) - state.rs: add drm: Option<WeftDrmData> field; route dmabuf import through GPU manager when the DRM path is active - Cargo.toml: add renderer_multi, use_system_lib Smithay features; add smithay-drm-extras and sd-notify Linux dependencies render_output submits a clear-colour-only frame to establish the VBlank pipeline. Surface compositing is wired up in a subsequent commit.
This commit is contained in:
parent
7d8b1cfecd
commit
8925ebe3df
6 changed files with 854 additions and 81 deletions
179
Cargo.lock
generated
179
Cargo.lock
generated
|
|
@ -24,6 +24,12 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aliasable"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.0"
|
||||
|
|
@ -78,12 +84,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
|
@ -184,7 +184,6 @@ version = "0.14.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7"
|
||||
dependencies = [
|
||||
"async-task",
|
||||
"bitflags 2.11.0",
|
||||
"polling",
|
||||
"rustix 1.1.4",
|
||||
|
|
@ -204,18 +203,6 @@ dependencies = [
|
|||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop-wayland-source"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
|
||||
dependencies = [
|
||||
"calloop 0.14.4",
|
||||
"rustix 1.1.4",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.56"
|
||||
|
|
@ -234,6 +221,16 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.20.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c6b04e07d8080154ed4ac03546d9a2b303cc2fe1901ba0b35b301516e289368"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
|
|
@ -520,6 +517,8 @@ dependencies = [
|
|||
"drm-fourcc",
|
||||
"gbm-sys",
|
||||
"libc",
|
||||
"wayland-backend",
|
||||
"wayland-server",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -739,6 +738,40 @@ version = "0.2.183"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
|
||||
|
||||
[[package]]
|
||||
name = "libdisplay-info"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4210cfe93a0dc37228e08105e3c13171e5af816f7bd39e00e3d3adcf2b487a2b"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"libc",
|
||||
"libdisplay-info-derive",
|
||||
"libdisplay-info-sys",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libdisplay-info-derive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dc2c710cf5819e91220a446d9e64acc6814386cc22c509c3f0df83c0b874a98"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libdisplay-info-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4f9264ece23c37ffa023ae635f48d588e1786745dad06dff10c9fb99dc646c"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
|
|
@ -839,6 +872,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
|
|
@ -1389,6 +1431,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "sd-notify"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b943eadf71d8b69e661330cb0e2656e31040acf21ee7708e2c238a0ec6af2bf4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.27"
|
||||
|
|
@ -1437,6 +1488,15 @@ dependencies = [
|
|||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.9"
|
||||
|
|
@ -1481,6 +1541,7 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "740cea6927892bc182d5bf70c8f79806c8bc9f68f2fb96e55a30be171b63af98"
|
||||
dependencies = [
|
||||
"aliasable",
|
||||
"appendlist",
|
||||
"atomic_float",
|
||||
"bitflags 2.11.0",
|
||||
|
|
@ -1510,6 +1571,7 @@ dependencies = [
|
|||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
"udev",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-egl",
|
||||
|
|
@ -1517,6 +1579,7 @@ dependencies = [
|
|||
"wayland-protocols-misc",
|
||||
"wayland-protocols-wlr",
|
||||
"wayland-server",
|
||||
"wayland-sys",
|
||||
"winit",
|
||||
"xkbcommon",
|
||||
]
|
||||
|
|
@ -1529,7 +1592,7 @@ checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
|
|||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"calloop 0.13.0",
|
||||
"calloop-wayland-source 0.3.0",
|
||||
"calloop-wayland-source",
|
||||
"cursor-icon",
|
||||
"libc",
|
||||
"log",
|
||||
|
|
@ -1546,6 +1609,16 @@ dependencies = [
|
|||
"xkeysym",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-drm-extras"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa68109eb23955c216dadb780b0a82e5b0d1dd4b649d4a52b59100eb83a30e96"
|
||||
dependencies = [
|
||||
"drm",
|
||||
"libdisplay-info",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol_str"
|
||||
version = "0.2.2"
|
||||
|
|
@ -1566,6 +1639,25 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "7.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48c8f33736f986f16d69b6cb8b03f55ddcad5c41acc4ccc39dd88e84aa805e7f"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"heck",
|
||||
"pkg-config",
|
||||
"toml",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.26.0"
|
||||
|
|
@ -1628,6 +1720,30 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.12+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime 0.7.5+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.0.0+spec-1.1.0"
|
||||
|
|
@ -1644,7 +1760,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_datetime 1.0.0+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
|
@ -1658,6 +1774,12 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.44"
|
||||
|
|
@ -1762,6 +1884,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
|
|
@ -2031,7 +2159,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "374f6b70e8e0d6bf9461a32988fd553b59ff630964924dad6e4a4eb6bd538d17"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"libc",
|
||||
"log",
|
||||
"memoffset",
|
||||
"once_cell",
|
||||
"pkg-config",
|
||||
]
|
||||
|
|
@ -2065,14 +2195,11 @@ name = "weft-compositor"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"calloop 0.14.4",
|
||||
"calloop-wayland-source 0.4.1",
|
||||
"sd-notify",
|
||||
"smithay",
|
||||
"smithay-drm-extras",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols-wlr",
|
||||
"wayland-server",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -5,9 +5,6 @@ edition.workspace = true
|
|||
rust-version.workspace = true
|
||||
publish = false
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "weft-compositor"
|
||||
path = "src/main.rs"
|
||||
|
|
@ -33,4 +30,8 @@ smithay = { version = "0.7", default-features = false, features = [
|
|||
"backend_libinput",
|
||||
"backend_udev",
|
||||
"backend_session_libseat",
|
||||
"renderer_multi",
|
||||
"use_system_lib",
|
||||
] }
|
||||
smithay-drm-extras = "0.1"
|
||||
sd-notify = "0.4"
|
||||
|
|
|
|||
|
|
@ -1,88 +1,645 @@
|
|||
// Non-Linux: DRM/KMS backend is unavailable; callers must use --winit.
|
||||
// Non-Linux: DRM/KMS backend is unavailable; callers must use --winit.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn run() -> anyhow::Result<()> {
|
||||
anyhow::bail!("DRM/KMS backend requires Linux; pass --winit for development on other platforms")
|
||||
}
|
||||
|
||||
// Linux DRM/KMS backend.
|
||||
// GPU enumeration and rendering are deferred; this skeleton establishes the
|
||||
// session, socket, and event loop that the full implementation will extend.
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::{collections::HashMap, path::Path, sync::Arc, time::Duration};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use anyhow::Context;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::{
|
||||
format::FormatSet,
|
||||
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
||||
Fourcc, Modifier,
|
||||
},
|
||||
drm::{
|
||||
compositor::FrameFlags,
|
||||
exporter::gbm::GbmFramebufferExporter,
|
||||
output::{DrmOutputManager, DrmOutputRenderElements},
|
||||
DrmDevice, DrmDeviceFd, DrmEvent, DrmNode, NodeType,
|
||||
},
|
||||
egl::{EGLDevice, EGLDisplay},
|
||||
input::InputEvent,
|
||||
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
||||
renderer::{
|
||||
element::surface::WaylandSurfaceRenderElement,
|
||||
gles::GlesRenderer,
|
||||
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer},
|
||||
},
|
||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||
},
|
||||
output::{Mode as WlMode, Output, PhysicalProperties, Subpixel},
|
||||
reexports::{
|
||||
calloop::{EventLoop, Interest, Mode, PostAction, generic::Generic},
|
||||
drm::control::{connector, crtc, ModeTypeFlags},
|
||||
input::{DeviceCapability, Libinput},
|
||||
rustix::fs::OFlags,
|
||||
wayland_server::Display,
|
||||
},
|
||||
utils::{DeviceFd, Transform},
|
||||
wayland::socket::ListeningSocketSource,
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use smithay_drm_extras::drm_scanner::{DrmScanEvent, DrmScanner};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::{
|
||||
input,
|
||||
state::{WeftClientState, WeftCompositorState},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use super::drm_device::{WeftDrmData, WeftDrmDevice, WeftOutputSurface};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const SUPPORTED_FORMATS: &[Fourcc] = &[
|
||||
Fourcc::Abgr2101010,
|
||||
Fourcc::Argb2101010,
|
||||
Fourcc::Abgr8888,
|
||||
Fourcc::Argb8888,
|
||||
];
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888];
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
type WeftMultiRenderer<'a> = MultiRenderer<
|
||||
'a,
|
||||
'a,
|
||||
GbmGlesBackend<GlesRenderer, DrmDeviceFd>,
|
||||
GbmGlesBackend<GlesRenderer, DrmDeviceFd>,
|
||||
>;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn run() -> anyhow::Result<()> {
|
||||
use std::sync::Arc;
|
||||
|
||||
use smithay::{
|
||||
backend::{
|
||||
session::{Session, libseat::LibSeatSession},
|
||||
udev::{UdevBackend, UdevEvent},
|
||||
},
|
||||
reexports::calloop::{EventLoop, Interest, Mode, PostAction, generic::Generic},
|
||||
wayland::socket::ListeningSocketSource,
|
||||
};
|
||||
|
||||
use crate::state::{WeftClientState, WeftCompositorState};
|
||||
|
||||
let mut display = smithay::reexports::wayland_server::Display::<WeftCompositorState>::new()?;
|
||||
let display_handle = display.handle();
|
||||
|
||||
let mut event_loop: EventLoop<'static, WeftCompositorState> = EventLoop::try_new()?;
|
||||
let loop_handle = event_loop.handle();
|
||||
|
||||
let mut display = Display::<WeftCompositorState>::new()?;
|
||||
let display_handle = display.handle();
|
||||
|
||||
let (session, session_notifier) =
|
||||
LibSeatSession::new().context("failed to create libseat session")?;
|
||||
|
||||
let seat_name = session.seat().to_owned();
|
||||
let loop_signal = event_loop.get_signal();
|
||||
|
||||
// Gain DRM device access without root via libseat.
|
||||
let (session, _notifier) =
|
||||
LibSeatSession::new().map_err(|e| anyhow::anyhow!("libseat session failed: {e}"))?;
|
||||
let primary_gpu_node = if let Ok(var) = std::env::var("WEFT_DRM_DEVICE") {
|
||||
DrmNode::from_path(var).context("invalid WEFT_DRM_DEVICE path")?
|
||||
} else {
|
||||
primary_gpu(&seat_name)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|p| DrmNode::from_path(p).ok()?.node_with_type(NodeType::Render)?.ok())
|
||||
.or_else(|| {
|
||||
all_gpus(&seat_name)
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.find_map(|p| DrmNode::from_path(p).ok())
|
||||
})
|
||||
.context("no GPU found")?
|
||||
};
|
||||
tracing::info!(?primary_gpu_node, "primary GPU");
|
||||
|
||||
let listening_socket = ListeningSocketSource::new_auto()
|
||||
.map_err(|e| anyhow::anyhow!("Wayland socket creation failed: {e}"))?;
|
||||
let gpu_manager: super::drm_device::WeftGpuManager =
|
||||
GpuManager::new(Default::default()).context("failed to create GPU manager")?;
|
||||
|
||||
let listening_socket =
|
||||
ListeningSocketSource::new_auto().context("failed to create Wayland socket")?;
|
||||
let socket_name = listening_socket.socket_name().to_os_string();
|
||||
std::env::set_var("WAYLAND_DISPLAY", &socket_name);
|
||||
tracing::info!(?socket_name, "Wayland compositor socket open");
|
||||
tracing::info!(?socket_name, "Wayland socket open");
|
||||
|
||||
loop_handle
|
||||
.insert_source(listening_socket, |client_stream, _, state| {
|
||||
.insert_source(listening_socket, |stream, _, state| {
|
||||
state
|
||||
.display_handle
|
||||
.insert_client(client_stream, Arc::new(WeftClientState::default()))
|
||||
.insert_client(stream, Arc::new(WeftClientState::default()))
|
||||
.unwrap();
|
||||
})
|
||||
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
|
||||
.map_err(|e| anyhow::anyhow!("socket source: {e}"))?;
|
||||
|
||||
loop_handle
|
||||
.insert_source(
|
||||
Generic::new(display, Interest::READ, Mode::Level),
|
||||
|_, display, state| {
|
||||
// Safety: the display is owned by this Generic source and is never
|
||||
// dropped while the event loop runs.
|
||||
// Safety: Display is owned by this Generic source and outlives the event loop.
|
||||
unsafe {
|
||||
display.get_mut().dispatch_clients(state).unwrap();
|
||||
}
|
||||
Ok(PostAction::Continue)
|
||||
},
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("display source insertion failed: {e}"))?;
|
||||
.map_err(|e| anyhow::anyhow!("display source: {e}"))?;
|
||||
|
||||
let udev_backend =
|
||||
UdevBackend::new(&seat_name).context("failed to create udev backend")?;
|
||||
|
||||
let mut libinput_ctx =
|
||||
Libinput::new_with_udev::<LibinputSessionInterface<LibSeatSession>>(
|
||||
session.clone().into(),
|
||||
);
|
||||
libinput_ctx
|
||||
.udev_assign_seat(&seat_name)
|
||||
.map_err(|_| anyhow::anyhow!("libinput seat assignment failed"))?;
|
||||
let libinput_backend = LibinputInputBackend::new(libinput_ctx);
|
||||
|
||||
// Enumerate GPU nodes via udev; hotplug events arrive through calloop.
|
||||
let udev_backend = UdevBackend::new(session.seat())?;
|
||||
loop_handle
|
||||
.insert_source(udev_backend, move |event, _, _state| match event {
|
||||
UdevEvent::Added { device_id, path } => {
|
||||
tracing::info!(?device_id, ?path, "GPU device added");
|
||||
}
|
||||
UdevEvent::Changed { device_id } => {
|
||||
tracing::debug!(?device_id, "GPU device changed");
|
||||
}
|
||||
UdevEvent::Removed { device_id } => {
|
||||
tracing::info!(?device_id, "GPU device removed");
|
||||
}
|
||||
.insert_source(
|
||||
libinput_backend,
|
||||
move |mut event, _, state: &mut WeftCompositorState| {
|
||||
if let InputEvent::DeviceAdded { device } = &mut event {
|
||||
if device.has_capability(DeviceCapability::Keyboard) {
|
||||
if let Some(led) = state.seat.get_keyboard().map(|k| k.led_state()) {
|
||||
device.led_update(led.into());
|
||||
}
|
||||
if let Some(drm) = state.drm.as_mut() {
|
||||
drm.keyboards.push(device.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
input::process_input_event(state, event);
|
||||
},
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("libinput source: {e}"))?;
|
||||
|
||||
loop_handle
|
||||
.insert_source(
|
||||
session_notifier,
|
||||
move |event, &mut (), state: &mut WeftCompositorState| match event {
|
||||
SessionEvent::PauseSession => {
|
||||
if let Some(drm) = state.drm.as_mut() {
|
||||
for dev in drm.devices.values_mut() {
|
||||
dev.drm_output_manager.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
SessionEvent::ActivateSession => {
|
||||
tracing::info!("session activated");
|
||||
}
|
||||
},
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("session notifier: {e}"))?;
|
||||
|
||||
loop_handle
|
||||
.insert_source(
|
||||
udev_backend,
|
||||
move |event, _, state: &mut WeftCompositorState| match event {
|
||||
UdevEvent::Added { device_id: _, path } => {
|
||||
let node = match DrmNode::from_path(&path) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, "failed to build DRM node");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Err(e) = device_added(state, node, &path) {
|
||||
tracing::warn!(?e, "failed to add DRM device");
|
||||
}
|
||||
}
|
||||
UdevEvent::Changed { device_id } => {
|
||||
let node = state
|
||||
.drm
|
||||
.as_ref()
|
||||
.and_then(|d| d.devices.keys().find(|n| n.dev_id() == device_id).copied());
|
||||
if let Some(node) = node {
|
||||
device_changed(state, node);
|
||||
}
|
||||
}
|
||||
UdevEvent::Removed { device_id } => {
|
||||
let node = state
|
||||
.drm
|
||||
.as_ref()
|
||||
.and_then(|d| d.devices.keys().find(|n| n.dev_id() == device_id).copied());
|
||||
if let Some(node) = node {
|
||||
device_removed(state, node);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("udev source: {e}"))?;
|
||||
|
||||
let mut state = WeftCompositorState::new(
|
||||
display_handle.clone(),
|
||||
loop_signal,
|
||||
loop_handle,
|
||||
seat_name,
|
||||
);
|
||||
|
||||
state.drm = Some(WeftDrmData {
|
||||
session,
|
||||
primary_gpu: primary_gpu_node,
|
||||
gpu_manager,
|
||||
devices: HashMap::new(),
|
||||
keyboards: Vec::new(),
|
||||
display_handle,
|
||||
});
|
||||
|
||||
let existing: Vec<(DrmNode, std::path::PathBuf)> = state
|
||||
.drm
|
||||
.as_ref()
|
||||
.map(|d| {
|
||||
all_gpus(d.session.seat())
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|p| DrmNode::from_path(&p).ok().map(|n| (n, p)))
|
||||
.collect()
|
||||
})
|
||||
.map_err(|e| anyhow::anyhow!("udev source insertion failed: {e}"))?;
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut state =
|
||||
WeftCompositorState::new(display_handle, loop_signal, loop_handle, session.seat());
|
||||
for (node, path) in existing {
|
||||
if let Err(e) = device_added(&mut state, node, &path) {
|
||||
tracing::warn!(?e, ?node, "startup device_added failed");
|
||||
}
|
||||
}
|
||||
|
||||
let _ = sd_notify::notify(false, &[sd_notify::NotifyState::Ready]);
|
||||
|
||||
tracing::info!("DRM/KMS backend initialised; entering event loop");
|
||||
event_loop.run(None, &mut state, |_| {})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn device_added(
|
||||
state: &mut WeftCompositorState,
|
||||
node: DrmNode,
|
||||
path: &Path,
|
||||
) -> anyhow::Result<()> {
|
||||
let drm_data = state.drm.as_mut().context("DRM data not initialised")?;
|
||||
|
||||
let fd = drm_data
|
||||
.session
|
||||
.open(
|
||||
path,
|
||||
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
|
||||
)
|
||||
.context("failed to open DRM device")?;
|
||||
|
||||
let fd = DrmDeviceFd::new(DeviceFd::from(fd));
|
||||
let (drm, notifier) =
|
||||
DrmDevice::new(fd.clone(), true).context("DrmDevice::new failed")?;
|
||||
let gbm = GbmDevice::new(fd).context("GbmDevice::new failed")?;
|
||||
|
||||
let render_node = (|| -> anyhow::Result<DrmNode> {
|
||||
// Safety: EGLDisplay requires the GBM device to outlive it; gbm lives in WeftDrmDevice.
|
||||
let egl_display =
|
||||
unsafe { EGLDisplay::new(gbm.clone()).context("EGLDisplay::new failed")? };
|
||||
let egl_device =
|
||||
EGLDevice::device_for_display(&egl_display).context("no EGL device")?;
|
||||
if egl_device.is_software() {
|
||||
anyhow::bail!("software renderer");
|
||||
}
|
||||
let rn = egl_device
|
||||
.try_get_render_node()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
drm_data
|
||||
.gpu_manager
|
||||
.as_mut()
|
||||
.add_node(rn, gbm.clone())
|
||||
.map_err(|e| anyhow::anyhow!("add_node: {e:?}"))?;
|
||||
Ok(rn)
|
||||
})()
|
||||
.map_err(|e| {
|
||||
tracing::warn!(?e, "EGL init failed; output may render black");
|
||||
e
|
||||
})
|
||||
.ok();
|
||||
|
||||
let effective_gpu = render_node.unwrap_or(drm_data.primary_gpu);
|
||||
|
||||
let allocator = GbmAllocator::new(
|
||||
gbm.clone(),
|
||||
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
||||
);
|
||||
|
||||
let exporter = GbmFramebufferExporter::new(gbm.clone(), render_node.into());
|
||||
|
||||
let color_formats = if std::env::var("WEFT_DISABLE_10BIT").is_ok() {
|
||||
SUPPORTED_FORMATS_8BIT_ONLY
|
||||
} else {
|
||||
SUPPORTED_FORMATS
|
||||
};
|
||||
|
||||
let render_formats: FormatSet = drm_data
|
||||
.gpu_manager
|
||||
.single_renderer(&effective_gpu)
|
||||
.map(|r| {
|
||||
r.as_ref()
|
||||
.egl_context()
|
||||
.dmabuf_render_formats()
|
||||
.iter()
|
||||
.filter(|f| render_node.is_some() || f.modifier == Modifier::Linear)
|
||||
.copied()
|
||||
.collect::<FormatSet>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let drm_output_manager = DrmOutputManager::new(
|
||||
drm,
|
||||
allocator,
|
||||
exporter,
|
||||
Some(gbm),
|
||||
color_formats.iter().copied(),
|
||||
render_formats,
|
||||
);
|
||||
|
||||
let registration_token = state
|
||||
.loop_handle
|
||||
.insert_source(
|
||||
notifier,
|
||||
move |event, _metadata, data: &mut WeftCompositorState| match event {
|
||||
DrmEvent::VBlank(crtc) => render_output(data, node, crtc),
|
||||
DrmEvent::Error(e) => tracing::error!(?e, "DRM error"),
|
||||
},
|
||||
)
|
||||
.map_err(|e| anyhow::anyhow!("DRM notifier: {e}"))?;
|
||||
|
||||
state.drm.as_mut().unwrap().devices.insert(
|
||||
node,
|
||||
WeftDrmDevice {
|
||||
drm_output_manager,
|
||||
drm_scanner: DrmScanner::new(),
|
||||
surfaces: HashMap::new(),
|
||||
render_node,
|
||||
registration_token,
|
||||
},
|
||||
);
|
||||
|
||||
device_changed(state, node);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn device_changed(state: &mut WeftCompositorState, node: DrmNode) {
|
||||
let drm_data = match state.drm.as_mut() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
let device = match drm_data.devices.get_mut(&node) {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let events: Vec<DrmScanEvent> = device
|
||||
.drm_scanner
|
||||
.scan_connectors(device.drm_output_manager.device());
|
||||
|
||||
for event in events {
|
||||
match event {
|
||||
DrmScanEvent::Connected {
|
||||
connector,
|
||||
crtc: Some(crtc),
|
||||
} => connector_connected(state, node, connector, crtc),
|
||||
DrmScanEvent::Disconnected {
|
||||
connector,
|
||||
crtc: Some(crtc),
|
||||
} => connector_disconnected(state, node, connector, crtc),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn connector_connected(
|
||||
state: &mut WeftCompositorState,
|
||||
node: DrmNode,
|
||||
connector: connector::Info,
|
||||
crtc: crtc::Handle,
|
||||
) {
|
||||
let name = format!("{:?}-{}", connector.interface(), connector.interface_id());
|
||||
|
||||
let mode = match connector
|
||||
.modes()
|
||||
.iter()
|
||||
.find(|m| m.mode_type().contains(ModeTypeFlags::PREFERRED))
|
||||
.copied()
|
||||
.or_else(|| connector.modes().first().copied())
|
||||
{
|
||||
Some(m) => m,
|
||||
None => {
|
||||
tracing::warn!(?name, "connector has no modes");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let wl_mode = WlMode {
|
||||
size: (mode.size().0 as i32, mode.size().1 as i32).into(),
|
||||
refresh: mode.vrefresh() as i32 * 1000,
|
||||
};
|
||||
|
||||
let output = Output::new(
|
||||
name.clone(),
|
||||
PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "Unknown".to_string(),
|
||||
model: name.clone(),
|
||||
},
|
||||
);
|
||||
|
||||
let drm_data = match state.drm.as_mut() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let global = output.create_global::<WeftCompositorState>(&drm_data.display_handle);
|
||||
output.change_current_state(
|
||||
Some(wl_mode),
|
||||
Some(Transform::Normal),
|
||||
None,
|
||||
Some((0, 0).into()),
|
||||
);
|
||||
output.set_preferred(wl_mode);
|
||||
|
||||
let render_node = drm_data
|
||||
.devices
|
||||
.get(&node)
|
||||
.and_then(|d| d.render_node)
|
||||
.unwrap_or(drm_data.primary_gpu);
|
||||
|
||||
let planes = drm_data
|
||||
.devices
|
||||
.get_mut(&node)
|
||||
.and_then(|d| d.drm_output_manager.device().planes(&crtc).ok());
|
||||
|
||||
let WeftDrmData {
|
||||
ref mut gpu_manager,
|
||||
ref mut devices,
|
||||
..
|
||||
} = *drm_data;
|
||||
|
||||
let device = match devices.get_mut(&node) {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let mut renderer = match gpu_manager.single_renderer(&render_node) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, "no renderer for output init");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let drm_output = match device.drm_output_manager.initialize_output(
|
||||
crtc,
|
||||
mode,
|
||||
&[connector.handle()],
|
||||
&output,
|
||||
planes,
|
||||
&mut renderer,
|
||||
&DrmOutputRenderElements::default(),
|
||||
) {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, ?name, "initialize_output failed");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
device.surfaces.insert(
|
||||
crtc,
|
||||
WeftOutputSurface {
|
||||
output: output.clone(),
|
||||
drm_output,
|
||||
device_id: node,
|
||||
global,
|
||||
},
|
||||
);
|
||||
|
||||
state.space.map_output(&output, (0, 0));
|
||||
tracing::info!(?name, "output connected");
|
||||
render_output(state, node, crtc);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn connector_disconnected(
|
||||
state: &mut WeftCompositorState,
|
||||
node: DrmNode,
|
||||
_connector: connector::Info,
|
||||
crtc: crtc::Handle,
|
||||
) {
|
||||
let drm_data = match state.drm.as_mut() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
if let Some(device) = drm_data.devices.get_mut(&node) {
|
||||
if let Some(surface) = device.surfaces.remove(&crtc) {
|
||||
state.space.unmap_output(&surface.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn device_removed(state: &mut WeftCompositorState, node: DrmNode) {
|
||||
let drm_data = match state.drm.as_mut() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
if let Some(device) = drm_data.devices.remove(&node) {
|
||||
state.loop_handle.remove(device.registration_token);
|
||||
for surface in device.surfaces.into_values() {
|
||||
state.space.unmap_output(&surface.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Handle) {
|
||||
let output = {
|
||||
let drm_data = match state.drm.as_ref() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
match drm_data
|
||||
.devices
|
||||
.get(&node)
|
||||
.and_then(|d| d.surfaces.get(&crtc))
|
||||
{
|
||||
Some(s) => s.output.clone(),
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
|
||||
let render_node = {
|
||||
let d = state.drm.as_ref().unwrap();
|
||||
d.devices
|
||||
.get(&node)
|
||||
.and_then(|d| d.render_node)
|
||||
.unwrap_or(d.primary_gpu)
|
||||
};
|
||||
|
||||
let WeftCompositorState {
|
||||
ref mut drm,
|
||||
ref space,
|
||||
..
|
||||
} = *state;
|
||||
|
||||
let drm_data = match drm.as_mut() {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let WeftDrmData {
|
||||
ref mut gpu_manager,
|
||||
ref mut devices,
|
||||
..
|
||||
} = *drm_data;
|
||||
|
||||
let device = match devices.get_mut(&node) {
|
||||
Some(d) => d,
|
||||
None => return,
|
||||
};
|
||||
let surface = match device.surfaces.get_mut(&crtc) {
|
||||
Some(s) => s,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let mut renderer = match gpu_manager.single_renderer(&render_node) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
tracing::warn!(?e, "renderer unavailable");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Wave 2: clear-colour-only frame to establish the VBlank pipeline.
|
||||
// Surface compositing is added in Wave 3.
|
||||
let elements: &[WaylandSurfaceRenderElement<WeftMultiRenderer<'_>>] = &[];
|
||||
match surface.drm_output.render_frame(
|
||||
&mut renderer,
|
||||
elements,
|
||||
[0.08_f32, 0.08, 0.08, 1.0],
|
||||
FrameFlags::DEFAULT,
|
||||
) {
|
||||
Ok(result) if !result.is_empty => {
|
||||
if let Err(e) = surface.drm_output.queue_frame(None) {
|
||||
tracing::warn!(?e, "queue_frame failed");
|
||||
}
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(e) => tracing::warn!(?e, "render_frame failed"),
|
||||
}
|
||||
|
||||
space.elements().for_each(|window| {
|
||||
window.send_frame(
|
||||
&output,
|
||||
Duration::ZERO,
|
||||
Some(Duration::ZERO),
|
||||
|_, _| Some(output.clone()),
|
||||
);
|
||||
});
|
||||
|
||||
let _ = state.display_handle.flush_clients();
|
||||
}
|
||||
65
crates/weft-compositor/src/backend/drm_device.rs
Normal file
65
crates/weft-compositor/src/backend/drm_device.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::gbm::GbmAllocator,
|
||||
drm::{
|
||||
exporter::gbm::GbmFramebufferExporter,
|
||||
output::{DrmOutput, DrmOutputManager},
|
||||
DrmDeviceFd, DrmNode,
|
||||
},
|
||||
renderer::{
|
||||
gles::GlesRenderer,
|
||||
multigpu::{gbm::GbmGlesBackend, GpuManager},
|
||||
},
|
||||
session::libseat::LibSeatSession,
|
||||
},
|
||||
desktop::utils::OutputPresentationFeedback,
|
||||
output::Output,
|
||||
reexports::{
|
||||
calloop::RegistrationToken,
|
||||
drm::control::crtc,
|
||||
wayland_server::{backend::GlobalId, DisplayHandle},
|
||||
},
|
||||
};
|
||||
use smithay_drm_extras::drm_scanner::DrmScanner;
|
||||
|
||||
pub type WeftAllocator = GbmAllocator<DrmDeviceFd>;
|
||||
pub type WeftExporter = GbmFramebufferExporter<DrmDeviceFd>;
|
||||
pub type WeftDrmOutput = DrmOutput<
|
||||
WeftAllocator,
|
||||
WeftExporter,
|
||||
Option<OutputPresentationFeedback>,
|
||||
DrmDeviceFd,
|
||||
>;
|
||||
pub type WeftDrmOutputManager = DrmOutputManager<
|
||||
WeftAllocator,
|
||||
WeftExporter,
|
||||
Option<OutputPresentationFeedback>,
|
||||
DrmDeviceFd,
|
||||
>;
|
||||
pub type WeftGpuManager = GpuManager<GbmGlesBackend<GlesRenderer, DrmDeviceFd>>;
|
||||
|
||||
pub struct WeftOutputSurface {
|
||||
pub output: Output,
|
||||
pub drm_output: WeftDrmOutput,
|
||||
pub device_id: DrmNode,
|
||||
pub global: GlobalId,
|
||||
}
|
||||
|
||||
pub struct WeftDrmDevice {
|
||||
pub drm_output_manager: WeftDrmOutputManager,
|
||||
pub drm_scanner: DrmScanner,
|
||||
pub surfaces: HashMap<crtc::Handle, WeftOutputSurface>,
|
||||
pub render_node: Option<DrmNode>,
|
||||
pub registration_token: RegistrationToken,
|
||||
}
|
||||
|
||||
pub struct WeftDrmData {
|
||||
pub session: LibSeatSession,
|
||||
pub primary_gpu: DrmNode,
|
||||
pub gpu_manager: WeftGpuManager,
|
||||
pub devices: HashMap<DrmNode, WeftDrmDevice>,
|
||||
pub keyboards: Vec<smithay::reexports::input::Device>,
|
||||
pub display_handle: DisplayHandle,
|
||||
}
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
pub mod drm;
|
||||
pub mod winit;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod drm_device;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#[cfg(target_os = "linux")]
|
||||
use crate::backend::drm_device::WeftDrmData;
|
||||
|
||||
use smithay::{
|
||||
backend::{input::TabletToolDescriptor, renderer::utils::on_commit_buffer_handler},
|
||||
delegate_compositor, delegate_cursor_shape, delegate_dmabuf, delegate_input_method_manager,
|
||||
|
|
@ -81,6 +84,9 @@ pub struct WeftCompositorState {
|
|||
|
||||
// Set to false when the compositor should exit the event loop.
|
||||
pub running: bool,
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub drm: Option<WeftDrmData>,
|
||||
}
|
||||
|
||||
impl WeftCompositorState {
|
||||
|
|
@ -134,6 +140,8 @@ impl WeftCompositorState {
|
|||
cursor_image_status: CursorImageStatus::Hidden,
|
||||
dmabuf_global: None,
|
||||
running: true,
|
||||
#[cfg(target_os = "linux")]
|
||||
drm: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -291,12 +299,24 @@ impl DmabufHandler for WeftCompositorState {
|
|||
fn dmabuf_imported(
|
||||
&mut self,
|
||||
_global: &DmabufGlobal,
|
||||
_dmabuf: smithay::backend::allocator::dmabuf::Dmabuf,
|
||||
dmabuf: smithay::backend::allocator::dmabuf::Dmabuf,
|
||||
notifier: ImportNotifier,
|
||||
) {
|
||||
// DMA-BUF import requires the renderer, which lives in the backend run function.
|
||||
// The backend is responsible for creating the global only when it can service imports.
|
||||
// If we reach here without a backend handler wired up, reject.
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(drm) = self.drm.as_mut() {
|
||||
use smithay::backend::renderer::ImportDma;
|
||||
let node = drm.primary_gpu;
|
||||
if drm
|
||||
.gpu_manager
|
||||
.single_renderer(&node)
|
||||
.ok()
|
||||
.and_then(|mut r| r.import_dmabuf(&dmabuf, None).ok())
|
||||
.is_some()
|
||||
{
|
||||
let _ = notifier.successful::<Self>();
|
||||
return;
|
||||
}
|
||||
}
|
||||
drop(notifier);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue