kms: Track active clients instead of active buffers
This commit is contained in:
parent
a15e378f1e
commit
ca00df0b37
6 changed files with 72 additions and 131 deletions
|
|
@ -38,12 +38,13 @@ use smithay::{
|
||||||
drm::control::{Device as ControlDevice, ModeTypeFlags, connector, crtc},
|
drm::control::{Device as ControlDevice, ModeTypeFlags, connector, crtc},
|
||||||
gbm::BufferObjectFlags as GbmBufferFlags,
|
gbm::BufferObjectFlags as GbmBufferFlags,
|
||||||
rustix::fs::OFlags,
|
rustix::fs::OFlags,
|
||||||
wayland_server::{DisplayHandle, Weak, protocol::wl_buffer::WlBuffer},
|
wayland_server::DisplayHandle,
|
||||||
},
|
},
|
||||||
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
|
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
|
||||||
wayland::drm_lease::{DrmLease, DrmLeaseState},
|
wayland::drm_lease::{DrmLease, DrmLeaseState},
|
||||||
};
|
};
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
use wayland_backend::server::ClientId;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::BorrowMut,
|
borrow::BorrowMut,
|
||||||
|
|
@ -117,7 +118,7 @@ pub struct InnerDevice {
|
||||||
pub leased_connectors: Vec<(connector::Handle, crtc::Handle)>,
|
pub leased_connectors: Vec<(connector::Handle, crtc::Handle)>,
|
||||||
pub leasing_global: Option<DrmLeaseState>,
|
pub leasing_global: Option<DrmLeaseState>,
|
||||||
pub active_leases: Vec<DrmLease>,
|
pub active_leases: Vec<DrmLease>,
|
||||||
pub active_buffers: HashSet<Weak<WlBuffer>>,
|
pub active_clients: HashSet<ClientId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for InnerDevice {
|
impl fmt::Debug for InnerDevice {
|
||||||
|
|
@ -133,7 +134,7 @@ impl fmt::Debug for InnerDevice {
|
||||||
.field("leased_connectors", &self.leased_connectors)
|
.field("leased_connectors", &self.leased_connectors)
|
||||||
.field("leasing_global", &self.leasing_global)
|
.field("leasing_global", &self.leasing_global)
|
||||||
.field("active_leases", &self.active_leases)
|
.field("active_leases", &self.active_leases)
|
||||||
.field("active_buffers", &self.active_buffers.len())
|
.field("active_clients", &self.active_clients.len())
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -338,7 +339,7 @@ impl State {
|
||||||
leased_connectors: Vec::new(),
|
leased_connectors: Vec::new(),
|
||||||
leasing_global,
|
leasing_global,
|
||||||
active_leases: Vec::new(),
|
active_leases: Vec::new(),
|
||||||
active_buffers: HashSet::new(),
|
active_clients: HashSet::new(),
|
||||||
},
|
},
|
||||||
|
|
||||||
supports_atomic,
|
supports_atomic,
|
||||||
|
|
@ -738,7 +739,7 @@ impl InnerDevice {
|
||||||
pub fn in_use(&self, primary: Option<&DrmNode>) -> bool {
|
pub fn in_use(&self, primary: Option<&DrmNode>) -> bool {
|
||||||
Some(&self.render_node) == primary
|
Some(&self.render_node) == primary
|
||||||
|| !self.surfaces.is_empty()
|
|| !self.surfaces.is_empty()
|
||||||
|| !self.active_buffers.is_empty()
|
|| !self.active_clients.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connector_added(
|
pub fn connector_added(
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use indexmap::IndexMap;
|
||||||
use render::gles::GbmGlowBackend;
|
use render::gles::GbmGlowBackend;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::{Buffer, dmabuf::Dmabuf, format::FormatSet},
|
allocator::{dmabuf::Dmabuf, format::FormatSet},
|
||||||
drm::{DrmDeviceFd, DrmNode, NodeType, VrrSupport, output::DrmOutputRenderElements},
|
drm::{DrmDeviceFd, DrmNode, NodeType, VrrSupport, output::DrmOutputRenderElements},
|
||||||
egl::{EGLContext, EGLDevice, EGLDisplay},
|
egl::{EGLContext, EGLDevice, EGLDisplay},
|
||||||
input::InputEvent,
|
input::InputEvent,
|
||||||
|
|
@ -41,7 +41,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use surface::GbmDrmOutput;
|
use surface::GbmDrmOutput;
|
||||||
use tracing::{debug, error, info, trace, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
|
@ -487,78 +487,55 @@ impl KmsState {
|
||||||
|
|
||||||
pub fn dmabuf_imported(
|
pub fn dmabuf_imported(
|
||||||
&mut self,
|
&mut self,
|
||||||
_client: Option<Client>,
|
client: Option<Client>,
|
||||||
global: &DmabufGlobal,
|
global: &DmabufGlobal,
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
) -> Result<DrmNode> {
|
) -> Result<DrmNode> {
|
||||||
let (expected_node, mut other_nodes) = self
|
let device = self
|
||||||
.drm_devices
|
.drm_devices
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.partition::<Vec<_>, _>(|device| {
|
.find(|device| {
|
||||||
device
|
device
|
||||||
.socket
|
.socket
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| &s.dmabuf_global == global)
|
.map(|s| &s.dmabuf_global == global)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
});
|
})
|
||||||
other_nodes.retain(|device| device.socket.is_some());
|
.context("Couldn't find gpu for dmabuf global")?;
|
||||||
|
|
||||||
let mut last_err = anyhow::anyhow!("Dmabuf cannot be imported on any gpu");
|
let new_client = if let Some(client) = client {
|
||||||
for device in expected_node.into_iter().chain(other_nodes.into_iter()) {
|
let new = device.inner.active_clients.insert(client.id());
|
||||||
let mut _egl = None;
|
device.inner.update_egl(
|
||||||
let egl_display = if let Some(egl_display) = device
|
self.primary_node.read().unwrap().as_ref(),
|
||||||
.inner
|
self.api.as_mut(),
|
||||||
.egl
|
)? && new
|
||||||
.as_ref()
|
} else {
|
||||||
.map(|internals| &internals.display)
|
false
|
||||||
{
|
};
|
||||||
egl_display
|
|
||||||
} else {
|
|
||||||
_egl =
|
|
||||||
Some(init_egl(&device.inner.gbm).context("Failed to initialize egl context")?);
|
|
||||||
&_egl.as_ref().unwrap().display
|
|
||||||
};
|
|
||||||
|
|
||||||
if !egl_display
|
let egl = device
|
||||||
.dmabuf_texture_formats()
|
.inner
|
||||||
.contains(&dmabuf.format())
|
.egl
|
||||||
{
|
.as_ref()
|
||||||
trace!(
|
.context("EGL initialization Error")?;
|
||||||
"Skipping import of dmabuf on {:?}: unsupported format",
|
egl.display
|
||||||
device.inner.render_node
|
.create_image_from_dmabuf(&dmabuf)
|
||||||
|
.inspect(|image| unsafe {
|
||||||
|
smithay::backend::egl::ffi::egl::DestroyImageKHR(
|
||||||
|
**egl.display.get_display_handle(),
|
||||||
|
*image,
|
||||||
);
|
);
|
||||||
continue;
|
})
|
||||||
}
|
.context("Failed to create EGLImage from dmabuf")?;
|
||||||
|
|
||||||
let result = egl_display
|
let node = device.inner.render_node;
|
||||||
.create_image_from_dmabuf(&dmabuf)
|
dmabuf.set_node(node);
|
||||||
.map(|image| {
|
|
||||||
unsafe {
|
|
||||||
smithay::backend::egl::ffi::egl::DestroyImageKHR(
|
|
||||||
**egl_display.get_display_handle(),
|
|
||||||
image,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
device.inner.render_node
|
|
||||||
})
|
|
||||||
.map_err(Into::into);
|
|
||||||
|
|
||||||
match result {
|
if new_client {
|
||||||
Ok(node) => {
|
self.refresh_used_devices()?;
|
||||||
dmabuf.set_node(node); // so the MultiRenderer knows what node to use
|
|
||||||
return Ok(node);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
trace!(
|
|
||||||
?err,
|
|
||||||
"Failed to import dmabuf on {:?}", device.inner.render_node
|
|
||||||
);
|
|
||||||
last_err = err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(last_err)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule_render(&mut self, output: &Output) {
|
pub fn schedule_render(&mut self, output: &Output) {
|
||||||
|
|
|
||||||
23
src/state.rs
23
src/state.rs
|
|
@ -114,6 +114,7 @@ use smithay::{
|
||||||
xwayland::XWaylandClientData,
|
xwayland::XWaylandClientData,
|
||||||
};
|
};
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
#[cfg(feature = "systemd")]
|
#[cfg(feature = "systemd")]
|
||||||
use std::os::fd::OwnedFd;
|
use std::os::fd::OwnedFd;
|
||||||
|
|
@ -149,9 +150,12 @@ macro_rules! fl {
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
pub compositor_client_state: CompositorClientState,
|
pub compositor_client_state: CompositorClientState,
|
||||||
pub advertised_drm_node: Option<DrmNode>,
|
pub advertised_drm_node: Option<DrmNode>,
|
||||||
|
pub evlh: LoopHandle<'static, State>,
|
||||||
pub evls: LoopSignal,
|
pub evls: LoopSignal,
|
||||||
pub security_context: Option<SecurityContext>,
|
pub security_context: Option<SecurityContext>,
|
||||||
}
|
}
|
||||||
|
unsafe impl Send for ClientState {}
|
||||||
|
unsafe impl Sync for ClientState {}
|
||||||
|
|
||||||
impl ClientState {
|
impl ClientState {
|
||||||
/// We treat a client as "sandboxed" if it has a security context for any sandbox engine
|
/// We treat a client as "sandboxed" if it has a security context for any sandbox engine
|
||||||
|
|
@ -167,7 +171,23 @@ impl ClientState {
|
||||||
|
|
||||||
impl ClientData for ClientState {
|
impl ClientData for ClientState {
|
||||||
fn initialized(&self, _client_id: ClientId) {}
|
fn initialized(&self, _client_id: ClientId) {}
|
||||||
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
|
fn disconnected(&self, client_id: ClientId, _reason: DisconnectReason) {
|
||||||
|
self.evlh.insert_idle(move |state| {
|
||||||
|
if let BackendData::Kms(kms_state) = &mut state.backend {
|
||||||
|
for device in kms_state.drm_devices.values_mut() {
|
||||||
|
if device.inner.active_clients.remove(&client_id)
|
||||||
|
&& !device
|
||||||
|
.inner
|
||||||
|
.in_use(kms_state.primary_node.read().unwrap().as_ref())
|
||||||
|
{
|
||||||
|
if let Err(err) = kms_state.refresh_used_devices() {
|
||||||
|
warn!(?err, "Failed to init devices.");
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
self.evls.wakeup();
|
self.evls.wakeup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -783,6 +803,7 @@ impl State {
|
||||||
BackendData::Kms(kms_state) => *kms_state.primary_node.read().unwrap(),
|
BackendData::Kms(kms_state) => *kms_state.primary_node.read().unwrap(),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
evlh: self.common.event_loop_handle.clone(),
|
||||||
evls: self.common.event_loop_signal.clone(),
|
evls: self.common.event_loop_signal.clone(),
|
||||||
security_context: None,
|
security_context: None,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,10 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::state::{BackendData, State};
|
use crate::state::State;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::wayland_server::{Resource, protocol::wl_buffer::WlBuffer},
|
reexports::wayland_server::protocol::wl_buffer::WlBuffer, wayland::buffer::BufferHandler,
|
||||||
wayland::buffer::BufferHandler,
|
|
||||||
};
|
};
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
impl BufferHandler for State {
|
impl BufferHandler for State {
|
||||||
fn buffer_destroyed(&mut self, buffer: &WlBuffer) {
|
fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {}
|
||||||
if let BackendData::Kms(kms_state) = &mut self.backend {
|
|
||||||
for device in kms_state.drm_devices.values_mut() {
|
|
||||||
if device.inner.active_buffers.remove(&buffer.downgrade())
|
|
||||||
&& !device
|
|
||||||
.inner
|
|
||||||
.in_use(kms_state.primary_node.read().unwrap().as_ref())
|
|
||||||
{
|
|
||||||
if let Err(err) = kms_state.refresh_used_devices() {
|
|
||||||
warn!(?err, "Failed to init devices.");
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::state::{BackendData, State};
|
use crate::state::State;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::allocator::dmabuf::Dmabuf,
|
backend::allocator::dmabuf::Dmabuf,
|
||||||
delegate_dmabuf,
|
delegate_dmabuf,
|
||||||
reexports::wayland_server::Resource,
|
|
||||||
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
||||||
};
|
};
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
impl DmabufHandler for State {
|
impl DmabufHandler for State {
|
||||||
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
||||||
|
|
@ -20,34 +18,13 @@ impl DmabufHandler for State {
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
import_notifier: ImportNotifier,
|
import_notifier: ImportNotifier,
|
||||||
) {
|
) {
|
||||||
match self
|
let client = import_notifier.client();
|
||||||
.backend
|
match self.backend.dmabuf_imported(client.clone(), global, dmabuf) {
|
||||||
.dmabuf_imported(import_notifier.client(), global, dmabuf)
|
|
||||||
{
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::debug!(?err, "dmabuf import failed");
|
tracing::debug!(?err, "dmabuf import failed");
|
||||||
import_notifier.failed()
|
import_notifier.failed()
|
||||||
}
|
}
|
||||||
Ok(Some(node)) => {
|
Ok(_) => {
|
||||||
// kms backend
|
|
||||||
let Ok(buffer) = import_notifier.successful::<State>() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let BackendData::Kms(kms_state) = &mut self.backend {
|
|
||||||
if let Some(device) = kms_state
|
|
||||||
.drm_devices
|
|
||||||
.values_mut()
|
|
||||||
.find(|dev| dev.inner.render_node == node)
|
|
||||||
{
|
|
||||||
device.inner.active_buffers.insert(buffer.downgrade());
|
|
||||||
}
|
|
||||||
if let Err(err) = kms_state.refresh_used_devices() {
|
|
||||||
warn!(?err, "Failed to init devices.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
let _ = import_notifier.successful::<State>();
|
let _ = import_notifier.successful::<State>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::{BackendData, State},
|
state::State,
|
||||||
wayland::protocols::drm::{DrmHandler, ImportError, delegate_wl_drm},
|
wayland::protocols::drm::{DrmHandler, ImportError, delegate_wl_drm},
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{allocator::dmabuf::Dmabuf, drm::DrmNode},
|
backend::{allocator::dmabuf::Dmabuf, drm::DrmNode},
|
||||||
reexports::wayland_server::{Resource, protocol::wl_buffer::WlBuffer},
|
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
|
||||||
wayland::dmabuf::DmabufGlobal,
|
wayland::dmabuf::DmabufGlobal,
|
||||||
};
|
};
|
||||||
use tracing::warn;
|
|
||||||
|
|
||||||
impl DrmHandler<Option<DrmNode>> for State {
|
impl DrmHandler<Option<DrmNode>> for State {
|
||||||
fn dmabuf_imported(
|
fn dmabuf_imported(
|
||||||
|
|
@ -22,24 +21,7 @@ impl DrmHandler<Option<DrmNode>> for State {
|
||||||
.map_err(|_| ImportError::Failed)
|
.map_err(|_| ImportError::Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn buffer_created(&mut self, buffer: WlBuffer, result: Option<DrmNode>) {
|
fn buffer_created(&mut self, _buffer: WlBuffer, _result: Option<DrmNode>) {}
|
||||||
if let Some(node) = result {
|
|
||||||
// kms backend
|
|
||||||
if let BackendData::Kms(kms_state) = &mut self.backend {
|
|
||||||
if let Some(device) = kms_state
|
|
||||||
.drm_devices
|
|
||||||
.values_mut()
|
|
||||||
.find(|device| device.inner.render_node == node)
|
|
||||||
{
|
|
||||||
device.inner.active_buffers.insert(buffer.downgrade());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(err) = kms_state.refresh_used_devices() {
|
|
||||||
warn!(?err, "Failed to init devices.");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_wl_drm!(State; Option<DrmNode>);
|
delegate_wl_drm!(State; Option<DrmNode>);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue