Merge pull request #484 from Smithay/feature/drm_timings

This commit is contained in:
Victoria Brekenfeld 2022-01-29 15:08:39 +01:00 committed by GitHub
commit 36c79a2735
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 6 deletions

View File

@ -122,7 +122,7 @@ fn main() {
let mut event_loop = EventLoop::<()>::try_new().unwrap(); let mut event_loop = EventLoop::<()>::try_new().unwrap();
event_loop event_loop
.handle() .handle()
.insert_source(device, move |event, _: &mut (), _: &mut ()| match event { .insert_source(device, move |event, _: &mut _, _: &mut ()| match event {
DrmEvent::VBlank(crtc) => vblank_handler.vblank(crtc), DrmEvent::VBlank(crtc) => vblank_handler.vblank(crtc),
DrmEvent::Error(e) => panic!("{}", e), DrmEvent::Error(e) => panic!("{}", e),
}) })

View File

@ -3,10 +3,11 @@ use std::cell::RefCell;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{atomic::AtomicBool, Arc}; use std::sync::{atomic::AtomicBool, Arc};
use std::time::{Instant, SystemTime};
use calloop::{EventSource, Interest, Poll, PostAction, Readiness, Token, TokenFactory}; use calloop::{EventSource, Interest, Poll, PostAction, Readiness, Token, TokenFactory};
use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles}; use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles};
use drm::{ClientCapability, Device as BasicDevice}; use drm::{ClientCapability, Device as BasicDevice, DriverCapability};
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat::fstat; use nix::sys::stat::fstat;
@ -27,6 +28,7 @@ pub struct DrmDevice<A: AsRawFd + 'static> {
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub(super) links: RefCell<Vec<crate::utils::signaling::SignalToken>>, pub(super) links: RefCell<Vec<crate::utils::signaling::SignalToken>>,
has_universal_planes: bool, has_universal_planes: bool,
has_monotonic_timestamps: bool,
resources: ResourceHandles, resources: ResourceHandles,
pub(super) logger: ::slog::Logger, pub(super) logger: ::slog::Logger,
token: Token, token: Token,
@ -136,6 +138,10 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
let has_universal_planes = dev let has_universal_planes = dev
.set_client_capability(ClientCapability::UniversalPlanes, true) .set_client_capability(ClientCapability::UniversalPlanes, true)
.is_ok(); .is_ok();
let has_monotonic_timestamps = dev
.get_driver_capability(DriverCapability::MonotonicTimestamp)
.unwrap_or(0)
== 1;
let resources = dev.resource_handles().map_err(|source| Error::Access { let resources = dev.resource_handles().map_err(|source| Error::Access {
errmsg: "Error loading resource handles", errmsg: "Error loading resource handles",
dev: dev.dev_path(), dev: dev.dev_path(),
@ -154,6 +160,7 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
links: RefCell::new(Vec::new()), links: RefCell::new(Vec::new()),
has_universal_planes, has_universal_planes,
has_monotonic_timestamps,
resources, resources,
logger: log, logger: log,
token: Token::invalid(), token: Token::invalid(),
@ -311,12 +318,30 @@ pub enum DrmEvent {
Error(Error), Error(Error),
} }
/// Timing metadata for page-flip events
#[derive(Debug)]
pub struct EventMetadata {
/// The time the frame flip happend
pub time: Time,
/// The sequence number of the frame
pub sequence: u32,
}
/// Either a realtime or monotonic timestamp
#[derive(Debug)]
pub enum Time {
/// Monotonic time stamp
Monotonic(Instant),
/// Realtime time stamp
Realtime(SystemTime),
}
impl<A> EventSource for DrmDevice<A> impl<A> EventSource for DrmDevice<A>
where where
A: AsRawFd + 'static, A: AsRawFd + 'static,
{ {
type Event = DrmEvent; type Event = DrmEvent;
type Metadata = (); type Metadata = Option<EventMetadata>;
type Ret = (); type Ret = ();
fn process_events<F>( fn process_events<F>(
@ -336,7 +361,22 @@ where
for event in events { for event in events {
if let Event::PageFlip(event) = event { if let Event::PageFlip(event) = event {
trace!(self.logger, "Got a page-flip event for crtc ({:?})", event.crtc); trace!(self.logger, "Got a page-flip event for crtc ({:?})", event.crtc);
callback(DrmEvent::VBlank(event.crtc), &mut ()); let metadata = EventMetadata {
time: if self.has_monotonic_timestamps {
// There is no way to create an Instant, although the underlying type on unix systems
// is just libc::timespec, which is literally what drm-rs is getting from the kernel and just converting
// into a Duration. So we cheat and initialize a Zero-Instant (because although Instant::ZERO
// exists, its private, so you cannot create abitrary Instants). What we really need is a unix-Ext
// trait for both SystemTime and Instant to convert from a libc::timespec.
//
// But this works for now, although it is quite the hack.
Time::Monotonic(unsafe { std::mem::zeroed::<Instant>() } + event.duration)
} else {
Time::Realtime(SystemTime::UNIX_EPOCH + event.duration)
},
sequence: event.frame,
};
callback(DrmEvent::VBlank(event.crtc), &mut Some(metadata));
} else { } else {
trace!( trace!(
self.logger, self.logger,
@ -353,7 +393,7 @@ where
dev: self.dev_path(), dev: self.dev_path(),
source, source,
}), }),
&mut (), &mut None,
); );
} }
} }

View File

@ -76,7 +76,7 @@ pub mod node;
pub(self) mod session; pub(self) mod session;
pub(self) mod surface; pub(self) mod surface;
pub use device::{DevPath, DrmDevice, DrmEvent}; pub use device::{DevPath, DrmDevice, DrmEvent, EventMetadata as DrmEventMetadata, Time as DrmEventTime};
pub use error::Error as DrmError; pub use error::Error as DrmError;
pub use node::{CreateDrmNodeError, DrmNode, NodeType}; pub use node::{CreateDrmNodeError, DrmNode, NodeType};
#[cfg(feature = "backend_gbm")] #[cfg(feature = "backend_gbm")]