2022-01-20 19:51:46 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
use crate::{
|
2022-02-04 21:04:17 +01:00
|
|
|
backend::render,
|
2022-04-14 22:16:37 +02:00
|
|
|
config::OutputConfig,
|
2022-04-13 22:59:14 +02:00
|
|
|
shell::Shell,
|
2022-11-22 18:20:20 +01:00
|
|
|
state::{BackendData, ClientState, Common, Data, Fps},
|
2022-07-04 15:29:31 +02:00
|
|
|
utils::prelude::*,
|
2022-11-03 18:51:27 +01:00
|
|
|
wayland::{
|
2022-12-03 00:06:20 +01:00
|
|
|
handlers::screencopy::UserdataExt,
|
2022-11-03 18:51:27 +01:00
|
|
|
protocols::screencopy::{BufferParams, Session as ScreencopySession},
|
|
|
|
|
},
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
2022-02-04 21:23:27 +01:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
use anyhow::{Context, Result};
|
|
|
|
|
use smithay::{
|
|
|
|
|
backend::{
|
2023-02-13 17:44:24 +01:00
|
|
|
allocator::{
|
|
|
|
|
dmabuf::{AnyError, Dmabuf, DmabufAllocator},
|
|
|
|
|
gbm::{GbmAllocator, GbmBufferFlags, GbmDevice},
|
|
|
|
|
vulkan::{ImageUsageFlags, VulkanAllocator},
|
|
|
|
|
Allocator, Format,
|
|
|
|
|
},
|
2022-12-27 18:27:29 +01:00
|
|
|
drm::{
|
|
|
|
|
DrmDevice, DrmDeviceFd, DrmEvent, DrmEventTime, DrmNode, GbmBufferedSurface, NodeType,
|
|
|
|
|
},
|
2022-02-04 21:23:27 +01:00
|
|
|
egl::{EGLContext, EGLDevice, EGLDisplay},
|
2022-04-25 23:00:30 +02:00
|
|
|
input::InputEvent,
|
2022-01-25 15:45:15 +01:00
|
|
|
libinput::{LibinputInputBackend, LibinputSessionInterface},
|
2022-03-16 20:06:31 +01:00
|
|
|
renderer::{
|
2022-09-28 12:01:29 +02:00
|
|
|
damage::DamageTrackedRenderer,
|
2022-11-17 20:32:54 +01:00
|
|
|
gles2::Gles2Renderbuffer,
|
|
|
|
|
glow::GlowRenderer,
|
2023-02-13 17:44:24 +01:00
|
|
|
multigpu::{gbm::GbmGlesBackend, GpuManager},
|
2022-03-16 20:06:31 +01:00
|
|
|
},
|
2023-01-03 19:17:51 +01:00
|
|
|
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
2022-03-16 20:06:31 +01:00
|
|
|
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
2023-02-13 17:44:24 +01:00
|
|
|
vulkan::{version::Version, Instance, PhysicalDevice},
|
2022-01-25 15:45:15 +01:00
|
|
|
},
|
2022-11-17 20:32:54 +01:00
|
|
|
desktop::utils::OutputPresentationFeedback,
|
2022-11-22 10:07:17 +01:00
|
|
|
input::Seat,
|
2022-09-09 20:00:00 -07:00
|
|
|
output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel},
|
2022-01-25 15:45:15 +01:00
|
|
|
reexports::{
|
2022-02-04 21:23:27 +01:00
|
|
|
calloop::{
|
2022-05-12 14:04:21 +02:00
|
|
|
timer::{TimeoutAction, Timer},
|
|
|
|
|
Dispatcher, EventLoop, InsertError, LoopHandle, RegistrationToken,
|
2022-01-25 15:45:15 +01:00
|
|
|
},
|
2022-04-05 16:35:58 +02:00
|
|
|
drm::control::{connector, crtc, Device as ControlDevice, ModeTypeFlags},
|
2022-01-25 15:45:15 +01:00
|
|
|
input::Libinput,
|
2022-02-04 21:23:27 +01:00
|
|
|
nix::{fcntl::OFlag, sys::stat::dev_t},
|
2022-11-17 20:32:54 +01:00
|
|
|
wayland_protocols::wp::presentation_time::server::wp_presentation_feedback,
|
2022-09-09 20:00:00 -07:00
|
|
|
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
2022-01-25 15:45:15 +01:00
|
|
|
},
|
2023-01-03 19:17:51 +01:00
|
|
|
utils::{DeviceFd, Size, Transform},
|
2023-02-27 13:54:49 -08:00
|
|
|
wayland::{
|
|
|
|
|
dmabuf::DmabufGlobal, relative_pointer::RelativePointerManagerState, seat::WaylandFocus,
|
|
|
|
|
},
|
2023-01-24 19:32:57 +01:00
|
|
|
xwayland::XWaylandClientData,
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
2023-03-03 19:34:41 +01:00
|
|
|
use tracing::{error, info, trace, warn};
|
2022-02-04 21:23:27 +01:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
use std::{
|
|
|
|
|
cell::RefCell,
|
|
|
|
|
collections::{HashMap, HashSet},
|
2023-02-13 17:44:24 +01:00
|
|
|
ffi::CStr,
|
2022-12-27 18:27:29 +01:00
|
|
|
os::unix::io::FromRawFd,
|
2022-01-25 15:45:15 +01:00
|
|
|
path::PathBuf,
|
2022-09-28 12:01:29 +02:00
|
|
|
time::Duration,
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
2022-01-20 19:51:46 +01:00
|
|
|
|
2022-02-01 13:59:39 +01:00
|
|
|
mod drm_helpers;
|
2022-03-22 12:41:54 +01:00
|
|
|
mod socket;
|
|
|
|
|
use socket::*;
|
2022-01-25 15:45:15 +01:00
|
|
|
|
2023-02-25 00:17:54 +01:00
|
|
|
use super::render::{init_shaders, CursorMode, GlMultiRenderer};
|
2022-11-22 18:20:20 +01:00
|
|
|
// for now we assume we need at least 3ms
|
|
|
|
|
const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
|
2022-09-28 12:01:29 +02:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
pub struct KmsState {
|
2022-03-16 20:06:31 +01:00
|
|
|
devices: HashMap<DrmNode, Device>,
|
2023-02-13 17:44:24 +01:00
|
|
|
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
2022-07-04 15:29:31 +02:00
|
|
|
pub primary: DrmNode,
|
2023-01-03 19:17:51 +01:00
|
|
|
session: LibSeatSession,
|
2022-04-26 12:28:50 +02:00
|
|
|
_tokens: Vec<RegistrationToken>,
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Device {
|
2022-03-16 20:06:31 +01:00
|
|
|
render_node: DrmNode,
|
2022-01-25 15:45:15 +01:00
|
|
|
surfaces: HashMap<crtc::Handle, Surface>,
|
2023-02-27 23:53:27 +01:00
|
|
|
drm: DrmDevice,
|
2023-02-13 17:44:24 +01:00
|
|
|
gbm: GbmDevice<DrmDeviceFd>,
|
|
|
|
|
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
|
2022-01-25 15:45:15 +01:00
|
|
|
formats: HashSet<Format>,
|
|
|
|
|
supports_atomic: bool,
|
|
|
|
|
event_token: Option<RegistrationToken>,
|
2022-03-22 12:41:54 +01:00
|
|
|
socket: Option<Socket>,
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Surface {
|
2023-02-13 17:44:24 +01:00
|
|
|
surface:
|
|
|
|
|
Option<GbmBufferedSurface<GbmAllocator<DrmDeviceFd>, Option<OutputPresentationFeedback>>>,
|
2022-09-28 12:01:29 +02:00
|
|
|
damage_tracker: DamageTrackedRenderer,
|
2022-04-13 22:59:14 +02:00
|
|
|
connector: connector::Handle,
|
2022-01-25 15:45:15 +01:00
|
|
|
output: Output,
|
|
|
|
|
refresh_rate: u32,
|
|
|
|
|
vrr: bool,
|
|
|
|
|
pending: bool,
|
2022-11-09 12:39:47 +01:00
|
|
|
dirty: bool,
|
2022-01-25 15:45:15 +01:00
|
|
|
render_timer_token: Option<RegistrationToken>,
|
2022-02-04 21:04:17 +01:00
|
|
|
fps: Fps,
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
pub fn init_backend(
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
event_loop: &mut EventLoop<'static, Data>,
|
|
|
|
|
state: &mut State,
|
|
|
|
|
) -> Result<()> {
|
2023-02-24 17:41:52 +01:00
|
|
|
let (session, notifier) = LibSeatSession::new().context("Failed to acquire session")?;
|
2022-01-25 15:45:15 +01:00
|
|
|
|
2023-02-24 17:41:52 +01:00
|
|
|
let udev_backend = UdevBackend::new(session.seat())?;
|
2022-02-04 21:23:27 +01:00
|
|
|
let mut libinput_context =
|
2023-01-03 19:17:51 +01:00
|
|
|
Libinput::new_with_udev::<LibinputSessionInterface<LibSeatSession>>(session.clone().into());
|
2022-02-04 21:23:27 +01:00
|
|
|
libinput_context
|
|
|
|
|
.udev_assign_seat(&session.seat())
|
|
|
|
|
.map_err(|_| anyhow::anyhow!("Failed to assign seat to libinput"))?;
|
2023-02-24 17:41:52 +01:00
|
|
|
let libinput_backend = LibinputInputBackend::new(libinput_context.clone());
|
2022-01-25 15:45:15 +01:00
|
|
|
|
|
|
|
|
let libinput_event_source = event_loop
|
|
|
|
|
.handle()
|
2022-07-04 15:29:31 +02:00
|
|
|
.insert_source(libinput_backend, move |mut event, _, data| {
|
2022-04-25 23:00:30 +02:00
|
|
|
if let &mut InputEvent::DeviceAdded { ref mut device } = &mut event {
|
2022-07-04 15:29:31 +02:00
|
|
|
data.state.common.config.read_device(device);
|
2022-04-25 23:00:30 +02:00
|
|
|
}
|
2022-08-31 13:01:23 +02:00
|
|
|
data.state.process_input_event(event);
|
2022-07-04 15:29:31 +02:00
|
|
|
for output in data.state.common.shell.outputs() {
|
2022-11-03 18:51:27 +01:00
|
|
|
if let Err(err) = data.state.backend.kms().schedule_render(
|
|
|
|
|
&data.state.common.event_loop_handle,
|
|
|
|
|
output,
|
|
|
|
|
None,
|
2022-11-17 20:32:54 +01:00
|
|
|
None,
|
2022-11-03 18:51:27 +01:00
|
|
|
) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(
|
|
|
|
|
?err,
|
|
|
|
|
"Error scheduling event loop for output {}.",
|
2022-07-04 16:00:29 +02:00
|
|
|
output.name(),
|
|
|
|
|
);
|
2022-05-12 14:04:21 +02:00
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map_err(|err| err.error)
|
|
|
|
|
.context("Failed to initialize libinput event source")?;
|
2023-02-24 17:41:52 +01:00
|
|
|
let api = GpuManager::new(GbmGlesBackend::<GlowRenderer>::default())
|
2022-09-28 12:01:29 +02:00
|
|
|
.context("Failed to initialize renderers")?;
|
2022-03-16 20:06:31 +01:00
|
|
|
|
|
|
|
|
// TODO get this info from system76-power, if available and setup a watcher
|
|
|
|
|
let primary = if let Some(path) = std::env::var("COSMIC_RENDER_DEVICE")
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|x| DrmNode::from_path(x).ok())
|
|
|
|
|
{
|
|
|
|
|
path
|
|
|
|
|
} else {
|
2023-03-03 12:22:14 -08:00
|
|
|
let primary_node = primary_gpu(session.seat())
|
2022-03-16 20:06:31 +01:00
|
|
|
.ok()
|
|
|
|
|
.flatten()
|
2023-03-03 12:22:14 -08:00
|
|
|
.and_then(|x| DrmNode::from_path(x).ok());
|
|
|
|
|
primary_node
|
2022-03-16 20:06:31 +01:00
|
|
|
.and_then(|x| x.node_with_type(NodeType::Render).and_then(Result::ok))
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
for dev in all_gpus(session.seat()).expect("No GPU found") {
|
|
|
|
|
if let Some(node) = DrmNode::from_path(dev)
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|x| x.node_with_type(NodeType::Render).and_then(Result::ok))
|
|
|
|
|
{
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-03 12:22:14 -08:00
|
|
|
// If we find no render nodes, use primary node
|
|
|
|
|
if let Some(primary_node) = primary_node {
|
|
|
|
|
return primary_node;
|
|
|
|
|
} else {
|
|
|
|
|
panic!("Failed to initialize any GPU");
|
|
|
|
|
}
|
2022-03-16 20:06:31 +01:00
|
|
|
})
|
|
|
|
|
};
|
2023-02-24 17:41:52 +01:00
|
|
|
info!("Using {} as primary gpu for rendering.", primary);
|
2022-03-16 20:06:31 +01:00
|
|
|
|
2022-07-04 15:29:31 +02:00
|
|
|
let udev_dispatcher = Dispatcher::new(udev_backend, move |event, _, data: &mut Data| {
|
2022-04-26 12:28:50 +02:00
|
|
|
match match event {
|
2022-07-04 16:00:29 +02:00
|
|
|
UdevEvent::Added { device_id, path } => data
|
|
|
|
|
.state
|
2023-02-14 23:15:58 +01:00
|
|
|
.device_added(device_id, path, &data.display.handle(), true)
|
2022-04-26 12:28:50 +02:00
|
|
|
.with_context(|| format!("Failed to add drm device: {}", device_id)),
|
2022-07-04 16:00:29 +02:00
|
|
|
UdevEvent::Changed { device_id } => data
|
|
|
|
|
.state
|
2022-04-26 12:28:50 +02:00
|
|
|
.device_changed(device_id)
|
|
|
|
|
.with_context(|| format!("Failed to update drm device: {}", device_id)),
|
2022-07-04 16:00:29 +02:00
|
|
|
UdevEvent::Removed { device_id } => data
|
|
|
|
|
.state
|
2022-07-04 15:29:31 +02:00
|
|
|
.device_removed(device_id, &data.display.handle())
|
2022-04-26 12:28:50 +02:00
|
|
|
.with_context(|| format!("Failed to remove drm device: {}", device_id)),
|
|
|
|
|
} {
|
|
|
|
|
Ok(()) => {
|
2023-03-03 19:34:41 +01:00
|
|
|
trace!("Successfully handled udev event.")
|
2022-04-26 12:28:50 +02:00
|
|
|
}
|
|
|
|
|
Err(err) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Error while handling udev event.")
|
2022-04-26 12:28:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
let udev_event_source = event_loop
|
|
|
|
|
.handle()
|
|
|
|
|
.register_dispatcher(udev_dispatcher.clone())
|
|
|
|
|
.unwrap();
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2022-04-26 12:28:50 +02:00
|
|
|
let handle = event_loop.handle();
|
2022-04-27 13:25:17 +02:00
|
|
|
let loop_signal = state.common.event_loop_signal.clone();
|
2022-04-26 12:28:50 +02:00
|
|
|
let dispatcher = udev_dispatcher.clone();
|
2023-01-03 19:17:51 +01:00
|
|
|
let session_event_source = event_loop
|
|
|
|
|
.handle()
|
|
|
|
|
.insert_source(notifier, move |event, &mut (), data| match event {
|
|
|
|
|
SessionEvent::ActivateSession => {
|
|
|
|
|
if let Err(err) = libinput_context.resume() {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Failed to resume libinput context.");
|
2023-01-03 19:17:51 +01:00
|
|
|
}
|
2023-01-25 18:43:35 +01:00
|
|
|
for device in data.state.backend.kms().devices.values() {
|
2023-02-27 23:53:27 +01:00
|
|
|
device.drm.activate();
|
2023-01-25 18:43:35 +01:00
|
|
|
}
|
2023-01-03 19:17:51 +01:00
|
|
|
let dispatcher = dispatcher.clone();
|
|
|
|
|
handle.insert_idle(move |data| {
|
|
|
|
|
for (dev, path) in dispatcher.as_source_ref().device_list() {
|
|
|
|
|
let drm_node = match DrmNode::from_dev_id(dev) {
|
|
|
|
|
Ok(node) => node,
|
|
|
|
|
Err(err) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Failed to read drm device {}.", path.display(),);
|
2023-01-03 19:17:51 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if data.state.backend.kms().devices.contains_key(&drm_node) {
|
|
|
|
|
if let Err(err) = data.state.device_changed(dev) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Failed to update drm device {}.", path.display(),);
|
2023-01-03 19:17:51 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2023-02-10 14:32:56 -08:00
|
|
|
if let Err(err) = data.state.device_added(
|
|
|
|
|
dev,
|
|
|
|
|
path.into(),
|
|
|
|
|
&data.display.handle(),
|
|
|
|
|
true,
|
|
|
|
|
) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Failed to add drm device {}.", path.display(),);
|
2023-01-03 19:17:51 +01:00
|
|
|
}
|
2022-04-26 12:28:50 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-07-04 15:29:31 +02:00
|
|
|
|
2023-01-03 19:17:51 +01:00
|
|
|
let seats = data.state.common.seats().cloned().collect::<Vec<_>>();
|
|
|
|
|
data.state.common.config.read_outputs(
|
|
|
|
|
&mut data.state.common.output_configuration_state,
|
|
|
|
|
&mut data.state.backend,
|
|
|
|
|
&mut data.state.common.shell,
|
|
|
|
|
seats.into_iter(),
|
2022-11-03 18:51:27 +01:00
|
|
|
&data.state.common.event_loop_handle,
|
2023-01-03 19:17:51 +01:00
|
|
|
);
|
|
|
|
|
for surface in data
|
|
|
|
|
.state
|
|
|
|
|
.backend
|
|
|
|
|
.kms()
|
|
|
|
|
.devices
|
|
|
|
|
.values_mut()
|
|
|
|
|
.flat_map(|d| d.surfaces.values_mut())
|
|
|
|
|
{
|
|
|
|
|
surface.pending = false;
|
2022-05-12 14:04:21 +02:00
|
|
|
}
|
2023-01-03 19:17:51 +01:00
|
|
|
for output in data.state.common.shell.outputs() {
|
|
|
|
|
let sessions = output.pending_buffers().collect::<Vec<_>>();
|
|
|
|
|
if let Err(err) = data.state.backend.kms().schedule_render(
|
|
|
|
|
&data.state.common.event_loop_handle,
|
|
|
|
|
output,
|
|
|
|
|
None,
|
|
|
|
|
if !sessions.is_empty() {
|
|
|
|
|
Some(sessions)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(
|
|
|
|
|
?err,
|
|
|
|
|
"Error scheduling event loop for output {}.",
|
2023-01-03 19:17:51 +01:00
|
|
|
output.name(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
loop_signal.wakeup();
|
|
|
|
|
}
|
|
|
|
|
SessionEvent::PauseSession => {
|
|
|
|
|
libinput_context.suspend();
|
|
|
|
|
for device in data.state.backend.kms().devices.values() {
|
2023-02-27 23:53:27 +01:00
|
|
|
device.drm.pause();
|
2022-04-26 12:28:50 +02:00
|
|
|
}
|
2023-01-03 19:17:51 +01:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.map_err(|err| err.error)
|
|
|
|
|
.context("Failed to initialize session event source")?;
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
state.backend = BackendData::Kms(KmsState {
|
2022-03-16 20:06:31 +01:00
|
|
|
api,
|
2022-05-03 13:37:51 +02:00
|
|
|
_tokens: vec![
|
|
|
|
|
libinput_event_source,
|
|
|
|
|
session_event_source,
|
|
|
|
|
udev_event_source,
|
|
|
|
|
],
|
2022-03-16 20:06:31 +01:00
|
|
|
primary,
|
2022-01-25 15:45:15 +01:00
|
|
|
session,
|
|
|
|
|
devices: HashMap::new(),
|
|
|
|
|
});
|
|
|
|
|
|
2023-02-27 13:54:49 -08:00
|
|
|
// Create relative pointer global
|
|
|
|
|
RelativePointerManagerState::new::<State>(&dh);
|
|
|
|
|
|
2023-01-18 20:23:41 +01:00
|
|
|
// TODO: Do multiple Xwaylands for better multigpu
|
|
|
|
|
state.launch_xwayland(Some(primary));
|
|
|
|
|
|
2022-04-26 12:28:50 +02:00
|
|
|
for (dev, path) in udev_dispatcher.as_source_ref().device_list() {
|
2022-02-04 21:23:27 +01:00
|
|
|
state
|
2023-02-14 23:15:58 +01:00
|
|
|
.device_added(dev, path.into(), dh, false)
|
2022-01-25 15:45:15 +01:00
|
|
|
.with_context(|| format!("Failed to add drm device: {}", path.display()))?;
|
|
|
|
|
}
|
2023-02-10 14:32:56 -08:00
|
|
|
|
2023-02-14 23:15:58 +01:00
|
|
|
// HACK: amdgpu doesn't like us initializing vulkan too early..
|
|
|
|
|
// so lets do that delayed until mesa fixes that.
|
2023-02-10 14:32:56 -08:00
|
|
|
let devices = state
|
|
|
|
|
.backend
|
|
|
|
|
.kms()
|
|
|
|
|
.devices
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|(drm_node, device)| (*drm_node, device.render_node))
|
|
|
|
|
.collect::<Vec<_>>();
|
2023-02-14 23:15:58 +01:00
|
|
|
for (drm_node, render_node) in devices {
|
|
|
|
|
state.init_vulkan(drm_node, render_node);
|
|
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl State {
|
2023-02-10 14:32:56 -08:00
|
|
|
fn device_added(
|
|
|
|
|
&mut self,
|
|
|
|
|
dev: dev_t,
|
|
|
|
|
path: PathBuf,
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
try_vulkan: bool,
|
|
|
|
|
) -> Result<()> {
|
2022-04-26 12:28:50 +02:00
|
|
|
if !self.backend.kms().session.is_active() {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2023-02-24 17:41:52 +01:00
|
|
|
let fd = DrmDeviceFd::new(unsafe {
|
|
|
|
|
DeviceFd::from_raw_fd(
|
|
|
|
|
self.backend
|
|
|
|
|
.kms()
|
|
|
|
|
.session
|
|
|
|
|
.open(
|
|
|
|
|
&path,
|
|
|
|
|
OFlag::O_RDWR | OFlag::O_CLOEXEC | OFlag::O_NOCTTY | OFlag::O_NONBLOCK,
|
|
|
|
|
)
|
|
|
|
|
.with_context(|| {
|
|
|
|
|
format!(
|
|
|
|
|
"Failed to optain file descriptor for drm device: {}",
|
|
|
|
|
path.display()
|
2022-09-28 15:18:04 +02:00
|
|
|
)
|
2023-02-24 17:41:52 +01:00
|
|
|
})?,
|
|
|
|
|
)
|
|
|
|
|
});
|
2023-02-27 23:53:27 +01:00
|
|
|
let (drm, notifier) = DrmDevice::new(fd.clone(), false)
|
2022-01-25 15:45:15 +01:00
|
|
|
.with_context(|| format!("Failed to initialize drm device for: {}", path.display()))?;
|
2022-03-16 20:06:31 +01:00
|
|
|
let drm_node = DrmNode::from_dev_id(dev)?;
|
2022-01-25 15:45:15 +01:00
|
|
|
let supports_atomic = drm.is_atomic();
|
|
|
|
|
|
2022-03-16 20:06:31 +01:00
|
|
|
let gbm = GbmDevice::new(fd)
|
|
|
|
|
.with_context(|| format!("Failed to initialize GBM device for {}", path.display()))?;
|
2023-02-14 23:15:58 +01:00
|
|
|
let (render_node, formats) = {
|
2023-02-24 17:41:52 +01:00
|
|
|
let egl_display = EGLDisplay::new(gbm.clone()).with_context(|| {
|
2023-02-14 23:15:58 +01:00
|
|
|
format!("Failed to create EGLDisplay for device: {}", path.display())
|
|
|
|
|
})?;
|
|
|
|
|
let egl_device = EGLDevice::device_for_display(&egl_display).with_context(|| {
|
|
|
|
|
format!("Unable to find matching egl device for {}", path.display())
|
|
|
|
|
})?;
|
|
|
|
|
let render_node = egl_device
|
|
|
|
|
.try_get_render_node()
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(std::convert::identity)
|
|
|
|
|
.unwrap_or(drm_node);
|
2023-02-24 17:41:52 +01:00
|
|
|
let egl_context = EGLContext::new(&egl_display).with_context(|| {
|
2023-02-14 23:15:58 +01:00
|
|
|
format!(
|
|
|
|
|
"Failed to create EGLContext for device {:?}:{}",
|
|
|
|
|
egl_device,
|
|
|
|
|
path.display()
|
|
|
|
|
)
|
|
|
|
|
})?;
|
|
|
|
|
let formats = egl_context.dmabuf_render_formats().clone();
|
|
|
|
|
(render_node, formats)
|
|
|
|
|
// NOTE: We need the to drop the EGL types here again,
|
|
|
|
|
// otherwise the EGLDisplay created below might share the same GBM context
|
|
|
|
|
};
|
2022-01-25 15:45:15 +01:00
|
|
|
|
2023-02-27 23:53:27 +01:00
|
|
|
let token = self
|
|
|
|
|
.common
|
|
|
|
|
.event_loop_handle
|
|
|
|
|
.insert_source(
|
|
|
|
|
notifier,
|
|
|
|
|
move |event, metadata, data: &mut Data| match event {
|
|
|
|
|
DrmEvent::VBlank(crtc) => {
|
|
|
|
|
let rescheduled = if let Some(device) =
|
|
|
|
|
data.state.backend.kms().devices.get_mut(&drm_node)
|
|
|
|
|
{
|
2022-11-09 12:39:47 +01:00
|
|
|
if let Some(surface) = device.surfaces.get_mut(&crtc) {
|
2022-11-18 17:20:52 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
surface.fps.displayed();
|
|
|
|
|
|
2022-11-09 12:39:47 +01:00
|
|
|
match surface.surface.as_mut().map(|x| x.frame_submitted()) {
|
2022-11-17 20:32:54 +01:00
|
|
|
Some(Ok(feedback)) => {
|
|
|
|
|
if let Some(mut feedback) = feedback.flatten() {
|
|
|
|
|
let submit_time =
|
|
|
|
|
match metadata.take().map(|data| data.time) {
|
|
|
|
|
Some(DrmEventTime::Monotonic(tp)) => Some(tp),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
let seq = metadata
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|metadata| metadata.sequence)
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
|
|
let (clock, flags) = if let Some(tp) = submit_time {
|
|
|
|
|
(
|
|
|
|
|
tp.into(),
|
|
|
|
|
wp_presentation_feedback::Kind::Vsync
|
|
|
|
|
| wp_presentation_feedback::Kind::HwClock
|
|
|
|
|
| wp_presentation_feedback::Kind::HwCompletion,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
(
|
|
|
|
|
data.state.common.clock.now(),
|
|
|
|
|
wp_presentation_feedback::Kind::Vsync,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
feedback.presented(
|
|
|
|
|
clock,
|
|
|
|
|
surface
|
|
|
|
|
.output
|
|
|
|
|
.current_mode()
|
|
|
|
|
.map(|mode| mode.refresh as u32)
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
seq as u64,
|
|
|
|
|
flags,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 12:39:47 +01:00
|
|
|
surface.pending = false;
|
2022-11-22 18:20:20 +01:00
|
|
|
surface.dirty.then(|| {
|
|
|
|
|
(surface.output.clone(), surface.fps.avg_rendertime(5))
|
|
|
|
|
})
|
2022-11-09 12:39:47 +01:00
|
|
|
}
|
|
|
|
|
Some(Err(err)) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
warn!(?err, "Failed to submit frame.");
|
2022-11-09 12:39:47 +01:00
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
_ => None, // got disabled
|
2022-04-13 22:59:14 +02:00
|
|
|
}
|
2022-11-09 12:39:47 +01:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
2023-02-27 23:53:27 +01:00
|
|
|
if let Some((output, avg_rendertime)) = rescheduled {
|
|
|
|
|
let mut scheduled_sessions =
|
|
|
|
|
data.state.workspace_session_for_output(&output);
|
|
|
|
|
let mut output_sessions = output.pending_buffers().peekable();
|
|
|
|
|
if output_sessions.peek().is_some() {
|
|
|
|
|
scheduled_sessions
|
|
|
|
|
.get_or_insert_with(Vec::new)
|
|
|
|
|
.extend(output_sessions);
|
|
|
|
|
}
|
2022-11-09 12:39:47 +01:00
|
|
|
|
2023-02-27 23:53:27 +01:00
|
|
|
let repaint_delay = std::cmp::max(avg_rendertime, MIN_RENDER_TIME);
|
|
|
|
|
if let Err(err) = data.state.backend.kms().schedule_render(
|
|
|
|
|
&data.state.common.event_loop_handle,
|
|
|
|
|
&output,
|
|
|
|
|
Some(repaint_delay),
|
|
|
|
|
scheduled_sessions,
|
|
|
|
|
) {
|
|
|
|
|
warn!(?err, "Failed to schedule render.");
|
|
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-02-27 23:53:27 +01:00
|
|
|
DrmEvent::Error(err) => {
|
|
|
|
|
warn!(?err, "Failed to read events of device {:?}.", dev);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
)
|
2022-01-25 15:45:15 +01:00
|
|
|
.with_context(|| format!("Failed to add drm device to event loop: {}", dev))?;
|
|
|
|
|
|
2022-07-04 15:29:31 +02:00
|
|
|
let socket = match self.create_socket(dh, render_node, formats.clone().into_iter()) {
|
2022-03-22 12:41:54 +01:00
|
|
|
Ok(socket) => Some(socket),
|
|
|
|
|
Err(err) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
warn!(
|
|
|
|
|
?err,
|
|
|
|
|
"Failed to initialize hardware-acceleration for clients on {}.", render_node,
|
2022-03-22 12:41:54 +01:00
|
|
|
);
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-02-13 17:44:24 +01:00
|
|
|
let allocator = Box::new(DmabufAllocator(GbmAllocator::new(
|
|
|
|
|
gbm.clone(),
|
|
|
|
|
GbmBufferFlags::RENDERING,
|
|
|
|
|
)));
|
2022-01-25 15:45:15 +01:00
|
|
|
let mut device = Device {
|
2022-03-16 20:06:31 +01:00
|
|
|
render_node,
|
2022-01-25 15:45:15 +01:00
|
|
|
surfaces: HashMap::new(),
|
2023-02-14 23:15:58 +01:00
|
|
|
gbm: gbm.clone(),
|
2023-02-13 17:44:24 +01:00
|
|
|
allocator,
|
2023-02-27 23:53:27 +01:00
|
|
|
drm,
|
2022-01-25 15:45:15 +01:00
|
|
|
formats,
|
|
|
|
|
supports_atomic,
|
|
|
|
|
event_token: Some(token),
|
2022-03-22 12:41:54 +01:00
|
|
|
socket,
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let outputs = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices
|
2022-04-13 22:59:14 +02:00
|
|
|
let mut wl_outputs = Vec::new();
|
2022-04-14 22:16:37 +02:00
|
|
|
let mut w = self.common.shell.global_space().size.w;
|
2022-11-21 10:10:50 +01:00
|
|
|
{
|
|
|
|
|
let backend = self.backend.kms();
|
2023-02-14 23:15:58 +01:00
|
|
|
backend
|
|
|
|
|
.api
|
|
|
|
|
.as_mut()
|
|
|
|
|
.add_node(render_node, gbm)
|
|
|
|
|
.with_context(|| {
|
|
|
|
|
format!(
|
|
|
|
|
"Failed to initialize renderer for device: {}, skipping",
|
|
|
|
|
render_node
|
|
|
|
|
)
|
|
|
|
|
})?;
|
2023-02-25 00:17:54 +01:00
|
|
|
|
|
|
|
|
let mut renderer = match backend.api.single_renderer(&render_node) {
|
|
|
|
|
Ok(renderer) => renderer,
|
|
|
|
|
Err(err) => {
|
|
|
|
|
warn!(?err, "Failed to initialize output.");
|
|
|
|
|
backend.api.as_mut().remove_node(&render_node);
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
init_shaders(&mut renderer).expect("Failed to initialize renderer");
|
|
|
|
|
|
2022-11-21 10:10:50 +01:00
|
|
|
for (crtc, conn) in outputs {
|
|
|
|
|
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
|
|
|
|
Ok(output) => {
|
|
|
|
|
w += output
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<RefCell<OutputConfig>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow()
|
|
|
|
|
.mode_size()
|
|
|
|
|
.w;
|
|
|
|
|
wl_outputs.push(output);
|
|
|
|
|
}
|
2023-02-24 17:41:52 +01:00
|
|
|
Err(err) => warn!(?err, "Failed to initialize output."),
|
2022-11-21 10:10:50 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
backend.devices.insert(drm_node, device);
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2022-04-13 22:59:14 +02:00
|
|
|
self.common
|
2022-07-04 15:29:31 +02:00
|
|
|
.output_configuration_state
|
2022-07-04 16:00:29 +02:00
|
|
|
.add_heads(wl_outputs.iter());
|
2022-11-22 10:07:17 +01:00
|
|
|
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
2022-05-03 13:37:51 +02:00
|
|
|
self.common.config.read_outputs(
|
2022-11-11 21:36:42 +01:00
|
|
|
&mut self.common.output_configuration_state,
|
2022-05-03 13:37:51 +02:00
|
|
|
&mut self.backend,
|
|
|
|
|
&mut self.common.shell,
|
2022-11-22 10:07:17 +01:00
|
|
|
seats.into_iter(),
|
2022-05-12 14:04:21 +02:00
|
|
|
&self.common.event_loop_handle,
|
2022-05-03 13:37:51 +02:00
|
|
|
);
|
2022-01-25 15:45:15 +01:00
|
|
|
|
2023-02-14 23:15:58 +01:00
|
|
|
if try_vulkan {
|
|
|
|
|
self.init_vulkan(drm_node, render_node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn init_vulkan(&mut self, drm_node: DrmNode, render_node: DrmNode) {
|
2023-02-24 17:41:52 +01:00
|
|
|
if let Ok(instance) = Instance::new(Version::VERSION_1_2, None) {
|
2023-02-13 17:44:24 +01:00
|
|
|
if let Some(physical_device) =
|
|
|
|
|
PhysicalDevice::enumerate(&instance)
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|devices| {
|
|
|
|
|
devices
|
|
|
|
|
.filter(|phd| {
|
|
|
|
|
phd.has_device_extension(unsafe {
|
|
|
|
|
CStr::from_bytes_with_nul_unchecked(
|
|
|
|
|
b"VK_EXT_physical_device_drm\0",
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
.find(|phd| {
|
|
|
|
|
phd.primary_node().unwrap() == Some(render_node)
|
|
|
|
|
|| phd.render_node().unwrap() == Some(render_node)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
match VulkanAllocator::new(
|
|
|
|
|
&physical_device,
|
|
|
|
|
ImageUsageFlags::COLOR_ATTACHMENT | ImageUsageFlags::SAMPLED,
|
|
|
|
|
) {
|
|
|
|
|
Ok(allocator) => {
|
|
|
|
|
self.backend
|
|
|
|
|
.kms()
|
|
|
|
|
.devices
|
|
|
|
|
.get_mut(&drm_node)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.allocator = Box::new(DmabufAllocator(allocator));
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
warn!(?err, "Failed to create vulkan allocator.");
|
2023-02-13 17:44:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn device_changed(&mut self, dev: dev_t) -> Result<()> {
|
2022-04-26 12:28:50 +02:00
|
|
|
if !self.backend.kms().session.is_active() {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2022-03-16 20:06:31 +01:00
|
|
|
let drm_node = DrmNode::from_dev_id(dev)?;
|
2022-04-05 16:35:58 +02:00
|
|
|
let mut outputs_removed = Vec::new();
|
|
|
|
|
let mut outputs_added = Vec::new();
|
2022-11-21 10:10:50 +01:00
|
|
|
{
|
|
|
|
|
let backend = self.backend.kms();
|
|
|
|
|
if let Some(device) = backend.devices.get_mut(&drm_node) {
|
|
|
|
|
let changes = device.enumerate_surfaces()?;
|
|
|
|
|
let mut w = self.common.shell.global_space().size.w;
|
|
|
|
|
for crtc in changes.removed {
|
|
|
|
|
if let Some(surface) = device.surfaces.remove(&crtc) {
|
|
|
|
|
if let Some(token) = surface.render_timer_token {
|
|
|
|
|
self.common.event_loop_handle.remove(token);
|
|
|
|
|
}
|
|
|
|
|
w -= surface.output.current_mode().map(|m| m.size.w).unwrap_or(0);
|
|
|
|
|
outputs_removed.push(surface.output.clone());
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-11-21 10:10:50 +01:00
|
|
|
for (crtc, conn) in changes.added {
|
2023-02-13 17:44:24 +01:00
|
|
|
let mut renderer = match backend.api.single_renderer(&device.render_node) {
|
2022-11-21 10:10:50 +01:00
|
|
|
Ok(renderer) => renderer,
|
|
|
|
|
Err(err) => {
|
2023-02-24 17:41:52 +01:00
|
|
|
warn!(?err, "Failed to initialize output.");
|
2022-11-21 10:10:50 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
|
|
|
|
Ok(output) => {
|
|
|
|
|
w += output
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<RefCell<OutputConfig>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow()
|
|
|
|
|
.mode_size()
|
|
|
|
|
.w;
|
|
|
|
|
outputs_added.push(output);
|
|
|
|
|
}
|
2023-02-24 17:41:52 +01:00
|
|
|
Err(err) => warn!(?err, "Failed to initialize output."),
|
2022-11-21 10:10:50 +01:00
|
|
|
};
|
|
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
self.common
|
|
|
|
|
.output_configuration_state
|
|
|
|
|
.remove_heads(outputs_removed.iter());
|
|
|
|
|
self.common
|
|
|
|
|
.output_configuration_state
|
|
|
|
|
.add_heads(outputs_added.iter());
|
2022-11-22 10:07:17 +01:00
|
|
|
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
2022-05-03 13:37:51 +02:00
|
|
|
self.common.config.read_outputs(
|
2022-11-11 21:36:42 +01:00
|
|
|
&mut self.common.output_configuration_state,
|
2022-05-03 13:37:51 +02:00
|
|
|
&mut self.backend,
|
|
|
|
|
&mut self.common.shell,
|
2023-01-24 21:13:55 +01:00
|
|
|
seats.iter().cloned(),
|
2022-05-12 14:04:21 +02:00
|
|
|
&self.common.event_loop_handle,
|
2022-05-03 13:37:51 +02:00
|
|
|
);
|
2023-01-24 21:13:55 +01:00
|
|
|
// 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.
|
|
|
|
|
// If we have 0 outputs at some point, we won't quit, but shell doesn't know where to move
|
|
|
|
|
// windows and workspaces to.
|
|
|
|
|
for output in outputs_removed {
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.remove_output(&output, seats.iter().cloned());
|
|
|
|
|
}
|
2022-04-14 22:16:37 +02:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 15:29:31 +02:00
|
|
|
fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
|
2022-03-16 20:06:31 +01:00
|
|
|
let drm_node = DrmNode::from_dev_id(dev)?;
|
2022-04-05 16:35:58 +02:00
|
|
|
let mut outputs_removed = Vec::new();
|
2023-02-14 23:15:58 +01:00
|
|
|
let backend = self.backend.kms();
|
|
|
|
|
if let Some(mut device) = backend.devices.remove(&drm_node) {
|
|
|
|
|
backend.api.as_mut().remove_node(&device.render_node);
|
2022-01-25 15:45:15 +01:00
|
|
|
for surface in device.surfaces.values_mut() {
|
|
|
|
|
if let Some(token) = surface.render_timer_token.take() {
|
|
|
|
|
self.common.event_loop_handle.remove(token);
|
|
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
outputs_removed.push(surface.output.clone());
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
if let Some(token) = device.event_token.take() {
|
|
|
|
|
self.common.event_loop_handle.remove(token);
|
|
|
|
|
}
|
2022-03-22 12:41:54 +01:00
|
|
|
if let Some(socket) = device.socket.take() {
|
|
|
|
|
self.common.event_loop_handle.remove(socket.token);
|
2022-07-04 16:00:29 +02:00
|
|
|
self.common
|
|
|
|
|
.dmabuf_state
|
|
|
|
|
.destroy_global::<State>(dh, socket.dmabuf_global);
|
2022-07-18 18:04:02 +02:00
|
|
|
dh.remove_global::<State>(socket.drm_global);
|
2022-03-22 12:41:54 +01:00
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
2022-04-13 22:59:14 +02:00
|
|
|
self.common
|
2022-07-04 15:29:31 +02:00
|
|
|
.output_configuration_state
|
2022-07-04 16:00:29 +02:00
|
|
|
.remove_heads(outputs_removed.iter());
|
2022-04-26 12:28:50 +02:00
|
|
|
|
2022-11-22 10:07:17 +01:00
|
|
|
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
2022-04-26 12:28:50 +02:00
|
|
|
if self.backend.kms().session.is_active() {
|
2022-08-11 17:13:56 +02:00
|
|
|
for output in outputs_removed {
|
2022-11-22 10:07:17 +01:00
|
|
|
self.common
|
|
|
|
|
.shell
|
|
|
|
|
.remove_output(&output, seats.iter().cloned());
|
2022-08-11 17:13:56 +02:00
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
self.common.config.read_outputs(
|
2022-11-11 21:36:42 +01:00
|
|
|
&mut self.common.output_configuration_state,
|
2022-05-03 13:37:51 +02:00
|
|
|
&mut self.backend,
|
|
|
|
|
&mut self.common.shell,
|
2022-11-22 10:07:17 +01:00
|
|
|
seats.into_iter(),
|
2022-05-12 14:04:21 +02:00
|
|
|
&self.common.event_loop_handle,
|
2022-05-03 13:37:51 +02:00
|
|
|
);
|
2022-11-11 21:36:42 +01:00
|
|
|
} else {
|
|
|
|
|
self.common.output_configuration_state.update();
|
2022-04-26 12:28:50 +02:00
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct OutputChanges {
|
|
|
|
|
pub added: Vec<(crtc::Handle, connector::Handle)>,
|
2022-02-04 21:23:27 +01:00
|
|
|
pub removed: Vec<crtc::Handle>,
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Device {
|
|
|
|
|
pub fn enumerate_surfaces(&mut self) -> Result<OutputChanges> {
|
|
|
|
|
// enumerate our outputs
|
2023-02-27 23:53:27 +01:00
|
|
|
let config = drm_helpers::display_configuration(&mut self.drm, self.supports_atomic)?;
|
2022-01-25 15:45:15 +01:00
|
|
|
|
2022-02-04 21:23:27 +01:00
|
|
|
let surfaces = self
|
|
|
|
|
.surfaces
|
|
|
|
|
.iter()
|
2022-04-13 22:59:14 +02:00
|
|
|
.map(|(c, s)| (*c, s.connector))
|
|
|
|
|
.collect::<HashMap<crtc::Handle, connector::Handle>>();
|
2022-02-04 21:23:27 +01:00
|
|
|
|
|
|
|
|
let added = config
|
|
|
|
|
.iter()
|
2022-04-13 22:59:14 +02:00
|
|
|
.filter(|(conn, crtc)| surfaces.get(&crtc).map(|c| c != *conn).unwrap_or(true))
|
2022-01-25 15:45:15 +01:00
|
|
|
.map(|(conn, crtc)| (crtc, conn))
|
|
|
|
|
.map(|(crtc, conn)| (*crtc, *conn))
|
|
|
|
|
.collect::<Vec<_>>();
|
2022-02-04 21:23:27 +01:00
|
|
|
let removed = surfaces
|
|
|
|
|
.iter()
|
2022-04-13 22:59:14 +02:00
|
|
|
.filter(|(crtc, conn)| config.get(conn).map(|c| c != *crtc).unwrap_or(true))
|
2022-02-04 21:23:27 +01:00
|
|
|
.map(|(crtc, _)| *crtc)
|
2022-01-25 15:45:15 +01:00
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
2022-02-04 21:23:27 +01:00
|
|
|
Ok(OutputChanges { added, removed })
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn setup_surface(
|
|
|
|
|
&mut self,
|
|
|
|
|
crtc: crtc::Handle,
|
|
|
|
|
conn: connector::Handle,
|
2022-04-14 22:16:37 +02:00
|
|
|
position: (i32, i32),
|
2023-02-13 17:44:24 +01:00
|
|
|
renderer: &mut GlMultiRenderer<'_, '_>,
|
2022-01-25 15:45:15 +01:00
|
|
|
) -> Result<Output> {
|
2023-02-27 23:53:27 +01:00
|
|
|
let drm = &mut self.drm;
|
2022-01-25 15:45:15 +01:00
|
|
|
let crtc_info = drm.get_crtc(crtc)?;
|
2022-08-11 17:13:56 +02:00
|
|
|
let conn_info = drm.get_connector(conn, false)?;
|
2022-02-04 21:23:27 +01:00
|
|
|
let vrr = drm_helpers::set_vrr(drm, crtc, conn, true).unwrap_or(false);
|
2022-02-01 13:59:39 +01:00
|
|
|
let interface = drm_helpers::interface_name(drm, conn)?;
|
2022-09-22 18:21:03 +02:00
|
|
|
let edid_info = drm_helpers::edid_info(drm, conn);
|
2022-04-13 22:59:14 +02:00
|
|
|
let mode = crtc_info.mode().unwrap_or_else(|| {
|
|
|
|
|
conn_info
|
|
|
|
|
.modes()
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|mode| mode.mode_type().contains(ModeTypeFlags::PREFERRED))
|
|
|
|
|
.copied()
|
|
|
|
|
.unwrap_or(conn_info.modes()[0])
|
|
|
|
|
});
|
2022-04-05 16:35:58 +02:00
|
|
|
let refresh_rate = drm_helpers::calculate_refresh_rate(mode);
|
2022-01-25 15:45:15 +01:00
|
|
|
let output_mode = OutputMode {
|
|
|
|
|
size: (mode.size().0 as i32, mode.size().1 as i32).into(),
|
2022-04-05 16:35:58 +02:00
|
|
|
refresh: refresh_rate as i32,
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
|
|
|
|
let (phys_w, phys_h) = conn_info.size().unwrap_or((0, 0));
|
2022-04-13 22:59:14 +02:00
|
|
|
let output = Output::new(
|
2022-01-25 15:45:15 +01:00
|
|
|
interface,
|
|
|
|
|
PhysicalProperties {
|
|
|
|
|
size: (phys_w as i32, phys_h as i32).into(),
|
|
|
|
|
// TODO: We need to read that from the connector properties
|
2022-09-09 20:00:00 -07:00
|
|
|
subpixel: Subpixel::Unknown,
|
2022-09-22 18:21:03 +02:00
|
|
|
make: edid_info
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|info| info.manufacturer.clone())
|
|
|
|
|
.unwrap_or_else(|_| String::from("Unknown")),
|
|
|
|
|
model: edid_info
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|info| info.model.clone())
|
|
|
|
|
.unwrap_or_else(|_| String::from("Unknown")),
|
2022-01-25 15:45:15 +01:00
|
|
|
},
|
|
|
|
|
);
|
2022-04-13 22:59:14 +02:00
|
|
|
for mode in conn_info.modes() {
|
|
|
|
|
let refresh_rate = drm_helpers::calculate_refresh_rate(*mode);
|
|
|
|
|
let mode = OutputMode {
|
|
|
|
|
size: (mode.size().0 as i32, mode.size().1 as i32).into(),
|
|
|
|
|
refresh: refresh_rate as i32,
|
|
|
|
|
};
|
|
|
|
|
output.add_mode(mode);
|
|
|
|
|
}
|
|
|
|
|
output.set_preferred(output_mode);
|
2022-01-25 15:45:15 +01:00
|
|
|
output.change_current_state(
|
|
|
|
|
Some(output_mode),
|
2022-02-04 21:23:27 +01:00
|
|
|
// TODO: Readout property for monitor rotation
|
2022-09-09 20:00:00 -07:00
|
|
|
Some(Transform::Normal),
|
2022-01-25 15:45:15 +01:00
|
|
|
None,
|
2022-04-14 22:16:37 +02:00
|
|
|
Some(position.into()),
|
2022-01-25 15:45:15 +01:00
|
|
|
);
|
2022-04-05 16:35:58 +02:00
|
|
|
output.user_data().insert_if_missing(|| {
|
|
|
|
|
RefCell::new(OutputConfig {
|
2022-04-13 22:59:14 +02:00
|
|
|
mode: ((output_mode.size.w, output_mode.size.h), Some(refresh_rate)),
|
2022-04-05 16:35:58 +02:00
|
|
|
vrr,
|
2022-04-14 22:16:37 +02:00
|
|
|
position,
|
2022-04-05 16:35:58 +02:00
|
|
|
..Default::default()
|
|
|
|
|
})
|
|
|
|
|
});
|
2022-01-25 15:45:15 +01:00
|
|
|
|
|
|
|
|
let data = Surface {
|
|
|
|
|
output: output.clone(),
|
2022-09-28 12:01:29 +02:00
|
|
|
damage_tracker: DamageTrackedRenderer::from_output(&output),
|
2022-04-14 22:16:37 +02:00
|
|
|
surface: None,
|
2022-04-13 22:59:14 +02:00
|
|
|
connector: conn,
|
2022-01-25 15:45:15 +01:00
|
|
|
vrr,
|
2022-04-05 16:35:58 +02:00
|
|
|
refresh_rate,
|
2022-04-14 22:16:37 +02:00
|
|
|
pending: false,
|
2022-11-09 12:39:47 +01:00
|
|
|
dirty: false,
|
2022-05-12 14:04:21 +02:00
|
|
|
render_timer_token: None,
|
2022-11-21 10:10:50 +01:00
|
|
|
fps: Fps::new(renderer.as_mut()),
|
2022-01-25 15:45:15 +01:00
|
|
|
};
|
|
|
|
|
self.surfaces.insert(crtc, data);
|
|
|
|
|
|
|
|
|
|
Ok(output)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 12:41:54 +01:00
|
|
|
const MAX_CPU_COPIES: usize = 3;
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
fn render_node_for_output(
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
output: &Output,
|
|
|
|
|
target_node: DrmNode,
|
|
|
|
|
shell: &Shell,
|
|
|
|
|
) -> DrmNode {
|
2022-05-16 18:11:24 +02:00
|
|
|
let workspace = shell.active_space(output);
|
2022-07-04 16:00:29 +02:00
|
|
|
let nodes = workspace
|
|
|
|
|
.get_fullscreen(output)
|
2022-09-28 12:01:29 +02:00
|
|
|
.map(|w| vec![w.clone()])
|
|
|
|
|
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
2022-07-04 16:00:29 +02:00
|
|
|
.into_iter()
|
|
|
|
|
.flat_map(|w| {
|
2023-01-24 19:32:57 +01:00
|
|
|
let client = dh.get_client(w.wl_surface()?.id()).ok()?;
|
|
|
|
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
|
|
|
|
return normal_client.drm_node.clone();
|
|
|
|
|
}
|
|
|
|
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
|
|
|
|
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
|
|
|
|
}
|
|
|
|
|
None
|
2022-07-04 16:00:29 +02:00
|
|
|
})
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
if nodes.contains(&target_node) || nodes.len() < MAX_CPU_COPIES {
|
|
|
|
|
target_node
|
|
|
|
|
} else {
|
|
|
|
|
nodes
|
|
|
|
|
.iter()
|
|
|
|
|
.fold(HashMap::new(), |mut count_map, node| {
|
|
|
|
|
let count = count_map.entry(node).or_insert(0);
|
|
|
|
|
*count += 1;
|
|
|
|
|
count_map
|
2022-03-22 12:41:54 +01:00
|
|
|
})
|
2022-07-04 16:00:29 +02:00
|
|
|
.into_iter()
|
|
|
|
|
.reduce(|a, b| if a.1 > b.1 { a } else { b })
|
|
|
|
|
.map(|(node, _)| *node)
|
|
|
|
|
.unwrap_or(target_node)
|
|
|
|
|
}
|
2022-05-16 18:11:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Surface {
|
|
|
|
|
pub fn render_output(
|
|
|
|
|
&mut self,
|
2023-02-13 17:44:24 +01:00
|
|
|
api: &mut GpuManager<GbmGlesBackend<GlowRenderer>>,
|
|
|
|
|
render_node: Option<(
|
|
|
|
|
&DrmNode,
|
|
|
|
|
&mut dyn Allocator<Buffer = Dmabuf, Error = AnyError>,
|
|
|
|
|
)>,
|
2022-05-16 18:11:24 +02:00
|
|
|
target_node: &DrmNode,
|
|
|
|
|
state: &mut Common,
|
2022-11-03 18:51:27 +01:00
|
|
|
screencopy: Option<&[(ScreencopySession, BufferParams)]>,
|
2022-05-16 18:11:24 +02:00
|
|
|
) -> Result<()> {
|
|
|
|
|
if self.surface.is_none() {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
2022-03-22 12:41:54 +01:00
|
|
|
|
2022-04-13 22:59:14 +02:00
|
|
|
let surface = self.surface.as_mut().unwrap();
|
2023-02-13 17:44:24 +01:00
|
|
|
let (render_node, mut renderer) = match render_node {
|
|
|
|
|
Some((render_node, allocator)) => (
|
|
|
|
|
render_node,
|
|
|
|
|
api.renderer(&render_node, &target_node, allocator, surface.format())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
),
|
|
|
|
|
None => (target_node, api.single_renderer(&target_node).unwrap()),
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-13 22:59:14 +02:00
|
|
|
let (buffer, age) = surface
|
2022-01-25 15:45:15 +01:00
|
|
|
.next_buffer()
|
|
|
|
|
.with_context(|| "Failed to allocate buffer")?;
|
2022-02-04 21:04:17 +01:00
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
match render::render_output::<GlMultiRenderer, _, Gles2Renderbuffer, _>(
|
2022-03-22 12:36:03 +01:00
|
|
|
Some(&render_node),
|
|
|
|
|
&mut renderer,
|
2022-11-17 20:32:54 +01:00
|
|
|
buffer.clone(),
|
2022-09-28 12:01:29 +02:00
|
|
|
&mut self.damage_tracker,
|
|
|
|
|
age as usize,
|
2022-02-04 21:04:17 +01:00
|
|
|
state,
|
2022-01-25 15:45:15 +01:00
|
|
|
&self.output,
|
2022-11-03 18:51:27 +01:00
|
|
|
CursorMode::All,
|
|
|
|
|
screencopy.map(|sessions| (buffer, sessions)),
|
2022-08-03 16:34:04 +02:00
|
|
|
Some(&mut self.fps),
|
2022-01-25 15:45:15 +01:00
|
|
|
) {
|
2022-11-17 20:32:54 +01:00
|
|
|
Ok((damage, states)) => {
|
|
|
|
|
let feedback = if damage.is_some() {
|
|
|
|
|
Some(state.take_presentation_feedback(&self.output, &states))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2022-11-06 11:50:09 +01:00
|
|
|
state.send_frames(&self.output, &states);
|
2022-04-13 22:59:14 +02:00
|
|
|
surface
|
2023-02-24 14:07:40 +01:00
|
|
|
.queue_buffer(damage, feedback)
|
2022-01-25 15:45:15 +01:00
|
|
|
.with_context(|| "Failed to submit buffer for display")?;
|
|
|
|
|
}
|
|
|
|
|
Err(err) => {
|
2022-04-13 22:59:14 +02:00
|
|
|
surface.reset_buffers();
|
2022-01-25 15:45:15 +01:00
|
|
|
anyhow::bail!("Rendering failed: {}", err);
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-11-06 11:50:09 +01:00
|
|
|
|
2022-01-25 15:45:15 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2022-01-20 19:51:46 +01:00
|
|
|
}
|
2022-01-28 18:54:25 +01:00
|
|
|
|
|
|
|
|
impl KmsState {
|
2022-05-03 13:37:51 +02:00
|
|
|
pub fn switch_vt(&mut self, num: i32) -> Result<(), anyhow::Error> {
|
2022-04-25 12:35:55 +02:00
|
|
|
self.session.change_vt(num).map_err(Into::into)
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-05 16:35:58 +02:00
|
|
|
pub fn apply_config_for_output(
|
|
|
|
|
&mut self,
|
|
|
|
|
output: &Output,
|
2022-11-22 10:07:17 +01:00
|
|
|
seats: impl Iterator<Item = Seat<State>>,
|
2022-04-13 22:59:14 +02:00
|
|
|
shell: &mut Shell,
|
|
|
|
|
test_only: bool,
|
2022-07-04 15:29:31 +02:00
|
|
|
loop_handle: &LoopHandle<'_, Data>,
|
2022-04-13 22:59:14 +02:00
|
|
|
) -> Result<(), anyhow::Error> {
|
|
|
|
|
let recreated = if let Some(device) = self
|
2022-04-05 16:35:58 +02:00
|
|
|
.devices
|
|
|
|
|
.values_mut()
|
|
|
|
|
.find(|dev| dev.surfaces.values().any(|s| s.output == *output))
|
|
|
|
|
{
|
2022-04-13 22:59:14 +02:00
|
|
|
let (crtc, mut surface) = device
|
2022-04-05 16:35:58 +02:00
|
|
|
.surfaces
|
2022-04-13 22:59:14 +02:00
|
|
|
.iter_mut()
|
|
|
|
|
.find(|(_, s)| s.output == *output)
|
2022-04-05 16:35:58 +02:00
|
|
|
.unwrap();
|
2022-04-13 22:59:14 +02:00
|
|
|
let output_config = output
|
2022-04-05 16:35:58 +02:00
|
|
|
.user_data()
|
|
|
|
|
.get::<RefCell<OutputConfig>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow();
|
|
|
|
|
|
2022-04-13 22:59:14 +02:00
|
|
|
if !output_config.enabled {
|
|
|
|
|
if !test_only {
|
2022-11-22 10:07:17 +01:00
|
|
|
shell.remove_output(output, seats);
|
2022-04-13 22:59:14 +02:00
|
|
|
if surface.surface.take().is_some() {
|
|
|
|
|
// just drop it
|
2022-08-17 17:13:44 +02:00
|
|
|
surface.pending = false;
|
2022-11-11 21:36:42 +01:00
|
|
|
surface.dirty = false;
|
2022-04-13 22:59:14 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
false
|
|
|
|
|
} else {
|
2023-02-27 23:53:27 +01:00
|
|
|
let drm = &mut device.drm;
|
2022-04-13 22:59:14 +02:00
|
|
|
let conn = surface.connector;
|
2022-08-11 17:13:56 +02:00
|
|
|
let conn_info = drm.get_connector(conn, false)?;
|
2022-04-13 22:59:14 +02:00
|
|
|
let mode = conn_info
|
|
|
|
|
.modes()
|
|
|
|
|
.iter()
|
2022-07-19 14:41:04 +02:00
|
|
|
// match the size
|
|
|
|
|
.filter(|mode| {
|
|
|
|
|
let (x, y) = mode.size();
|
|
|
|
|
Size::from((x as i32, y as i32)) == output_config.mode_size()
|
|
|
|
|
})
|
|
|
|
|
// and then select the closest refresh rate (e.g. to match 59.98 as 60)
|
2022-04-13 22:59:14 +02:00
|
|
|
.min_by_key(|mode| {
|
|
|
|
|
let refresh_rate = drm_helpers::calculate_refresh_rate(**mode);
|
|
|
|
|
(output_config.mode.1.unwrap() as i32 - refresh_rate as i32).abs()
|
|
|
|
|
})
|
|
|
|
|
.ok_or(anyhow::anyhow!("Unknown mode"))?;
|
|
|
|
|
|
|
|
|
|
if !test_only {
|
2022-11-11 21:36:42 +01:00
|
|
|
let res = if let Some(gbm_surface) = surface.surface.as_mut() {
|
2022-04-13 22:59:14 +02:00
|
|
|
if output_config.vrr != surface.vrr {
|
|
|
|
|
surface.vrr = drm_helpers::set_vrr(
|
|
|
|
|
drm,
|
|
|
|
|
*crtc,
|
|
|
|
|
conn_info.handle(),
|
|
|
|
|
output_config.vrr,
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
gbm_surface.use_mode(*mode).unwrap();
|
|
|
|
|
false
|
|
|
|
|
} else {
|
|
|
|
|
surface.vrr = drm_helpers::set_vrr(drm, *crtc, conn, output_config.vrr)
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
surface.refresh_rate = drm_helpers::calculate_refresh_rate(*mode);
|
|
|
|
|
|
2023-01-03 19:17:51 +01:00
|
|
|
let drm_surface = drm.create_surface(*crtc, *mode, &[conn])?;
|
2022-04-13 22:59:14 +02:00
|
|
|
let target = GbmBufferedSurface::new(
|
|
|
|
|
drm_surface,
|
2023-02-13 17:44:24 +01:00
|
|
|
GbmAllocator::new(
|
|
|
|
|
device.gbm.clone(),
|
|
|
|
|
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
|
|
|
|
|
),
|
2022-04-13 22:59:14 +02:00
|
|
|
device.formats.clone(),
|
|
|
|
|
)
|
|
|
|
|
.with_context(|| {
|
|
|
|
|
format!(
|
|
|
|
|
"Failed to initialize Gbm surface for {}",
|
|
|
|
|
drm_helpers::interface_name(drm, conn)
|
|
|
|
|
.unwrap_or_else(|_| String::from("Unknown"))
|
|
|
|
|
)
|
|
|
|
|
})?;
|
|
|
|
|
surface.surface = Some(target);
|
|
|
|
|
true
|
2022-11-11 21:36:42 +01:00
|
|
|
};
|
|
|
|
|
shell.add_output(output);
|
|
|
|
|
res
|
2022-04-13 22:59:14 +02:00
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
}
|
2022-04-13 22:59:14 +02:00
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-20 16:06:37 +02:00
|
|
|
shell.refresh_outputs();
|
2022-04-13 22:59:14 +02:00
|
|
|
if recreated {
|
2022-11-03 18:51:27 +01:00
|
|
|
let sessions = output.pending_buffers().collect::<Vec<_>>();
|
|
|
|
|
if let Err(err) = self.schedule_render(
|
|
|
|
|
loop_handle,
|
|
|
|
|
output,
|
2022-11-17 20:32:54 +01:00
|
|
|
None,
|
2022-11-03 18:51:27 +01:00
|
|
|
if !sessions.is_empty() {
|
|
|
|
|
Some(sessions)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
) {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(
|
|
|
|
|
?err,
|
|
|
|
|
"Error scheduling event loop for output {}.",
|
2022-07-04 16:00:29 +02:00
|
|
|
output.name(),
|
|
|
|
|
);
|
2022-05-12 14:04:21 +02:00
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
}
|
|
|
|
|
Ok(())
|
2022-03-30 13:47:06 +02:00
|
|
|
}
|
2022-05-16 18:11:24 +02:00
|
|
|
pub fn target_node_for_output(&self, output: &Output) -> Option<DrmNode> {
|
2022-07-04 16:00:29 +02:00
|
|
|
self.devices
|
2022-08-03 16:41:47 +02:00
|
|
|
.values()
|
|
|
|
|
.find(|dev| dev.surfaces.values().any(|s| s.output == *output))
|
|
|
|
|
.map(|dev| &dev.render_node)
|
2022-07-04 16:00:29 +02:00
|
|
|
.copied()
|
2022-05-16 18:11:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
pub fn try_early_import(
|
|
|
|
|
&mut self,
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
surface: &WlSurface,
|
|
|
|
|
output: &Output,
|
|
|
|
|
target: DrmNode,
|
|
|
|
|
shell: &Shell,
|
|
|
|
|
) {
|
2022-07-04 15:29:31 +02:00
|
|
|
let render = render_node_for_output(dh, &output, target, &shell);
|
2022-05-16 18:11:24 +02:00
|
|
|
if let Err(err) = self.api.early_import(
|
2023-01-24 19:32:57 +01:00
|
|
|
if let Some(client) = dh.get_client(surface.id()).ok() {
|
|
|
|
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
|
|
|
|
normal_client.drm_node.clone()
|
|
|
|
|
} else if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
|
|
|
|
xwayland_client.user_data().get::<DrmNode>().cloned()
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
2022-05-16 18:11:24 +02:00
|
|
|
render,
|
|
|
|
|
surface,
|
|
|
|
|
) {
|
2023-03-03 19:34:41 +01:00
|
|
|
trace!(?err, "Early import failed.");
|
2022-05-16 18:11:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-04-05 16:35:58 +02:00
|
|
|
|
2022-08-31 13:01:23 +02:00
|
|
|
pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
|
2022-07-04 15:29:31 +02:00
|
|
|
use smithay::backend::renderer::ImportDma;
|
|
|
|
|
|
|
|
|
|
for device in self.devices.values() {
|
2022-07-04 16:00:29 +02:00
|
|
|
if device
|
|
|
|
|
.socket
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.dmabuf_global == global)
|
|
|
|
|
.unwrap_or(false)
|
|
|
|
|
{
|
|
|
|
|
return self
|
|
|
|
|
.api
|
2023-02-13 17:44:24 +01:00
|
|
|
.single_renderer(&device.render_node)?
|
2022-07-04 15:29:31 +02:00
|
|
|
.import_dmabuf(&dmabuf, None)
|
|
|
|
|
.map(|_| ())
|
|
|
|
|
.map_err(Into::into);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unreachable!()
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-12 14:04:21 +02:00
|
|
|
pub fn schedule_render(
|
|
|
|
|
&mut self,
|
2022-07-04 15:29:31 +02:00
|
|
|
loop_handle: &LoopHandle<'_, Data>,
|
2022-05-12 14:04:21 +02:00
|
|
|
output: &Output,
|
2022-11-17 20:32:54 +01:00
|
|
|
delay: Option<Duration>,
|
2022-11-03 18:51:27 +01:00
|
|
|
mut screencopy_sessions: Option<Vec<(ScreencopySession, BufferParams)>>,
|
2022-05-12 14:04:21 +02:00
|
|
|
) -> Result<(), InsertError<Timer>> {
|
2022-04-13 22:59:14 +02:00
|
|
|
if let Some((device, crtc, surface)) = self
|
2022-02-04 21:23:27 +01:00
|
|
|
.devices
|
2022-03-16 20:06:31 +01:00
|
|
|
.iter_mut()
|
2022-04-13 22:59:14 +02:00
|
|
|
.flat_map(|(node, d)| d.surfaces.iter_mut().map(move |(c, s)| (node, c, s)))
|
|
|
|
|
.find(|(_, _, s)| s.output == *output)
|
2022-01-25 15:45:15 +01:00
|
|
|
{
|
2022-04-13 22:59:14 +02:00
|
|
|
if surface.surface.is_none() {
|
2022-12-03 00:06:20 +01:00
|
|
|
if let Some(sessions) = screencopy_sessions {
|
|
|
|
|
loop_handle.insert_idle(move |data| {
|
|
|
|
|
for (session, params) in sessions.into_iter() {
|
|
|
|
|
data.state.common.still_pending(session, params);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-05-12 14:04:21 +02:00
|
|
|
return Ok(());
|
2022-04-13 22:59:14 +02:00
|
|
|
}
|
2022-01-25 15:45:15 +01:00
|
|
|
if !surface.pending {
|
2022-05-12 14:04:21 +02:00
|
|
|
let device = *device;
|
|
|
|
|
let crtc = *crtc;
|
2022-08-17 17:14:01 +02:00
|
|
|
if let Some(token) = surface.render_timer_token.take() {
|
|
|
|
|
loop_handle.remove(token);
|
|
|
|
|
}
|
2022-05-12 14:04:21 +02:00
|
|
|
surface.render_timer_token = Some(loop_handle.insert_source(
|
2022-11-17 20:32:54 +01:00
|
|
|
if surface.vrr || delay.is_none() {
|
|
|
|
|
Timer::immediate()
|
|
|
|
|
} else {
|
|
|
|
|
Timer::from_duration(delay.unwrap())
|
|
|
|
|
},
|
2022-07-04 15:29:31 +02:00
|
|
|
move |_time, _, data| {
|
|
|
|
|
let backend = data.state.backend.kms();
|
2023-02-13 17:44:24 +01:00
|
|
|
let (mut device, mut other) = backend
|
|
|
|
|
.devices
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.partition::<Vec<_>, _>(|(key, _val)| *key == &device);
|
|
|
|
|
let target_device = &mut device[0].1;
|
|
|
|
|
|
|
|
|
|
if let Some(surface) = target_device.surfaces.get_mut(&crtc) {
|
|
|
|
|
let target_node = target_device.render_node;
|
|
|
|
|
let render_node = render_node_for_output(
|
|
|
|
|
&data.display.handle(),
|
|
|
|
|
&surface.output,
|
|
|
|
|
target_node,
|
|
|
|
|
&data.state.common.shell,
|
|
|
|
|
);
|
|
|
|
|
let state = &mut data.state.common;
|
|
|
|
|
|
|
|
|
|
let result = if render_node != target_node {
|
|
|
|
|
let render_device = &mut other
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.find(|(_, val)| val.render_node == render_node)
|
|
|
|
|
.unwrap()
|
|
|
|
|
.1;
|
|
|
|
|
surface.render_output(
|
2022-05-12 14:04:21 +02:00
|
|
|
&mut backend.api,
|
2023-02-13 17:44:24 +01:00
|
|
|
Some((
|
|
|
|
|
&render_device.render_node,
|
|
|
|
|
render_device.allocator.as_mut(),
|
|
|
|
|
)),
|
|
|
|
|
&target_node,
|
|
|
|
|
state,
|
2022-11-03 18:51:27 +01:00
|
|
|
screencopy_sessions.as_deref(),
|
2023-02-13 17:44:24 +01:00
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
surface.render_output(
|
|
|
|
|
&mut backend.api,
|
|
|
|
|
None,
|
|
|
|
|
&target_node,
|
|
|
|
|
state,
|
|
|
|
|
screencopy_sessions.as_deref(),
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match result {
|
2023-02-16 16:27:27 +01:00
|
|
|
Ok(_) => {
|
|
|
|
|
surface.dirty = false;
|
|
|
|
|
surface.pending = true;
|
|
|
|
|
return TimeoutAction::Drop;
|
|
|
|
|
}
|
2023-02-13 17:44:24 +01:00
|
|
|
Err(err) => {
|
|
|
|
|
if backend.session.is_active() {
|
2023-02-24 17:41:52 +01:00
|
|
|
error!(?err, "Error rendering.");
|
2023-02-13 17:44:24 +01:00
|
|
|
return TimeoutAction::ToDuration(Duration::from_secs_f64(
|
|
|
|
|
(1000.0 / surface.refresh_rate as f64) - 0.003,
|
|
|
|
|
));
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
2023-02-13 17:44:24 +01:00
|
|
|
}
|
|
|
|
|
};
|
2022-12-03 00:06:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(sessions) = screencopy_sessions.as_mut() {
|
|
|
|
|
for (session, params) in sessions.drain(..) {
|
|
|
|
|
data.state.common.still_pending(session, params);
|
2022-05-12 14:04:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TimeoutAction::Drop
|
|
|
|
|
},
|
|
|
|
|
)?);
|
2022-11-09 12:39:47 +01:00
|
|
|
} else {
|
2022-12-03 00:06:20 +01:00
|
|
|
if let Some(sessions) = screencopy_sessions {
|
|
|
|
|
loop_handle.insert_idle(|data| {
|
|
|
|
|
for (session, params) in sessions.into_iter() {
|
|
|
|
|
data.state.common.still_pending(session, params);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-11-09 12:39:47 +01:00
|
|
|
surface.dirty = true;
|
2022-01-25 15:45:15 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-05-12 14:04:21 +02:00
|
|
|
Ok(())
|
2022-01-28 18:54:25 +01:00
|
|
|
}
|
2022-02-04 21:23:27 +01:00
|
|
|
}
|