Skip to content

Commit ca00df0

Browse files
committed
kms: Track active clients instead of active buffers
1 parent a15e378 commit ca00df0

6 files changed

Lines changed: 74 additions & 133 deletions

File tree

src/backend/kms/device.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ use smithay::{
3838
drm::control::{Device as ControlDevice, ModeTypeFlags, connector, crtc},
3939
gbm::BufferObjectFlags as GbmBufferFlags,
4040
rustix::fs::OFlags,
41-
wayland_server::{DisplayHandle, Weak, protocol::wl_buffer::WlBuffer},
41+
wayland_server::DisplayHandle,
4242
},
4343
utils::{Clock, DevPath, DeviceFd, Monotonic, Point, Transform},
4444
wayland::drm_lease::{DrmLease, DrmLeaseState},
4545
};
4646
use tracing::{error, info, warn};
47+
use wayland_backend::server::ClientId;
4748

4849
use std::{
4950
borrow::BorrowMut,
@@ -117,7 +118,7 @@ pub struct InnerDevice {
117118
pub leased_connectors: Vec<(connector::Handle, crtc::Handle)>,
118119
pub leasing_global: Option<DrmLeaseState>,
119120
pub active_leases: Vec<DrmLease>,
120-
pub active_buffers: HashSet<Weak<WlBuffer>>,
121+
pub active_clients: HashSet<ClientId>,
121122
}
122123

123124
impl fmt::Debug for InnerDevice {
@@ -133,7 +134,7 @@ impl fmt::Debug for InnerDevice {
133134
.field("leased_connectors", &self.leased_connectors)
134135
.field("leasing_global", &self.leasing_global)
135136
.field("active_leases", &self.active_leases)
136-
.field("active_buffers", &self.active_buffers.len())
137+
.field("active_clients", &self.active_clients.len())
137138
.finish()
138139
}
139140
}
@@ -338,7 +339,7 @@ impl State {
338339
leased_connectors: Vec::new(),
339340
leasing_global,
340341
active_leases: Vec::new(),
341-
active_buffers: HashSet::new(),
342+
active_clients: HashSet::new(),
342343
},
343344

344345
supports_atomic,
@@ -738,7 +739,7 @@ impl InnerDevice {
738739
pub fn in_use(&self, primary: Option<&DrmNode>) -> bool {
739740
Some(&self.render_node) == primary
740741
|| !self.surfaces.is_empty()
741-
|| !self.active_buffers.is_empty()
742+
|| !self.active_clients.is_empty()
742743
}
743744

744745
pub fn connector_added(

src/backend/kms/mod.rs

Lines changed: 36 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use indexmap::IndexMap;
1414
use render::gles::GbmGlowBackend;
1515
use smithay::{
1616
backend::{
17-
allocator::{Buffer, dmabuf::Dmabuf, format::FormatSet},
17+
allocator::{dmabuf::Dmabuf, format::FormatSet},
1818
drm::{DrmDeviceFd, DrmNode, NodeType, VrrSupport, output::DrmOutputRenderElements},
1919
egl::{EGLContext, EGLDevice, EGLDisplay},
2020
input::InputEvent,
@@ -41,7 +41,7 @@ use smithay::{
4141
},
4242
};
4343
use surface::GbmDrmOutput;
44-
use tracing::{debug, error, info, trace, warn};
44+
use tracing::{debug, error, info, warn};
4545

4646
use std::{
4747
collections::{HashMap, HashSet},
@@ -487,78 +487,55 @@ impl KmsState {
487487

488488
pub fn dmabuf_imported(
489489
&mut self,
490-
_client: Option<Client>,
490+
client: Option<Client>,
491491
global: &DmabufGlobal,
492492
dmabuf: Dmabuf,
493493
) -> Result<DrmNode> {
494-
let (expected_node, mut other_nodes) = self
494+
let device = self
495495
.drm_devices
496496
.values_mut()
497-
.partition::<Vec<_>, _>(|device| {
497+
.find(|device| {
498498
device
499499
.socket
500500
.as_ref()
501501
.map(|s| &s.dmabuf_global == global)
502502
.unwrap_or(false)
503-
});
504-
other_nodes.retain(|device| device.socket.is_some());
505-
506-
let mut last_err = anyhow::anyhow!("Dmabuf cannot be imported on any gpu");
507-
for device in expected_node.into_iter().chain(other_nodes.into_iter()) {
508-
let mut _egl = None;
509-
let egl_display = if let Some(egl_display) = device
510-
.inner
511-
.egl
512-
.as_ref()
513-
.map(|internals| &internals.display)
514-
{
515-
egl_display
516-
} else {
517-
_egl =
518-
Some(init_egl(&device.inner.gbm).context("Failed to initialize egl context")?);
519-
&_egl.as_ref().unwrap().display
520-
};
521-
522-
if !egl_display
523-
.dmabuf_texture_formats()
524-
.contains(&dmabuf.format())
525-
{
526-
trace!(
527-
"Skipping import of dmabuf on {:?}: unsupported format",
528-
device.inner.render_node
503+
})
504+
.context("Couldn't find gpu for dmabuf global")?;
505+
506+
let new_client = if let Some(client) = client {
507+
let new = device.inner.active_clients.insert(client.id());
508+
device.inner.update_egl(
509+
self.primary_node.read().unwrap().as_ref(),
510+
self.api.as_mut(),
511+
)? && new
512+
} else {
513+
false
514+
};
515+
516+
let egl = device
517+
.inner
518+
.egl
519+
.as_ref()
520+
.context("EGL initialization Error")?;
521+
egl.display
522+
.create_image_from_dmabuf(&dmabuf)
523+
.inspect(|image| unsafe {
524+
smithay::backend::egl::ffi::egl::DestroyImageKHR(
525+
**egl.display.get_display_handle(),
526+
*image,
529527
);
530-
continue;
531-
}
528+
})
529+
.context("Failed to create EGLImage from dmabuf")?;
532530

533-
let result = egl_display
534-
.create_image_from_dmabuf(&dmabuf)
535-
.map(|image| {
536-
unsafe {
537-
smithay::backend::egl::ffi::egl::DestroyImageKHR(
538-
**egl_display.get_display_handle(),
539-
image,
540-
);
541-
};
542-
device.inner.render_node
543-
})
544-
.map_err(Into::into);
531+
let node = device.inner.render_node;
532+
dmabuf.set_node(node);
545533

546-
match result {
547-
Ok(node) => {
548-
dmabuf.set_node(node); // so the MultiRenderer knows what node to use
549-
return Ok(node);
550-
}
551-
Err(err) => {
552-
trace!(
553-
?err,
554-
"Failed to import dmabuf on {:?}", device.inner.render_node
555-
);
556-
last_err = err;
557-
}
558-
}
534+
if new_client {
535+
self.refresh_used_devices()?;
559536
}
560537

561-
Err(last_err)
538+
Ok(node)
562539
}
563540

564541
pub fn schedule_render(&mut self, output: &Output) {

src/state.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ use smithay::{
114114
xwayland::XWaylandClientData,
115115
};
116116
use time::UtcOffset;
117+
use tracing::warn;
117118

118119
#[cfg(feature = "systemd")]
119120
use std::os::fd::OwnedFd;
@@ -149,9 +150,12 @@ macro_rules! fl {
149150
pub struct ClientState {
150151
pub compositor_client_state: CompositorClientState,
151152
pub advertised_drm_node: Option<DrmNode>,
153+
pub evlh: LoopHandle<'static, State>,
152154
pub evls: LoopSignal,
153155
pub security_context: Option<SecurityContext>,
154156
}
157+
unsafe impl Send for ClientState {}
158+
unsafe impl Sync for ClientState {}
155159

156160
impl ClientState {
157161
/// We treat a client as "sandboxed" if it has a security context for any sandbox engine
@@ -167,7 +171,23 @@ impl ClientState {
167171

168172
impl ClientData for ClientState {
169173
fn initialized(&self, _client_id: ClientId) {}
170-
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {
174+
fn disconnected(&self, client_id: ClientId, _reason: DisconnectReason) {
175+
self.evlh.insert_idle(move |state| {
176+
if let BackendData::Kms(kms_state) = &mut state.backend {
177+
for device in kms_state.drm_devices.values_mut() {
178+
if device.inner.active_clients.remove(&client_id)
179+
&& !device
180+
.inner
181+
.in_use(kms_state.primary_node.read().unwrap().as_ref())
182+
{
183+
if let Err(err) = kms_state.refresh_used_devices() {
184+
warn!(?err, "Failed to init devices.");
185+
};
186+
break;
187+
}
188+
}
189+
}
190+
});
171191
self.evls.wakeup();
172192
}
173193
}
@@ -783,6 +803,7 @@ impl State {
783803
BackendData::Kms(kms_state) => *kms_state.primary_node.read().unwrap(),
784804
_ => None,
785805
},
806+
evlh: self.common.event_loop_handle.clone(),
786807
evls: self.common.event_loop_signal.clone(),
787808
security_context: None,
788809
}

src/wayland/handlers/buffer.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,10 @@
11
// SPDX-License-Identifier: GPL-3.0-only
22

3-
use crate::state::{BackendData, State};
3+
use crate::state::State;
44
use smithay::{
5-
reexports::wayland_server::{Resource, protocol::wl_buffer::WlBuffer},
6-
wayland::buffer::BufferHandler,
5+
reexports::wayland_server::protocol::wl_buffer::WlBuffer, wayland::buffer::BufferHandler,
76
};
8-
use tracing::warn;
97

108
impl BufferHandler for State {
11-
fn buffer_destroyed(&mut self, buffer: &WlBuffer) {
12-
if let BackendData::Kms(kms_state) = &mut self.backend {
13-
for device in kms_state.drm_devices.values_mut() {
14-
if device.inner.active_buffers.remove(&buffer.downgrade())
15-
&& !device
16-
.inner
17-
.in_use(kms_state.primary_node.read().unwrap().as_ref())
18-
{
19-
if let Err(err) = kms_state.refresh_used_devices() {
20-
warn!(?err, "Failed to init devices.");
21-
};
22-
break;
23-
}
24-
}
25-
}
26-
}
9+
fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {}
2710
}

src/wayland/handlers/dmabuf.rs

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
// SPDX-License-Identifier: GPL-3.0-only
22

3-
use crate::state::{BackendData, State};
3+
use crate::state::State;
44
use smithay::{
55
backend::allocator::dmabuf::Dmabuf,
66
delegate_dmabuf,
7-
reexports::wayland_server::Resource,
87
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
98
};
10-
use tracing::warn;
119

1210
impl DmabufHandler for State {
1311
fn dmabuf_state(&mut self) -> &mut DmabufState {
@@ -20,34 +18,13 @@ impl DmabufHandler for State {
2018
dmabuf: Dmabuf,
2119
import_notifier: ImportNotifier,
2220
) {
23-
match self
24-
.backend
25-
.dmabuf_imported(import_notifier.client(), global, dmabuf)
26-
{
21+
let client = import_notifier.client();
22+
match self.backend.dmabuf_imported(client.clone(), global, dmabuf) {
2723
Err(err) => {
2824
tracing::debug!(?err, "dmabuf import failed");
2925
import_notifier.failed()
3026
}
31-
Ok(Some(node)) => {
32-
// kms backend
33-
let Ok(buffer) = import_notifier.successful::<State>() else {
34-
return;
35-
};
36-
37-
if let BackendData::Kms(kms_state) = &mut self.backend {
38-
if let Some(device) = kms_state
39-
.drm_devices
40-
.values_mut()
41-
.find(|dev| dev.inner.render_node == node)
42-
{
43-
device.inner.active_buffers.insert(buffer.downgrade());
44-
}
45-
if let Err(err) = kms_state.refresh_used_devices() {
46-
warn!(?err, "Failed to init devices.");
47-
};
48-
}
49-
}
50-
Ok(None) => {
27+
Ok(_) => {
5128
let _ = import_notifier.successful::<State>();
5229
}
5330
}

src/wayland/handlers/drm.rs

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
// SPDX-License-Identifier: GPL-3.0-only
22

33
use crate::{
4-
state::{BackendData, State},
4+
state::State,
55
wayland::protocols::drm::{DrmHandler, ImportError, delegate_wl_drm},
66
};
77
use smithay::{
88
backend::{allocator::dmabuf::Dmabuf, drm::DrmNode},
9-
reexports::wayland_server::{Resource, protocol::wl_buffer::WlBuffer},
9+
reexports::wayland_server::protocol::wl_buffer::WlBuffer,
1010
wayland::dmabuf::DmabufGlobal,
1111
};
12-
use tracing::warn;
1312

1413
impl DrmHandler<Option<DrmNode>> for State {
1514
fn dmabuf_imported(
@@ -22,24 +21,7 @@ impl DrmHandler<Option<DrmNode>> for State {
2221
.map_err(|_| ImportError::Failed)
2322
}
2423

25-
fn buffer_created(&mut self, buffer: WlBuffer, result: Option<DrmNode>) {
26-
if let Some(node) = result {
27-
// kms backend
28-
if let BackendData::Kms(kms_state) = &mut self.backend {
29-
if let Some(device) = kms_state
30-
.drm_devices
31-
.values_mut()
32-
.find(|device| device.inner.render_node == node)
33-
{
34-
device.inner.active_buffers.insert(buffer.downgrade());
35-
}
36-
37-
if let Err(err) = kms_state.refresh_used_devices() {
38-
warn!(?err, "Failed to init devices.");
39-
};
40-
}
41-
}
42-
}
24+
fn buffer_created(&mut self, _buffer: WlBuffer, _result: Option<DrmNode>) {}
4325
}
4426

4527
delegate_wl_drm!(State; Option<DrmNode>);

0 commit comments

Comments
 (0)