Skip to content

Commit

Permalink
metal: emulate vblank events on the nvidia driver
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Oct 4, 2024
1 parent f004afd commit 8e01c37
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 4 deletions.
2 changes: 2 additions & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- Emulate vblank events on the nvidia driver.

# 1.6.0 (2024-09-25)

- Various bugfixes.
Expand Down
23 changes: 19 additions & 4 deletions src/backends/metal/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,19 @@ impl MetalConnector {

fn queue_sequence(&self) {
if let Some(crtc) = self.crtc.get() {
if crtc.needs_vblank_emulation.get() {
return;
}
if let Err(e) = self.master.queue_sequence(crtc.id) {
log::error!("Could not queue a CRTC sequence: {}", ErrorFmt(e));
log::error!("Could not queue a CRTC sequence: {}", ErrorFmt(&e));
if let DrmError::QueueSequence(OsError(c::EOPNOTSUPP)) = e {
if let Some(node) = self.state.root.outputs.get(&self.connector_id) {
log::warn!("{}: Switching to vblank emulation", self.kernel_id());
crtc.needs_vblank_emulation.set(true);
node.global.connector.needs_vblank_emulation.set(true);
node.vblank();
}
}
} else {
crtc.have_queued_sequence.set(true);
}
Expand Down Expand Up @@ -944,6 +955,7 @@ pub struct MetalCrtc {

pub mode_blob: CloneCell<Option<Rc<PropBlob>>>,
pub have_queued_sequence: Cell<bool>,
pub needs_vblank_emulation: Cell<bool>,
}

impl Debug for MetalCrtc {
Expand Down Expand Up @@ -1291,6 +1303,7 @@ fn create_crtc(
vrr_enabled: props.get("VRR_ENABLED")?.map(|v| v == 1),
mode_blob: Default::default(),
have_queued_sequence: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
})
}

Expand Down Expand Up @@ -1955,6 +1968,10 @@ impl MetalBackend {
connector.queue_sequence();
}
self.update_u32_sequence(&connector, sequence);
let time_ns = tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000;
if crtc.needs_vblank_emulation.get() {
self.handle_drm_sequence_event(dev, crtc_id, time_ns as _, connector.sequence.get());
}
connector.can_present.set(true);
if let Some(fb) = connector.next_framebuffer.take() {
*connector.active_framebuffer.borrow_mut() = Some(fb);
Expand All @@ -1976,9 +1993,7 @@ impl MetalBackend {
{
connector.schedule_present();
}
connector
.next_flip_nsec
.set(tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000 + dd.refresh as u64);
connector.next_flip_nsec.set(time_ns + dd.refresh as u64);
{
let mut flags = KIND_HW_COMPLETION;
if connector.presentation_is_sync.get() {
Expand Down
1 change: 1 addition & 0 deletions src/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ fn create_dummy_output(state: &Rc<State>) {
drm_dev: None,
async_event: Default::default(),
damaged: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
});
let schedule = Rc::new(OutputSchedule::new(
&state.ring,
Expand Down
1 change: 1 addition & 0 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ pub struct ConnectorData {
pub drm_dev: Option<Rc<DrmDevData>>,
pub async_event: Rc<AsyncEvent>,
pub damaged: Cell<bool>,
pub needs_vblank_emulation: Cell<bool>,
}

pub struct OutputData {
Expand Down
1 change: 1 addition & 0 deletions src/tasks/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
drm_dev: drm_dev.clone(),
async_event: Rc::new(AsyncEvent::default()),
damaged: Cell::new(false),
needs_vblank_emulation: Cell::new(false),
});
if let Some(dev) = drm_dev {
dev.connectors.set(id, data.clone());
Expand Down
10 changes: 10 additions & 0 deletions src/tree/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ impl OutputNode {
for listener in self.vblank_event.iter() {
listener.after_vblank();
}
if self.global.connector.needs_vblank_emulation.get() {
if self.vblank_event.has_listeners() {
self.global.connector.damage();
} else {
let connector = self.global.connector.clone();
self.vblank_event.on_attach(Box::new(move || {
connector.damage();
}));
}
}
}

pub fn presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/event_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ impl<T: ?Sized> EventSource<T> {
iter: self.listeners.iter(),
}
}

pub fn has_listeners(&self) -> bool {
self.listeners.is_not_empty()
}

pub fn on_attach(&self, f: Box<dyn FnOnce()>) {
self.on_attach.set(Some(f));
}
}

pub struct EventSourceIter<T: ?Sized> {
Expand Down

0 comments on commit 8e01c37

Please sign in to comment.