metal: request crtc sequence events
This commit is contained in:
parent
a1985b2870
commit
a37ce1acda
3 changed files with 135 additions and 5 deletions
|
|
@ -463,6 +463,7 @@ pub struct MetalConnector {
|
||||||
pub try_switch_format: Cell<bool>,
|
pub try_switch_format: Cell<bool>,
|
||||||
|
|
||||||
pub version: NumCell<u64>,
|
pub version: NumCell<u64>,
|
||||||
|
pub sequence: Cell<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for MetalConnector {
|
impl Debug for MetalConnector {
|
||||||
|
|
@ -712,6 +713,16 @@ impl MetalConnector {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn queue_sequence(&self) {
|
||||||
|
if let Some(crtc) = self.crtc.get() {
|
||||||
|
if let Err(e) = self.master.queue_sequence(crtc.id) {
|
||||||
|
log::error!("Could not queue a CRTC sequence: {}", ErrorFmt(e));
|
||||||
|
} else {
|
||||||
|
crtc.have_queued_sequence.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for MetalConnector {
|
impl Connector for MetalConnector {
|
||||||
|
|
@ -908,6 +919,7 @@ pub struct MetalCrtc {
|
||||||
pub vrr_enabled: MutableProperty<bool>,
|
pub vrr_enabled: MutableProperty<bool>,
|
||||||
|
|
||||||
pub mode_blob: CloneCell<Option<Rc<PropBlob>>>,
|
pub mode_blob: CloneCell<Option<Rc<PropBlob>>>,
|
||||||
|
pub have_queued_sequence: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for MetalCrtc {
|
impl Debug for MetalCrtc {
|
||||||
|
|
@ -1042,6 +1054,7 @@ fn create_connector(
|
||||||
tearing_requested: Cell::new(false),
|
tearing_requested: Cell::new(false),
|
||||||
try_switch_format: Cell::new(false),
|
try_switch_format: Cell::new(false),
|
||||||
version: Default::default(),
|
version: Default::default(),
|
||||||
|
sequence: Default::default(),
|
||||||
});
|
});
|
||||||
let futures = ConnectorFutures {
|
let futures = ConnectorFutures {
|
||||||
_present: backend
|
_present: backend
|
||||||
|
|
@ -1244,6 +1257,7 @@ fn create_crtc(
|
||||||
out_fence_ptr: props.get("OUT_FENCE_PTR")?.id,
|
out_fence_ptr: props.get("OUT_FENCE_PTR")?.id,
|
||||||
vrr_enabled: props.get("VRR_ENABLED")?.map(|v| v == 1),
|
vrr_enabled: props.get("VRR_ENABLED")?.map(|v| v == 1),
|
||||||
mode_blob: Default::default(),
|
mode_blob: Default::default(),
|
||||||
|
have_queued_sequence: Cell::new(false),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1828,9 +1842,64 @@ impl MetalBackend {
|
||||||
sequence,
|
sequence,
|
||||||
crtc_id,
|
crtc_id,
|
||||||
} => self.handle_drm_flip_event(dev, crtc_id, tv_sec, tv_usec, sequence),
|
} => self.handle_drm_flip_event(dev, crtc_id, tv_sec, tv_usec, sequence),
|
||||||
|
DrmEvent::Sequence {
|
||||||
|
time_ns,
|
||||||
|
sequence,
|
||||||
|
crtc_id,
|
||||||
|
} => self.handle_drm_sequence_event(dev, crtc_id, time_ns, sequence),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_sequence(&self, connector: &Rc<MetalConnector>, new: u64) {
|
||||||
|
if connector.sequence.replace(new) == new {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_u32_sequence(&self, connector: &Rc<MetalConnector>, sequence: u32) {
|
||||||
|
let old = connector.sequence.get();
|
||||||
|
let mut new = (old & !(u32::MAX as u64)) | (sequence as u64);
|
||||||
|
if new < old {
|
||||||
|
new += 1 << u32::BITS;
|
||||||
|
if new < old {
|
||||||
|
log::warn!("Ignoring nonsensical sequence {sequence} (old = {old})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if new > old + (1 << (u32::BITS - 1)) {
|
||||||
|
new = new.saturating_sub(1 << u32::BITS);
|
||||||
|
if new < old {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.update_sequence(connector, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_drm_sequence_event(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
dev: &Rc<MetalDrmDeviceData>,
|
||||||
|
crtc_id: DrmCrtc,
|
||||||
|
time_ns: i64,
|
||||||
|
sequence: u64,
|
||||||
|
) {
|
||||||
|
let crtc = match dev.dev.crtcs.get(&crtc_id) {
|
||||||
|
Some(c) => c,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
crtc.have_queued_sequence.set(false);
|
||||||
|
let connector = match crtc.connector.get() {
|
||||||
|
Some(c) => c,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
self.update_sequence(&connector, sequence);
|
||||||
|
connector.queue_sequence();
|
||||||
|
let dd = connector.display.borrow();
|
||||||
|
connector
|
||||||
|
.next_flip_nsec
|
||||||
|
.set(time_ns as u64 + dd.refresh as u64);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_drm_flip_event(
|
fn handle_drm_flip_event(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
dev: &Rc<MetalDrmDeviceData>,
|
dev: &Rc<MetalDrmDeviceData>,
|
||||||
|
|
@ -1847,6 +1916,10 @@ impl MetalBackend {
|
||||||
Some(c) => c,
|
Some(c) => c,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
if !crtc.have_queued_sequence.get() {
|
||||||
|
connector.queue_sequence();
|
||||||
|
}
|
||||||
|
self.update_u32_sequence(&connector, sequence);
|
||||||
connector.can_present.set(true);
|
connector.can_present.set(true);
|
||||||
if let Some(fb) = connector.next_framebuffer.take() {
|
if let Some(fb) = connector.next_framebuffer.take() {
|
||||||
*connector.active_framebuffer.borrow_mut() = Some(fb);
|
*connector.active_framebuffer.borrow_mut() = Some(fb);
|
||||||
|
|
@ -1877,7 +1950,7 @@ impl MetalBackend {
|
||||||
tv_sec as _,
|
tv_sec as _,
|
||||||
tv_usec * 1000,
|
tv_usec * 1000,
|
||||||
refresh,
|
refresh,
|
||||||
sequence as _,
|
connector.sequence.get(),
|
||||||
KIND_VSYNC | KIND_HW_COMPLETION,
|
KIND_VSYNC | KIND_HW_COMPLETION,
|
||||||
);
|
);
|
||||||
let _ = fb.client.remove_obj(&*fb);
|
let _ = fb.client.remove_obj(&*fb);
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ use crate::{
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBuf,
|
dmabuf::DmaBuf,
|
||||||
drm::sys::{
|
drm::sys::{
|
||||||
auth_magic, drm_format_modifier, drm_format_modifier_blob, drop_master, get_version,
|
auth_magic, drm_event_crtc_sequence, drm_format_modifier, drm_format_modifier_blob,
|
||||||
revoke_lease, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP, DRM_CAP_CURSOR_HEIGHT,
|
drop_master, get_version, queue_sequence, revoke_lease, DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP,
|
||||||
DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
|
DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
|
||||||
},
|
},
|
||||||
Modifier, INVALID_MODIFIER,
|
Modifier, INVALID_MODIFIER,
|
||||||
},
|
},
|
||||||
|
|
@ -142,6 +142,8 @@ pub enum DrmError {
|
||||||
CreateLease(#[source] OsError),
|
CreateLease(#[source] OsError),
|
||||||
#[error("Could not drop DRM master")]
|
#[error("Could not drop DRM master")]
|
||||||
DropMaster(#[source] OsError),
|
DropMaster(#[source] OsError),
|
||||||
|
#[error("Could not queue a CRTC sequence")]
|
||||||
|
QueueSequence(#[source] OsError),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
|
||||||
|
|
@ -223,6 +225,10 @@ impl Drm {
|
||||||
pub fn is_master(&self) -> bool {
|
pub fn is_master(&self) -> bool {
|
||||||
auth_magic(self.fd.raw(), 0) != Err(OsError(c::EACCES))
|
auth_magic(self.fd.raw(), 0) != Err(OsError(c::EACCES))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn queue_sequence(&self, crtc: DrmCrtc) -> Result<(), DrmError> {
|
||||||
|
queue_sequence(self.fd.raw(), crtc).map_err(DrmError::QueueSequence)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InFormat {
|
pub struct InFormat {
|
||||||
|
|
@ -554,6 +560,17 @@ impl DrmMaster {
|
||||||
crtc_id: DrmCrtc(event.crtc_id),
|
crtc_id: DrmCrtc(event.crtc_id),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
sys::DRM_EVENT_CRTC_SEQUENCE => {
|
||||||
|
let event: drm_event_crtc_sequence = match uapi::pod_read_init(buf) {
|
||||||
|
Ok(e) => e,
|
||||||
|
_ => return Err(DrmError::InvalidRead),
|
||||||
|
};
|
||||||
|
self.events.push(DrmEvent::Sequence {
|
||||||
|
time_ns: event.time_ns,
|
||||||
|
sequence: event.sequence,
|
||||||
|
crtc_id: DrmCrtc(event.user_data as _),
|
||||||
|
});
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
buf = &buf[len..];
|
buf = &buf[len..];
|
||||||
|
|
@ -582,6 +599,11 @@ pub enum DrmEvent {
|
||||||
sequence: u32,
|
sequence: u32,
|
||||||
crtc_id: DrmCrtc,
|
crtc_id: DrmCrtc,
|
||||||
},
|
},
|
||||||
|
Sequence {
|
||||||
|
time_ns: i64,
|
||||||
|
sequence: u64,
|
||||||
|
crtc_id: DrmCrtc,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrmFramebuffer {
|
pub struct DrmFramebuffer {
|
||||||
|
|
|
||||||
|
|
@ -1048,7 +1048,6 @@ pub fn gem_close(fd: c::c_int, handle: u32) -> Result<(), OsError> {
|
||||||
#[expect(dead_code)]
|
#[expect(dead_code)]
|
||||||
pub const DRM_EVENT_VBLANK: u32 = 0x01;
|
pub const DRM_EVENT_VBLANK: u32 = 0x01;
|
||||||
pub const DRM_EVENT_FLIP_COMPLETE: u32 = 0x02;
|
pub const DRM_EVENT_FLIP_COMPLETE: u32 = 0x02;
|
||||||
#[expect(dead_code)]
|
|
||||||
pub const DRM_EVENT_CRTC_SEQUENCE: u32 = 0x03;
|
pub const DRM_EVENT_CRTC_SEQUENCE: u32 = 0x03;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -1071,6 +1070,16 @@ pub struct drm_event_vblank {
|
||||||
|
|
||||||
unsafe impl Pod for drm_event_vblank {}
|
unsafe impl Pod for drm_event_vblank {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct drm_event_crtc_sequence {
|
||||||
|
pub base: drm_event,
|
||||||
|
pub user_data: u64,
|
||||||
|
pub time_ns: i64,
|
||||||
|
pub sequence: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Pod for drm_event_crtc_sequence {}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct drm_mode_get_blob {
|
struct drm_mode_get_blob {
|
||||||
blob_id: u32,
|
blob_id: u32,
|
||||||
|
|
@ -1399,3 +1408,29 @@ pub fn auth_magic(fd: c::c_int, magic: c::c_uint) -> Result<(), OsError> {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DRM_CRTC_SEQUENCE_RELATIVE: u32 = 0x00000001;
|
||||||
|
// const DRM_CRTC_SEQUENCE_NEXT_ON_MISS: u32 = 0x00000002;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct drm_crtc_queue_sequence {
|
||||||
|
crtc_id: u32,
|
||||||
|
flags: u32,
|
||||||
|
sequence: u64,
|
||||||
|
user_data: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
const DRM_IOCTL_CRTC_QUEUE_SEQUENCE: u64 = drm_iowr::<drm_crtc_queue_sequence>(0x3c);
|
||||||
|
|
||||||
|
pub fn queue_sequence(fd: c::c_int, crtc: DrmCrtc) -> Result<(), OsError> {
|
||||||
|
let mut res = drm_crtc_queue_sequence {
|
||||||
|
crtc_id: crtc.0,
|
||||||
|
flags: DRM_CRTC_SEQUENCE_RELATIVE,
|
||||||
|
sequence: 1,
|
||||||
|
user_data: crtc.0 as _,
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
ioctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &mut res)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue