Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions winit-wayland/src/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::time::{Duration, Instant};

use calloop::ping::Ping;
use dpi::LogicalSize;
use libc::dev_t;
use rustix::event::{PollFd, PollFlags};
use rustix::pipe::{self, PipeFlags};
use sctk::reexports::calloop_wayland_source::WaylandSource;
Expand Down Expand Up @@ -566,6 +567,10 @@ impl EventLoop {
fn exit_code(&self) -> Option<i32> {
self.active_event_loop.exit_code()
}

pub fn main_drm_device(&self) -> Option<dev_t> {
self.active_event_loop.state.borrow().linux_dmabuf_manager.as_ref()?.device()
}
}

impl AsFd for EventLoop {
Expand Down
7 changes: 7 additions & 0 deletions winit-wayland/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use crate::types::wp_fractional_scaling::FractionalScalingManager;
use crate::types::wp_viewporter::ViewporterState;
use crate::types::xdg_activation::XdgActivationState;
use crate::types::xdg_toplevel_icon_manager::XdgToplevelIconManagerState;
use crate::types::zwp_linux_dmabuf::LinuxDmabufManager;
use crate::window::{WindowRequests, WindowState};
use crate::WindowId;

Expand Down Expand Up @@ -112,6 +113,9 @@ pub struct WinitState {
/// KWin blur manager.
pub kwin_blur_manager: Option<KWinBlurManager>,

/// Dmabuf manager.
pub linux_dmabuf_manager: Option<LinuxDmabufManager>,

/// Loop handle to re-register event sources, such as keyboard repeat.
pub loop_handle: LoopHandle<'static, Self>,

Expand Down Expand Up @@ -161,6 +165,8 @@ impl WinitState {
(None, None)
};

let linux_dmabuf_manager = LinuxDmabufManager::new(globals, queue_handle).ok();

let shm = Shm::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
let image_pool = Arc::new(Mutex::new(SlotPool::new(2, &shm).unwrap()));

Expand All @@ -186,6 +192,7 @@ impl WinitState {
viewporter_state,
fractional_scaling_manager,
kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(),
linux_dmabuf_manager,

seats,
text_input_state: TextInputState::new(globals, queue_handle).ok(),
Expand Down
1 change: 1 addition & 0 deletions winit-wayland/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod wp_fractional_scaling;
pub mod wp_viewporter;
pub mod xdg_activation;
pub mod xdg_toplevel_icon_manager;
pub mod zwp_linux_dmabuf;
83 changes: 83 additions & 0 deletions winit-wayland/src/types/zwp_linux_dmabuf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use libc::dev_t;
use sctk::globals::GlobalData;
use wayland_client::globals::{BindError, GlobalList};
use wayland_client::{delegate_dispatch, Connection, Dispatch, QueueHandle};
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1;
use wayland_protocols::wp::linux_dmabuf::zv1::client::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1;
use wayland_protocols::wp::linux_dmabuf::zv1::client::{
zwp_linux_dmabuf_feedback_v1, zwp_linux_dmabuf_v1,
};

use crate::state::WinitState;

#[derive(Debug)]
pub struct LinuxDmabufManager {
_manager: ZwpLinuxDmabufV1,
feedback: LinuxDmabufFeedback,
}

#[derive(Debug)]
pub struct LinuxDmabufFeedback {
_feedback: ZwpLinuxDmabufFeedbackV1,
device: Option<dev_t>,
pending_device: Option<dev_t>,
}

impl LinuxDmabufManager {
pub fn new(
globals: &GlobalList,
queue_handle: &QueueHandle<WinitState>,
) -> Result<Self, BindError> {
let manager: ZwpLinuxDmabufV1 = globals.bind(queue_handle, 4..=5, GlobalData)?;
let feedback = manager.get_default_feedback(queue_handle, GlobalData);
let feedback =
LinuxDmabufFeedback { _feedback: feedback, device: None, pending_device: None };
Ok(Self { _manager: manager, feedback })
}

pub fn device(&self) -> Option<dev_t> {
self.feedback.device
}
}

impl Dispatch<ZwpLinuxDmabufV1, GlobalData, WinitState> for LinuxDmabufManager {
fn event(
_state: &mut WinitState,
_proxy: &ZwpLinuxDmabufV1,
_event: zwp_linux_dmabuf_v1::Event,
_data: &GlobalData,
_conn: &Connection,
_qhandle: &QueueHandle<WinitState>,
) {
// nothing
}
}

impl Dispatch<ZwpLinuxDmabufFeedbackV1, GlobalData, WinitState> for LinuxDmabufManager {
fn event(
state: &mut WinitState,
_proxy: &ZwpLinuxDmabufFeedbackV1,
event: zwp_linux_dmabuf_feedback_v1::Event,
_data: &GlobalData,
_conn: &Connection,
_qhandle: &QueueHandle<WinitState>,
) {
use zwp_linux_dmabuf_feedback_v1::Event;
match event {
Event::Done => {
let manager = state.linux_dmabuf_manager.as_mut().unwrap();
if let Some(device) = manager.feedback.pending_device.take() {
manager.feedback.device = Some(device);
}
},
Event::MainDevice { device } => {
let dev = dev_t::from_ne_bytes(device.try_into().unwrap());
state.linux_dmabuf_manager.as_mut().unwrap().feedback.pending_device = Some(dev);
},
_ => {},
}
}
}

delegate_dispatch!(WinitState: [ZwpLinuxDmabufV1: GlobalData] => LinuxDmabufManager);
delegate_dispatch!(WinitState: [ZwpLinuxDmabufFeedbackV1: GlobalData] => LinuxDmabufManager);
2 changes: 2 additions & 0 deletions winit/src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ changelog entry.
- Each platform now has corresponding `WindowAttributes` struct instead of trait extension.
- On Wayland, added implementation for `Window::set_window_icon`
- Add `Window::request_ime_update` to atomically apply set of IME changes.
- Add `EventLoopExtDrm` to query the main GPU device on multi-GPU systems on
Linux.

### Changed

Expand Down
21 changes: 21 additions & 0 deletions winit/src/platform/drm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use libc::dev_t;

use crate::event_loop::EventLoop;

/// Additional methods on [`EventLoop`] that are specific to platforms using the Linux
/// Direct Rendering Manager (DRM).
pub trait EventLoopExtDrm {
/// Returns the device that the system prefers to use.
///
/// The EGL EGL_EXT_device_drm and Vulkan VK_EXT_physical_device_drm extensions can be
/// used to select a matching device for accelerated rendering.
///
/// This function returns `None` if the device is unknown.
fn main_drm_device(&self) -> Option<dev_t>;
}

impl EventLoopExtDrm for EventLoop {
fn main_drm_device(&self) -> Option<dev_t> {
self.event_loop.main_drm_device()
}
}
2 changes: 2 additions & 0 deletions winit/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub use winit_web as web;
pub use winit_win32 as windows;
#[cfg(x11_platform)]
pub use winit_x11 as x11;
#[cfg(any(x11_platform, wayland_platform))]
pub mod drm;

#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform, docsrs))]
pub mod scancode;
Expand Down
10 changes: 10 additions & 0 deletions winit/src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::env;
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
use std::time::Duration;

use libc::dev_t;
pub(crate) use winit_common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
use winit_core::application::ApplicationHandler;
use winit_core::error::{EventLoopError, NotSupportedError};
Expand Down Expand Up @@ -169,6 +170,15 @@ impl EventLoop {
pub fn window_target(&self) -> &dyn ActiveEventLoop {
x11_or_wayland!(match self; EventLoop(evlp) => evlp.window_target())
}

pub fn main_drm_device(&self) -> Option<dev_t> {
match self {
#[cfg(wayland_platform)]
EventLoop::Wayland(evlp) => evlp.main_drm_device(),
#[cfg(x11_platform)]
EventLoop::X(_) => None,
Copy link
Contributor Author

@mahkoh mahkoh Jul 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't care enough about X to implement this. But it is possible by using the Dri3Open request to get a DRM fd and then calling stat on it.

}
}
}

impl AsFd for EventLoop {
Expand Down
Loading